Skip to content

Python: projected objects that outlive RoApartment crash the process (0xC0000005) on release or interpreter exit #189

Description

@lei9444

Problem Description

If a projected WinRT object is still referenced after the with RoApartment(...) block that created it exits, the Python process crashes with an access violation (0xC0000005, exit code -1073741819). It happens either when the object is released explicitly (del obj) or when the interpreter shuts down. Nothing is printed and no Python exception is raised; the process just dies.

bindings/py/README.md does say to "Use a projection lifetime scope inside the COM apartment so wrappers release their native values before RoUninitialize", and code that follows that pattern exits cleanly. But breaking the rule should give a clear Python error, a warning, or a safe leak, not a native crash. It is easy to hit by accident, for example with a module-level variable, or an object created inside RoApartment but outside projected_lifetime_scope().

Observations:

  • del obj right after leaving the apartment crashes immediately; the statement after del never runs. This points to IUnknown::Release running after RoUninitialize.
  • It happens with both RoApartment(0) (STA) and RoApartment(1) (MTA).
  • It reproduces on the published dynwinrt 0.1.0rc22 and also on a build of Clarify common Python runtime errors and name apartment constants #188, so it is not a regression from that PR.
  • Wrapping the object's creation in projected_lifetime_scope() inside the apartment (the documented pattern) exits with code 0.

Steps To Reproduce

  1. Generate bindings: dynwinrt-codegen generate --lang py --class-name Windows.Foundation.Uri --output ./generated

  2. Run:

    from dynwinrt import RoApartment
    from generated.windows.foundation import Uri
    
    with RoApartment(1):
        live = Uri("https://example.com/c")
        live.host
    
    print("left apartment", flush=True)
    del live  # crashes here: 0xC0000005
    print("after del", flush=True)  # never printed
  3. The process exits with code -1073741819 (0xC0000005) and "after del" is never printed. Without the del, the crash happens at interpreter shutdown instead, after the script's last line has run.

  4. For comparison, this exits with code 0:

    with RoApartment(1), projected_lifetime_scope():
        live = Uri("https://example.com/c")
        live.host

Expected Results

Leaving the apartment while projections are still alive should never crash the process. Possible behaviors, to be decided:

  • raise a clear error, or emit a warning naming the leaked projections, when RoApartment exits while its projections are still live;
  • and/or make release after RoUninitialize safe, for example by leaking the reference instead of calling Release into an uninitialized apartment. At minimum this should hold during interpreter shutdown.

Afterwards, using such an object should raise a Python exception, not crash. The lifecycle work in #188 could help here.

Component

Python bindings (dynwinrt)

Windows SDK Version

10.0.26100

Environment

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions