Rémi Bernon (@rbernon) commented about server/async.c:
+ cancel->process = (struct process *)grab_object( process ); + cancel->thread = thread ? (struct thread *)grab_object( thread ) : 0; + list_init(&cancel->asyncs); + cancel->wait_handle = 0; + cancel->count = 0; + list_add_tail( &process->async_cancels, &cancel->async_cancels_entry ); + return cancel; +} + +static void cancel_async( struct async_cancel *cancel, struct async *async ) { list_remove( &async->process_entry ); - list_add_tail( &process->cancelled_asyncs, &async->process_entry ); + list_add_tail( &cancel->asyncs, &async->process_entry ); + grab_object( async ); + grab_object( cancel ); I think this makes the cancel / async ownership unclear. I think the cancel group should own its async as they are kept in a list, but not the other way around.
I understand however that the cancel objects also need to be kept alive until they get signaled, but I think this should match their insertion/removal from the `process->async_cancels` list. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7797#note_111820