Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=18670 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- When patches for this issue were sent back in 2014-15, it was assumed that this approach was insufficient, since it wouldn't close duplicated handles. Whether native ws2_32 closes duplicated handles seems never to have been tested, however, and manual testing shows that it does not.
In greater detail:
* It is known, in the first place, that socket handles are NT kernel handles, since they can be passed to CreateIoCompletionPort().
* When calling WSADuplicateSocketW(), a valid handle is stored in the "dwProviderReserved" member of WSAPROTOCOL_INFO. This same handle is returned in a subsequent call to WSASocket() with the same WSAPROTOCOL_INFO structure. Even before WSASocket is called, the handle can be successfully passed to Nt* functions without returning STATUS_INVALID_HANDLE. [Amusingly, our "hack" actually had the right idea, but used the wrong member.]
* If WSASocket() is called on the handle, it is closed by WSACleanup() [i.e. a subsequent NtClose() returns STATUS_INVALID_HANDLE]. If WSASocket() is not called, NtClose() after WSACleanup() returns STATUS_SUCCESS. The same applies to a socket created with DuplicateHandle() directly.
dlls/ws2_32/socket.c | 14 +++++++++++--- dlls/ws2_32/tests/sock.c | 3 --- 2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 44214630296..246a0e2819b 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1770,9 +1770,17 @@ int WINAPI WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData) */ INT WINAPI WSACleanup(void) { - if (num_startup) { - num_startup--; - TRACE("pending cleanups: %d\n", num_startup); + TRACE("decreasing startup count from %d\n", num_startup); + if (num_startup) + { + if (!--num_startup) + { + unsigned int i; + + for (i = 0; i < socket_list_size; ++i) + CloseHandle(SOCKET2HANDLE(socket_list[i])); + memset(socket_list, 0, socket_list_size * sizeof(*socket_list)); + } return 0; } SetLastError(WSANOTINITIALISED); diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index c7f88d6f3b1..7835246397d 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1221,7 +1221,6 @@ static void test_WithWSAStartup(void) ok(res == 0, "WSAStartup() failed unexpectedly: %d\n", res);
/* show that sockets are destroyed automatically after WSACleanup */ - todo_wine { SetLastError(0xdeadbeef); res = send(pairs[0].src, "TEST", 4, 0); error = WSAGetLastError(); @@ -1258,8 +1257,6 @@ static void test_WithWSAStartup(void) } }
- } - /* While wine is not fixed, close all sockets manually */ for (i = 0; i < socks; i++) {