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>
This commit is contained in:
Zebediah Figura 2021-07-26 11:53:46 -05:00 committed by Alexandre Julliard
parent 9bc5bc7c66
commit 4c639d6926
2 changed files with 17 additions and 8 deletions

View File

@ -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;

View File

@ -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());