Почему при вызове WS2_32 shutdown создается новый дескриптор?

#sockets #resource-leak

#сокеты #утечка ресурсов

Вопрос:

Это действительно озадачивает меня, вот трассировка стека, которая показывает, что вызов shutdown в моем сокете фактически привел к созданию другого дескриптора для потока, что вызывает утечку дескриптора.

 0x00007ffe0b560064: ntdll!NtCreateEvent 0x0000000000000014
0x00007ffe06cb5ab6: mswsock!MSAFD_SockThreadInitialize 0x000000000000002e
0x00007ffe06cb5a60: mswsock!SockEnterApiSlow 0x000000000000003c
0x00007ffe06cbc591: mswsock!WSPShutdown 0x0000000000000221
0x00007ffe0a3318f2: WS2_32!shutdown 0x0000000000000072
... some other function calls
0x00007ff7cdf7479c: X!thread_start<unsigned int (__cdecl*)(void * __ptr64)> 0x0000000000000050
0x00007ffe0b017974: KERNEL32!BaseThreadInitThunk 0x0000000000000014
0x00007ffe0b52a271: ntdll!RtlUserThreadStart 0x0000000000000021
 

Вызов — это простое завершение работы (sock, 1); но почему создается новый дескриптор?
Я не вызываю shutdown дважды в сокете, но определенно чего-то не хватает, не так ли?

Комментарии:

1. Вы уверены, что был создан новый поток? В трассировке стека я вижу, что ваш поток вызывает shutdown() , и в конечном итоге это вызывает MSAFD_SockThreadInitialize() , но неясно, что MSAFD_SockThreadInitialize() создает поток (несмотря на его имя)

2. Ах да, это событие для потока, но какого потока? и почему он это делает? Это вывод !htrace, который показывает, что дескриптор на данный момент был создан и оставлен открытым. Я понимаю, что это не фактический исходный код, но чтобы получить приблизительное представление: github.com/pustladi/Windows-2000/blob/master/private/net /…

3. Я предполагаю, что вызывающий поток. Я надеюсь, что вы вызываете closesocket() сокет после shutdown() ? Если нет, то вы пропускаете сокет, и утечка дескриптора может быть частью этого.

4. Спасибо за вашу помощь @JeremyFriesner, это вызов, который я мог подтвердить, что выполняется закрытие сокета: iRC = shutdown(sock, 1) ; iRC = select(1, amp;readFds, 0, 0, amp;timeVal) ; iRC = closesocket(sock) ;

5. @AmirDashti согласно коду в этой ссылке SockEnterApiSlow() возвращает указатель на локальные данные потока, вызывая SockThreadInitialize() только в том случае, если эти данные TLS еще не были инициализированы для вызывающего потока. И эта инициализация включает в себя создание нового объекта события, который используется для сигнализации завершения ввода-вывода сокета, выполняемого вызывающим потоком. Итак, само собой разумеется, что shutdown() он пытается выполнить ввод-вывод, используя эти данные TLS, поэтому он и вызывает SockEnterApiSlow() . Когда вызывающий поток завершает работу и очищает свои данные TLS, этот объект события также должен быть освобожден.