server: Always set the async result when the APC object is destroyed.

This can happen if the async is terminated while there is no thread to queue
the APC to (as in the relevant test), or if the client dies before getting the
APC, or before transferring the APC results back to the server.

This also fixes a leak of async objects present since 61abc500f5. If a process
dies while accept asyncs are pending, the asyncs will be terminated but will
not find a valid thread to queue the APC to, and thus async_set_result() and
the completion callback are never called.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-02-24 16:11:35 -06:00 committed by Alexandre Julliard
parent 4eddeff18a
commit 44fc44880f
2 changed files with 12 additions and 9 deletions

View File

@ -4168,9 +4168,9 @@ static void test_exit_process_async(void)
size = 0xdeadbeef;
ret = GetQueuedCompletionStatus(port, &size, &key, &overlapped, 1000);
ok(!ret, "expected failure\n");
todo_wine ok(GetLastError() == ERROR_OPERATION_ABORTED, "got error %u\n", GetLastError());
todo_wine ok(!size, "got size %u\n", size);
todo_wine ok(key == 123, "got key %Iu\n", key);
ok(GetLastError() == ERROR_OPERATION_ABORTED, "got error %u\n", GetLastError());
ok(!size, "got size %u\n", size);
ok(key == 123, "got key %Iu\n", key);
CloseHandle(port);
CloseHandle(server);

View File

@ -490,8 +490,16 @@ static int thread_apc_signaled( struct object *obj, struct wait_queue_entry *ent
static void thread_apc_destroy( struct object *obj )
{
struct thread_apc *apc = (struct thread_apc *)obj;
if (apc->caller) release_object( apc->caller );
if (apc->owner) release_object( apc->owner );
if (apc->owner)
{
if (apc->result.type == APC_ASYNC_IO)
async_set_result( apc->owner, apc->result.async_io.status, apc->result.async_io.total );
else if (apc->call.type == APC_ASYNC_IO)
async_set_result( apc->owner, apc->call.async_io.status, 0 );
release_object( apc->owner );
}
}
/* queue an async procedure call */
@ -1649,11 +1657,6 @@ DECL_HANDLER(select)
apc->result.create_thread.handle = handle;
clear_error(); /* ignore errors from the above calls */
}
else if (apc->result.type == APC_ASYNC_IO)
{
if (apc->owner)
async_set_result( apc->owner, apc->result.async_io.status, apc->result.async_io.total );
}
wake_up( &apc->obj, 0 );
close_handle( current->process, req->prev_apc );
release_object( apc );