Skip to content

Harden Python preview collection, lifetime, interface, and async safety - #198

Open
leileizhang (lei9444) wants to merge 9 commits into
mainfrom
lei9444-fix-python-preview-blockers
Open

leileizhang (lei9444) wants to merge 9 commits into
mainfrom
lei9444-fix-python-preview-blockers

Conversation

@lei9444

@lei9444 leileizhang (lei9444) commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Reject native-null IJsonValue inputs before mutating stock JsonArray/JsonObject (including raw arrays, slices, updates, and generic interface views), while preserving native nulls in custom generic collections. Stock-class stubs and generated runtime annotations, including --no-pyi, now describe the non-null input contract.
  • Track owned raw Python outputs inside apartment lifetime scopes (Python: projected objects that outlive RoApartment crash the process (0xC0000005) on release or interpreter exit #189). Independently owned COM-bearing DynWinRTArray and DynWinRTStruct containers are also weakly observed at creation/extraction, released before apartment teardown, and fail explicitly on use after release. Scalar containers remain usable; native reference ownership and callback affinity are preserved.
  • QueryInterface-check generated interface constructors before caching or dispatch; a mismatched IBuffer(uri._obj) now fails with E_NOINTERFACE without consuming its source.
  • Reject Async receivers before DynWinRTValue.call_0/call_1 native dispatch (Reject Async receivers in low-level Python call_0/call_1 before vtable dispatch #196).
  • Fifth integration correction: avoid rooting temporary raw COM casts and callback inputs in Python: projected objects that outlive RoApartment crash the process (0xC0000005) on release or interpreter exit #189 lifetime scopes; refresh seven generated Python snapshots required by the IID-constructor commit. The original four commits were not rewritten.
  • Additive follow-ups: packaged ProjectedLifetimeScope.track_native stub parity (commit 6), projection-only COM-drop fixture correction (commit 7), stock JSON runtime/--no-pyi annotations (commit 8), and independent array/struct COM-owner cleanup (commit 9). All changes are additive; no published history was rewritten.

Validation

  • Rust core: 499 passed, 1 ignored; codegen: 652 passed, 1 ignored; Python binding Rust: 11 passed.
  • Before the container fix, isolated subprocesses reproduced five Object-array/struct apartment-exit crashes (0xC0000005) and two native reference-balance failures. Afterward, direct, extracted and nested COM containers exit cleanly, native owners close at scope exit, scalar containers remain live, and released-container operations raise. The complete Python binding suite passes (14 optional WinUI fixture skips).
  • Generated Python E2E: 55/55 WinRT, 20/20 implementations, with strict generated declaration checks. Strict mypy/Pyright consumers, installed-wheel mypy.stubtest, --no-pyi/inspect.signature, JS/TS snapshots and declaration typechecks pass.
  • The full local codegen suite passes except one unrelated Windows-path-length-limited mypy fixture (its generated filename is 262 characters on this worktree); the hosted shorter-path test covers it. cargo fmt --all --check and git diff --check pass.

No release pipeline, XML DOM nullability, or published preview.22 release-note changes are included.

Validate the receiver's stock runtime-class contract before JSON value writes, preflight bulk mutations, and keep custom generic collections nullable. Narrow verified stock class stubs and test real native behavior and strict consumers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Register owned native results at Python return boundaries so a closing scope releases raw values before apartment teardown, while preserving borrowed sources, scalar results, callback thread affinity, and released-value errors. Reproduce and guard the shutdown crash in subprocesses.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
QueryInterface-check standalone constructors before retaining or caching a pointer, preserve borrowed constructor sources on cache hits, and fail closed for unknown IIDs. Keep generic and observable projections safe with real WinRT and strict typing regressions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Require an Object before call_0/call_1 can prepare or dispatch a caller-specified native signature. Exercise pre-dispatch rejection and valid IID-cast low-level calls in an isolated Python process.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Observe raw outputs weakly so temporary casts and callback inputs drop without accumulating native references; keep projected wrappers strongly tracked and release surviving raw owners before apartment shutdown. Refresh seven generated Python snapshots for the interface-IID constructor change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Mixed-language test coverage

Workflow status: ✅ Passed

Layer Lines Functions Branches/regions
Rust, including native .pyd/.node 86.92% 82.44% 86.65% regions
Python aggregate 72.34% n/a 39.42% branches
Python runtime 98.17% n/a 94.57% branches
Generated Python WinRT projections 71.08% n/a 33.5% branches
Generated Python WinRT implementations 71.97% n/a 46.3% branches
JavaScript aggregate 21.91% 25.18% 57.61% branches
JavaScript runtime 44.27% 45.76% 78.99% branches
Generated WinRT projections 22.8% 18.7% 54.84% branches
Generated WinRT implementations 45.99% 59.19% 60.97% branches
Generated Classic COM projections 11.88% 23.97% 53.4% branches

View workflow run and download full HTML/LCOV/XML reports

Match ProjectedLifetimeScope.track_native in the packaged Python stub and test the installed wheel surface, fixing hosted mypy.stubtest parity without changing native lifetime behavior.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Match DynWinRTValue's owned-reference drop in the projection-only test double and accept the checked-constructor cache argument. Assert that an unconsumed temporary returns the native owner's reference count to baseline.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Make stock JsonArray/JsonObject runtime method inputs non-null in both normal and --no-pyi output, keeping generic IVector/IMap<IJsonValue> nullable. Verify generated source and inspect.signature contracts without changing JS/TS projections.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Weakly track independent DynWinRTArray and DynWinRTStruct owners at creation, extraction, and nested-field boundaries. Deterministically release surviving COM references at scope exit, reject all post-release access, and leave scalar containers live. Cover five previously crashing subprocess paths, nested arrays, and native reference balance.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant