.NET Framework / old .NET Core seems to allocate not more space than necessary for the fd_set inputs, so if the allocation fell on the edge of the end of the heap, Wine tried to read past it.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52259 Signed-off-by: Torge Matthies openglfreak@googlemail.com --- dlls/ws2_32/socket.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 648284c10a3..446cbd0b469 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2395,9 +2395,9 @@ int WINAPI select( int count, fd_set *read_ptr, fd_set *write_ptr, FD_ZERO( &read ); FD_ZERO( &write ); FD_ZERO( &except ); - if (read_ptr) read = *read_ptr; - if (write_ptr) write = *write_ptr; - if (except_ptr) except = *except_ptr; + if (read_ptr) read.fd_count = read_ptr->fd_count; + if (write_ptr) write.fd_count = write_ptr->fd_count; + if (except_ptr) except.fd_count = except_ptr->fd_count;
if (!(sync_event = get_sync_event())) return -1;
@@ -2408,26 +2408,29 @@ int WINAPI select( int count, fd_set *read_ptr, fd_set *write_ptr,
for (i = 0; i < read.fd_count; ++i) { - params->sockets[params->count].socket = read.fd_array[i]; + poll_socket = read_ptr->fd_array[i]; + read.fd_array[i] = poll_socket; + params->sockets[params->count].socket = poll_socket; params->sockets[params->count].flags = AFD_POLL_READ | AFD_POLL_ACCEPT | AFD_POLL_HUP; ++params->count; - poll_socket = read.fd_array[i]; }
for (i = 0; i < write.fd_count; ++i) { - params->sockets[params->count].socket = write.fd_array[i]; + poll_socket = write_ptr->fd_array[i]; + write.fd_array[i] = poll_socket; + params->sockets[params->count].socket = poll_socket; params->sockets[params->count].flags = AFD_POLL_WRITE; ++params->count; - poll_socket = write.fd_array[i]; }
for (i = 0; i < except.fd_count; ++i) { - params->sockets[params->count].socket = except.fd_array[i]; + poll_socket = except_ptr->fd_array[i]; + except.fd_array[i] = poll_socket; + params->sockets[params->count].socket = poll_socket; params->sockets[params->count].flags = AFD_POLL_OOB | AFD_POLL_CONNECT_ERR; ++params->count; - poll_socket = except.fd_array[i]; }
if (!params->count) @@ -2450,9 +2453,9 @@ int WINAPI select( int count, fd_set *read_ptr, fd_set *write_ptr, if (!status) { /* pointers may alias, so clear them all first */ - if (read_ptr) FD_ZERO( read_ptr ); - if (write_ptr) FD_ZERO( write_ptr ); - if (except_ptr) FD_ZERO( except_ptr ); + if (read_ptr) read_ptr->fd_count = 0; + if (write_ptr) write_ptr->fd_count = 0; + if (except_ptr) except_ptr->fd_count = 0;
for (i = 0; i < params->count; ++i) {
Signed-off-by: Torge Matthies openglfreak@googlemail.com --- dlls/ws2_32/tests/sock.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 02713a7c625..cdf5a804952 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -3152,7 +3152,7 @@ static void test_select(void) static char tmp_buf[1024];
SOCKET fdListen, fdRead, fdWrite; - fd_set readfds, writefds, exceptfds; + fd_set readfds, writefds, exceptfds, *alloc_readfds; unsigned int maxfd; int ret, len; char buffer; @@ -3160,7 +3160,8 @@ static void test_select(void) struct sockaddr_in address; select_thread_params thread_params; HANDLE thread_handle; - DWORD ticks, id; + DWORD ticks, id, old_protect; + void *page_pair;
fdRead = socket(AF_INET, SOCK_STREAM, 0); ok( (fdRead != INVALID_SOCKET), "socket failed unexpectedly: %d\n", WSAGetLastError() ); @@ -3326,6 +3327,21 @@ static void test_select(void) ok(FD_ISSET(fdWrite, &readfds), "fdWrite socket is not in the set\n"); ok(FD_ISSET(fdRead, &readfds), "fdRead socket is not in the set\n");
+ page_pair = VirtualAlloc(NULL, 0x1000 * 2, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (!page_pair) + ok(0, "VirtualAlloc error %d\n", GetLastError()); + else + { + BOOL vprot_ret = VirtualProtect((char*)page_pair + 0x1000, 0x1000, PAGE_NOACCESS, &old_protect); + ok(vprot_ret, "VirtualProtect error %d\n", GetLastError()); + alloc_readfds = ((char*)page_pair + 0x1000) - offsetof(fd_set, fd_array[1]); + alloc_readfds->fd_count = 1; + alloc_readfds->fd_array[0] = fdRead; + ret = select(fdRead+1, alloc_readfds, NULL, NULL, &select_timeout); + ok(ret == 1, "select returned %d\n", ret); + VirtualFree(page_pair, 0, MEM_RELEASE); + } + closesocket(fdRead); closesocket(fdWrite);