Signed-off-by: Paul Gofman pgofman@codeweavers.com --- The main goal of these patches is to address use after free which happens with TPIO objects when the completion arrives after TpReleaseIoCompletion() was called. Windows seems to keep the TPIO object alive after TpReleaseIoCompletion() until it receives the number of completions equal to what it expects. The following aspects are currently different in Wine: - TpWaitForIoCompletion with cancel_pending set to TRUE in Wine treats that essentially the same way as TpCancelAsyncIoOperatio(). As far as my testing goes, TpCancelAsyncIoOperatio() tells us that the operation is canceled and the completion is not expected. While with TpWaitForIoCompletion(..., TRUE) Windows still expects completions but doesn't call the callback. - The memory for TPIO object should not freed after TpReleaseIoCompletion() until the expected number of completions is received.
dlls/ntdll/threadpool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c index 9e99398bdee..b82d06e5e42 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -1536,6 +1536,8 @@ static void CALLBACK ioqueue_thread_proc( void *param ) { RtlEnterCriticalSection( &io->pool->cs );
+ --io->u.io.pending_count; + if (!array_reserve((void **)&io->u.io.completions, &io->u.io.completion_max, io->u.io.completion_count + 1, sizeof(*io->u.io.completions))) { @@ -2138,7 +2140,6 @@ static void tp_object_execute( struct threadpool_object *object, BOOL wait_threa { assert( object->u.io.completion_count ); completion = object->u.io.completions[--object->u.io.completion_count]; - object->u.io.pending_count--; }
/* Leave critical section and do the actual callback. */