Skip to content

Fix COM wrapper weak-handle defensive copy in ReferenceTrackerNativeObjectWrapper#129668

Open
Copilot wants to merge 3 commits into
mainfrom
copilot/bugfix-potential-double-free-comwrappers
Open

Fix COM wrapper weak-handle defensive copy in ReferenceTrackerNativeObjectWrapper#129668
Copilot wants to merge 3 commits into
mainfrom
copilot/bugfix-potential-double-free-comwrappers

Conversation

Copilot AI commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

This change addresses a COM wrapper lifetime bug where GCHandle.Free() could execute on a defensive copy of _nativeObjectWrapperWeakHandle, making cleanup non-idempotent under finalization/release interleavings.
The fix is surgical: remove readonly so Free() updates the actual field state.

  • What changed

    • In System.Runtime.InteropServices.ComWrappers.ReferenceTrackerNativeObjectWrapper, changed:
      • internal readonly GCHandle _nativeObjectWrapperWeakHandle;
      • to internal GCHandle _nativeObjectWrapperWeakHandle;
  • Why this matters

    • GCHandle is a mutable struct.
    • Calling mutating members on a readonly field can operate on a defensive copy.
    • For Release()/finalizer race handling, this can lead to stale IsAllocated state and duplicate free behavior.
  • Code example

    // Before
    internal readonly GCHandle _nativeObjectWrapperWeakHandle;
    
    // After
    internal GCHandle _nativeObjectWrapperWeakHandle;

Copilot AI requested review from Copilot and removed request for Copilot June 21, 2026 13:37
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jun 21, 2026
@jkotas jkotas added area-System.Runtime.InteropServices and removed area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI labels Jun 21, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot June 21, 2026 14:21
Copilot AI changed the title [WIP] Fix potential double free in ComWrappers implementation Fix COM wrapper weak-handle defensive copy in ReferenceTrackerNativeObjectWrapper Jun 21, 2026
Copilot AI requested a review from jkotas June 21, 2026 14:22
@jkotas jkotas requested a review from AaronRobinsonMSFT June 21, 2026 14:37
@jkotas jkotas marked this pull request as ready for review June 21, 2026 14:37
Copilot AI review requested due to automatic review settings June 21, 2026 14:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a correctness issue in CoreLib’s COM wrapper tracking path by ensuring _nativeObjectWrapperWeakHandle.Free() mutates the actual stored GCHandle field (avoiding readonly-field defensive copies) so cleanup becomes reliably idempotent.

Changes:

  • Changed ReferenceTrackerNativeObjectWrapper._nativeObjectWrapperWeakHandle from readonly to mutable to prevent GCHandle.Free() from operating on a defensive copy.
  • Ensures subsequent cleanup paths (e.g., re-release/finalizer flows) can observe the freed state.

Comment on lines +670 to +672
private int _trackerObjectDisconnected; // Atomic boolean, so using int.
private readonly bool _releaseTrackerObject;
internal readonly GCHandle _nativeObjectWrapperWeakHandle;
internal GCHandle _nativeObjectWrapperWeakHandle;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this. These sorts of gotchas crop up and we've no tests that can help us know we've done something wrong.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Add comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in b42d42a.

Comment on lines +671 to +672
private readonly bool _releaseTrackerObject;
internal readonly GCHandle _nativeObjectWrapperWeakHandle;
internal GCHandle _nativeObjectWrapperWeakHandle;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is very difficult to add deterministic test that verifies there is no GC handle double-free.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI requested a review from jkotas June 22, 2026 03:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants