[PATCH v3 1/8] server: Actually set initial status in set_async_direct_result handler.

Jinoh Kang jinoh.kang.kr at gmail.com
Tue Mar 1 07:23:25 CST 2022


On 2/26/22 03:57, Zebediah Figura (she/her) wrote:
> On 2/21/22 11:23, Jinoh Kang wrote:
>> Commit 15483b1a126 (server: Allow calling async_handoff() with status
>> code STATUS_ALERTED., 2022-02-10) introduced the set_async_direct_result
>> handler which calls async_set_initial_status().
>>
>> However, the async_set_initial_status() call does nothing since
>> async->terminated is set, leaving the async in a confusing state
>> (unknown_status = 1 but pending/completed).
>>
>> So far, this issue is unlikely to have been a problem in practice for
>> the following reasons:
>>
>> 1. async_set_initial_status() would have unset unknown_status, but it
>>    remains set instead.  This is usually not a problem, since
>>    unknown_status is usually ever read by code paths effectively
>>    unreachable for non-device (e.g. socket) asyncs.
>>
>>    It would still potentially allow set_async_direct_result to be called
>>    multiple times, but it wouldn't actually happen in practice unless
>>    something goes wrong.
>>
>> 2. async_set_initial_status() would have set initial_status; however,
>>    it is left with the default value STATUS_PENDING.  If the actual
>>    status is something other than that, the handler closes the wait
>>    handle and async_satisfied (the only realconsumer of initial_status)
>>    would never be called anyway.
>>
>> For reasons above, this issue is not effectively observable or testable.
>> Nonetheless, the current code does leave the async object in an
>> inconsistent state.
>>
>> Fix this by setting the initial_status directly (and unsetting
>> unknown_status as well).
>>
>> Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
>> ---
>>
>> Notes:
>>     v1 -> v2: no changes
>>     v2 -> v3: no changes
>>
>>  server/async.c | 3 ++-
>>  1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/server/async.c b/server/async.c
>> index 7d0ff10f7a4..f078f42f34c 100644
>> --- a/server/async.c
>> +++ b/server/async.c
>> @@ -769,7 +769,8 @@ DECL_HANDLER(set_async_direct_result)
>>          return;
>>      }
>>  
>> -    async_set_initial_status( async, status );
>> +    async->initial_status = status;
>> +    async->unknown_status = 0;
>>  
>>      if (status == STATUS_PENDING)
>>      {
> 
> I feel like this raises further questions, like "why does
> async_set_initial_status() assert async->unknown_status

To prevent overwriting initial status that was already set, I guess?

> but then return if async->terminated?"

This function was introduced in commit 484b78bda01 (ntoskrnl: Report the initial status of an IRP separately from the IOSB status., 2021-09-12), but it provides no explanation.

I guess it was to keep it in sync with set_async_pending()?

That said, I suppose nothing will go wrong even if we pull out the !async->terminated check.
Nobody really cares about the initial status after termination, except async_satisfied().

> 
> For IRPs I think the async can be terminated with unknown_status if the
> process dies. I'm not sure if we have an actual bug here,

This is not a bug (yet), but subsequent patches in this series require that the initial status is eventually set.

> but conceptually we should probably be resetting unknown_status and setting
> initial_status in async_set_result() if necessary.

Great.

> 
> Of course, if we do that, I think it becomes possible to call
> async_set_initial_status() on an async which already has
> !async->unknown_status, so that assert() would have to go away.

Yeah, and also the !async->terminated check.


-- 
Sincerely,
Jinoh Kang



More information about the wine-devel mailing list