Problem Description
The Python binding's low-level DynWinRTValue.call_0() and call_1() can accept a WinRTValue::Async as their receiver. WinRTValue::as_object() converts the stored IAsyncInfo to an IUnknown pointer (crates/dynwinrt/src/value.rs), and these helpers then pass that pointer, a caller-supplied vtable index, and a caller-supplied ABI signature directly to call_dynamic() (bindings/py/src/runtime.rs). The native dispatcher reads the function pointer at that slot (crates/dynwinrt/src/call.rs). It does not first QueryInterface to the concrete IAsyncOperation<T>/IAsyncAction interface or verify that the selected slot has the requested signature.
A wrong receiver/slot/signature can call an unrelated method with an incompatible ABI or read past the vtable, potentially causing an access violation instead of a Python exception. This is a source-level risk; no crashing invocation was run during this investigation. Ordinary async wait()/generated await uses the concrete async interface, and DynWinRTMethodHandle.invoke() already rejects Async receivers. This is distinct from the apartment-shutdown release crash tracked in #189 and is not introduced or resolved by #188.
Steps To Reproduce
- Obtain a raw
DynWinRTValue holding the result of a WinRT async method (WinRTValue::Async internally).
- Inspect
DynWinRTValue.call_0() / call_1() in bindings/py/src/runtime.rs: both use .as_object() to obtain the receiver pointer; WinRTValue::as_object() accepts Async in crates/dynwinrt/src/value.rs.
- These helpers pass that pointer to a dynamically built method with a caller-provided index/signature. Calling with an index/signature intended for another interface reaches
get_vtable_function_ptr() without a receiver-interface check. Do not run such a potentially crashing call outside an isolated process.
No live crash reproduction is claimed here; the steps establish the unsafe dispatch path.
Expected Results
call_0() and call_1() should reject an Async receiver before native dispatch, with a clear Python exception, consistent with call() and DynWinRTMethodHandle.invoke(). Async completion should continue to use wait()/the generated await path, which resolves the concrete async interface before calling GetResults. Add a regression test that verifies rejection without invoking an invalid native vtable slot.
Component
Python bindings (dynwinrt)
Windows SDK Version
10.0.26100
Environment
- Windows; Python binding using the WinRT dynamic invocation core.
- Source-level analysis only; a specific OS/Python version or observed crash is not required to establish the missing receiver check.
Problem Description
The Python binding's low-level
DynWinRTValue.call_0()andcall_1()can accept aWinRTValue::Asyncas their receiver.WinRTValue::as_object()converts the storedIAsyncInfoto anIUnknownpointer (crates/dynwinrt/src/value.rs), and these helpers then pass that pointer, a caller-supplied vtable index, and a caller-supplied ABI signature directly tocall_dynamic()(bindings/py/src/runtime.rs). The native dispatcher reads the function pointer at that slot (crates/dynwinrt/src/call.rs). It does not first QueryInterface to the concreteIAsyncOperation<T>/IAsyncActioninterface or verify that the selected slot has the requested signature.A wrong receiver/slot/signature can call an unrelated method with an incompatible ABI or read past the vtable, potentially causing an access violation instead of a Python exception. This is a source-level risk; no crashing invocation was run during this investigation. Ordinary async
wait()/generated await uses the concrete async interface, andDynWinRTMethodHandle.invoke()already rejectsAsyncreceivers. This is distinct from the apartment-shutdown release crash tracked in #189 and is not introduced or resolved by #188.Steps To Reproduce
DynWinRTValueholding the result of a WinRT async method (WinRTValue::Asyncinternally).DynWinRTValue.call_0()/call_1()inbindings/py/src/runtime.rs: both use.as_object()to obtain the receiver pointer;WinRTValue::as_object()acceptsAsyncincrates/dynwinrt/src/value.rs.get_vtable_function_ptr()without a receiver-interface check. Do not run such a potentially crashing call outside an isolated process.No live crash reproduction is claimed here; the steps establish the unsafe dispatch path.
Expected Results
call_0()andcall_1()should reject anAsyncreceiver before native dispatch, with a clear Python exception, consistent withcall()andDynWinRTMethodHandle.invoke(). Async completion should continue to usewait()/the generated await path, which resolves the concrete async interface before callingGetResults. Add a regression test that verifies rejection without invoking an invalid native vtable slot.Component
Python bindings (dynwinrt)
Windows SDK Version
10.0.26100
Environment