async_set_result() is the only way the async completion callback can be called. If the async were a request async and the I/O failed even before it was marked as pending, async_handoff() simply discards the async without either calling async_set_result() or directly invoking the completion callback. This leads to memory leak.
Fix this by calling the completion_callback on synchronous failure path if it was not already called, setting it to NULL afterwards.
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com ---
Notes: v6 -> v7: new patch
server/async.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/server/async.c b/server/async.c index d49fb8b7c04..182344923d4 100644 --- a/server/async.c +++ b/server/async.c @@ -322,6 +322,13 @@ void async_wake_obj( struct async *async ) } }
+static void async_call_completion_callback( struct async *async ) +{ + if (async->completion_callback) + async->completion_callback( async->completion_callback_private ); + async->completion_callback = NULL; +} + /* return async object status and wait handle to client */ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_blocking ) { @@ -363,6 +370,8 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_
if (!async->pending && NT_ERROR( get_error() )) { + async_call_completion_callback( async ); + close_handle( async->thread->process, async->wait_handle ); async->wait_handle = 0; return 0; @@ -528,9 +537,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota wake_up( &async->obj, 0 ); }
- if (async->completion_callback) - async->completion_callback( async->completion_callback_private ); - async->completion_callback = NULL; + async_call_completion_callback( async );
if (async->queue) {