Module: wine Branch: master Commit: 4c639d6926c9103b42caca8d91cd868e64635910 URL: https://source.winehq.org/git/wine.git/?a=commit;h=4c639d6926c9103b42caca8d9...
Author: Zebediah Figura zfigura@codeweavers.com Date: Mon Jul 26 11:53:46 2021 -0500
ntdll: Fill the I/O status block with the results of the send_socket call in sock_send().
The server might change the status. In particular, if we got a short but nonzero write on a nonblocking socket, try_send() would return STATUS_DEVICE_NOT_READY and hence leave the I/O status block unfilled. The server subsequently massages this into STATUS_SUCECSS, causing a garbage size to be eventually returned from ws2_32 send().
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51439 Signed-off-by: Zebediah Figura zfigura@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntdll/unix/socket.c | 15 +++++++++------ dlls/ws2_32/tests/sock.c | 10 ++++++++-- 2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 6b863fd61f0..e29dc7f66d1 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -922,12 +922,6 @@ static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi if (status == STATUS_DEVICE_NOT_READY && force_async) status = STATUS_PENDING;
- if (!NT_ERROR(status)) - { - io->Status = status; - io->Information = async->sent_len; - } - SERVER_START_REQ( send_socket ) { req->status = status; @@ -936,6 +930,11 @@ static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi status = wine_server_call( req ); wait_handle = wine_server_ptr_handle( reply->wait ); options = reply->options; + if ((!NT_ERROR(status) || wait_handle) && status != STATUS_PENDING) + { + io->Status = status; + io->Information = async->sent_len; + } } SERVER_END_REQ;
@@ -1111,6 +1110,10 @@ static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, status = wine_server_call( req ); wait_handle = wine_server_ptr_handle( reply->wait ); options = reply->options; + /* In theory we'd fill the iosb here, as above in sock_send(), but it's + * actually currently impossible to get STATUS_SUCCESS. The server will + * either return STATUS_PENDING or an error code, and in neither case + * should the iosb be filled. */ } SERVER_END_REQ;
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 5f2a68e5073..ca0a3d86174 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -5080,8 +5080,14 @@ static void test_write_events(struct event_test_ctx *ctx)
if (!broken(1)) { - while (send(server, buffer, buffer_size, 0) == buffer_size); - ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); + while ((ret = send(server, buffer, buffer_size, 0)) == buffer_size); + /* Windows will never send less than buffer_size bytes here, but Linux + * may do a short write. */ + todo_wine_if (ret > 0) + { + ok(ret == -1, "got %d\n", ret); + ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); + }
while (recv(client, buffer, buffer_size, 0) > 0); ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError());