Commit 97afac46 authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

ntdll: Avoid accessing the I/O status block in wait_async().

Steam uses WSASend() with completion ports, reusing OVERLAPPED structures as soon as they are returned from GetQueuedCompletionStatus(). Since completion is queued during the select request in wait_async(), the I/O status block can be reused even before the call to NtDeviceIoControl exits. This works fine with current Wine, because WSASend() doesn't access the I/O status block after queuing completion. However, a patch that changes it to use wait_async() like other async requests causes NtDeviceIoControlFile to consistently return garbage status codes. Signed-off-by: 's avatarZebediah Figura <z.figura12@gmail.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent a5b6e90d
...@@ -4697,10 +4697,9 @@ static async_data_t server_async( HANDLE handle, struct async_fileio *user, HAND ...@@ -4697,10 +4697,9 @@ static async_data_t server_async( HANDLE handle, struct async_fileio *user, HAND
return async; return async;
} }
static NTSTATUS wait_async( HANDLE handle, BOOL alertable, IO_STATUS_BLOCK *io ) static NTSTATUS wait_async( HANDLE handle, BOOL alertable )
{ {
if (NtWaitForSingleObject( handle, alertable, NULL )) return STATUS_PENDING; return NtWaitForSingleObject( handle, alertable, NULL );
return io->u.Status;
} }
/* callback for irp async I/O completion */ /* callback for irp async I/O completion */
...@@ -4861,7 +4860,7 @@ static NTSTATUS server_read_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE a ...@@ -4861,7 +4860,7 @@ static NTSTATUS server_read_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE a
if (status != STATUS_PENDING) free( async ); if (status != STATUS_PENDING) free( async );
if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), io ); if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT) );
return status; return status;
} }
...@@ -4899,7 +4898,7 @@ static NTSTATUS server_write_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ...@@ -4899,7 +4898,7 @@ static NTSTATUS server_write_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE
if (status != STATUS_PENDING) free( async ); if (status != STATUS_PENDING) free( async );
if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), io ); if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT) );
return status; return status;
} }
...@@ -4944,7 +4943,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, ...@@ -4944,7 +4943,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
if (status != STATUS_PENDING) free( async ); if (status != STATUS_PENDING) free( async );
if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), io ); if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT) );
return status; return status;
} }
...@@ -5937,7 +5936,7 @@ NTSTATUS WINAPI NtFlushBuffersFile( HANDLE handle, IO_STATUS_BLOCK *io ) ...@@ -5937,7 +5936,7 @@ NTSTATUS WINAPI NtFlushBuffersFile( HANDLE handle, IO_STATUS_BLOCK *io )
if (ret != STATUS_PENDING) free( async ); if (ret != STATUS_PENDING) free( async );
if (wait_handle) ret = wait_async( wait_handle, FALSE, io ); if (wait_handle) ret = wait_async( wait_handle, FALSE );
} }
if (needs_close) close( fd ); if (needs_close) close( fd );
...@@ -6436,7 +6435,7 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io ...@@ -6436,7 +6435,7 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io
} }
SERVER_END_REQ; SERVER_END_REQ;
if (status != STATUS_PENDING) free( async ); if (status != STATUS_PENDING) free( async );
if (wait_handle) status = wait_async( wait_handle, FALSE, io ); if (wait_handle) status = wait_async( wait_handle, FALSE );
return status; return status;
} }
else if (io->u.Status) return io->u.Status; else if (io->u.Status) return io->u.Status;
......
...@@ -118,14 +118,14 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry ...@@ -118,14 +118,14 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry
async->direct_result = 0; async->direct_result = 0;
} }
set_wait_status( entry, async->status );
/* close wait handle here to avoid extra server round trip */ /* close wait handle here to avoid extra server round trip */
if (async->wait_handle) if (async->wait_handle)
{ {
close_handle( async->thread->process, async->wait_handle ); close_handle( async->thread->process, async->wait_handle );
async->wait_handle = 0; async->wait_handle = 0;
} }
if (async->status == STATUS_PENDING) make_wait_abandoned( entry );
} }
static void async_destroy( struct object *obj ) static void async_destroy( struct object *obj )
......
...@@ -67,6 +67,7 @@ struct thread_wait ...@@ -67,6 +67,7 @@ struct thread_wait
client_ptr_t cookie; /* magic cookie to return to client */ client_ptr_t cookie; /* magic cookie to return to client */
abstime_t when; abstime_t when;
struct timeout_user *user; struct timeout_user *user;
int status; /* status to return (unless STATUS_PENDING) */
struct wait_queue_entry queues[1]; struct wait_queue_entry queues[1];
}; };
...@@ -727,6 +728,11 @@ void make_wait_abandoned( struct wait_queue_entry *entry ) ...@@ -727,6 +728,11 @@ void make_wait_abandoned( struct wait_queue_entry *entry )
entry->wait->abandoned = 1; entry->wait->abandoned = 1;
} }
void set_wait_status( struct wait_queue_entry *entry, int status )
{
entry->wait->status = status;
}
/* finish waiting */ /* finish waiting */
static unsigned int end_wait( struct thread *thread, unsigned int status ) static unsigned int end_wait( struct thread *thread, unsigned int status )
{ {
...@@ -739,6 +745,7 @@ static unsigned int end_wait( struct thread *thread, unsigned int status ) ...@@ -739,6 +745,7 @@ static unsigned int end_wait( struct thread *thread, unsigned int status )
if (status < wait->count) /* wait satisfied, tell it to the objects */ if (status < wait->count) /* wait satisfied, tell it to the objects */
{ {
wait->status = status;
if (wait->select == SELECT_WAIT_ALL) if (wait->select == SELECT_WAIT_ALL)
{ {
for (i = 0, entry = wait->queues; i < wait->count; i++, entry++) for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
...@@ -749,6 +756,7 @@ static unsigned int end_wait( struct thread *thread, unsigned int status ) ...@@ -749,6 +756,7 @@ static unsigned int end_wait( struct thread *thread, unsigned int status )
entry = wait->queues + status; entry = wait->queues + status;
entry->obj->ops->satisfied( entry->obj, entry ); entry->obj->ops->satisfied( entry->obj, entry );
} }
status = wait->status;
if (wait->abandoned) status += STATUS_ABANDONED_WAIT_0; if (wait->abandoned) status += STATUS_ABANDONED_WAIT_0;
} }
for (i = 0, entry = wait->queues; i < wait->count; i++, entry++) for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
......
...@@ -106,6 +106,7 @@ extern struct thread *get_wait_queue_thread( struct wait_queue_entry *entry ); ...@@ -106,6 +106,7 @@ extern struct thread *get_wait_queue_thread( struct wait_queue_entry *entry );
extern enum select_op get_wait_queue_select_op( struct wait_queue_entry *entry ); extern enum select_op get_wait_queue_select_op( struct wait_queue_entry *entry );
extern client_ptr_t get_wait_queue_key( struct wait_queue_entry *entry ); extern client_ptr_t get_wait_queue_key( struct wait_queue_entry *entry );
extern void make_wait_abandoned( struct wait_queue_entry *entry ); extern void make_wait_abandoned( struct wait_queue_entry *entry );
extern void set_wait_status( struct wait_queue_entry *entry, int status );
extern void stop_thread( struct thread *thread ); extern void stop_thread( struct thread *thread );
extern int wake_thread( struct thread *thread ); extern int wake_thread( struct thread *thread );
extern int wake_thread_queue_entry( struct wait_queue_entry *entry ); extern int wake_thread_queue_entry( struct wait_queue_entry *entry );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment