Complete the OVERLAPPED when an async request fails validation
pawnio_execute_async and pawnio_execute_async_win32 set
overlapped->Internal to STATUS_PENDING before calling
pawnio_execute_async_nt, but that function validates the name and the
input and output sizes and can return before it ever reaches
NtDeviceIoControlFile. Nothing then wrote the IO status block, so
Internal stayed at STATUS_PENDING for good.
A caller that trusts HasOverlappedIoCompleted or GetOverlappedResult
sees a request that started and never finishes. Real DeviceIoControl
never leaves an OVERLAPPED pending after returning a synchronous
failure.
Record the status in Internal and clear InternalHigh whenever the call
comes back an NT failure. Where NtDeviceIoControlFile was actually
reached the kernel already wrote the same value, so the store is
idempotent, and the cast is through ULONG rather than ULONG_PTR so the
top half stays zero exactly as a kernel written IO_STATUS_BLOCK leaves
it, instead of sign extending the status. STATUS_PENDING is left alone:
that request really is outstanding and the kernel owns the block.
No event is signalled and no completion packet is queued, which is what
Windows does for a request that failed before it started.
Measured against this build and a build of the previous revision, with
a module loaded on a real handle:
before after
ordinary call Internal=00000000 completed=yes unchanged
name too long Internal=00000103 completed=NO Internal=C0000106 completed=yes
out_size overflow Internal=00000000 completed=yes Internal=C000000D completed=yes
The middle row is the leak. The third row only became a validation
failure with the preceding length fix -- before it the oversized
out_size was silently truncated to a byte count of zero and the call
"succeeded". The returned HRESULT, BOOL and last error are unchanged in
every row. N
namazso committed
9eed56c36e51a8560192c58e12bb356b510883cd
Parent: c9fcd85