Skip to content

Clear RCW cache entries when releasing wrapper objects#125754

Open
jkoritzinsky wants to merge 5 commits intodotnet:mainfrom
jkoritzinsky:rcw-cache-clear
Open

Clear RCW cache entries when releasing wrapper objects#125754
jkoritzinsky wants to merge 5 commits intodotnet:mainfrom
jkoritzinsky:rcw-cache-clear

Conversation

@jkoritzinsky
Copy link
Member

Remove native wrappers from the RCW cache in the tracker support global instance when releasing external objects for the Jupiter runtime. Without this change, a disconnected COM object wrapper could remain in the ComWrappers instance's cache. Then, if a new COM object is allocated at the same address (only possible because the COM objects were forcibly disconnected when ComWrappers.ReleaseObjects was called as part of the request from the Jupiter runtime), the old, disconnected COM object wrapper would be returned by ComWrappers.

Unblocks Microsoft Store migration to NativeAOT.

…al instance when releasing external objects for the Jupiter runtime
@jkoritzinsky jkoritzinsky added area-System.Runtime.InteropServices partner-impact This issue impacts a partner who needs to be kept updated labels Mar 18, 2026
@jkoritzinsky
Copy link
Member Author

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0 (link to workflow run)

@dotnet-policy-service
Copy link
Contributor

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

Copy link
Contributor

Copilot AI left a comment

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 the reference-tracker (Jupiter) integration where RCW cache entries could outlive a forced disconnect, potentially causing ComWrappers to return a stale/disconnected wrapper if the native COM address is reused. This is particularly relevant for enabling NativeAOT scenarios that rely on ComWrappers.ReleaseObjects-driven disconnection.

Changes:

  • Track ReferenceTrackerNativeObjectWrapper instances released on thread-end and remove them from the RCW cache before calling ReleaseObjects.
  • Add an internal ComWrappers.RemoveWrappersFromCache(...) helper and a bulk-removal path in RcwCache.
  • Refactor RCW cache removal logic into a shared RemoveLocked(...) helper to avoid duplication.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.cs Collects wrappers to remove during thread-end release and invokes RCW cache clearing before releasing objects.
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs Adds an internal cache-removal API and implements bulk RCW cache removal with shared locked logic.

@jkoritzinsky
Copy link
Member Author

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0 (link to workflow run)

Copilot AI review requested due to automatic review settings March 19, 2026 20:59
@jkoritzinsky
Copy link
Member Author

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0 (link to workflow run)

Copy link
Contributor

Copilot AI left a comment

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 the COM tracker-support flow by ensuring RCW cache entries are cleared when external objects are released for the Jupiter runtime, preventing stale/disconnected wrappers from being returned if a COM object address is later reused.

Changes:

  • Remove eligible ReferenceTrackerNativeObjectWrapper instances from the global tracker-support ComWrappers RCW cache during ReleaseExternalObjectsFromCurrentThread.
  • Add ComWrappers/RcwCache APIs to remove multiple wrappers from the RCW cache in a single write-lock.
  • Add a regression test validating a new RCW is created after NotifyEndOfReferenceTrackingOnThread clears the cache.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/tests/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.cs Updates test harness behavior and adds a regression test for RCW cache clearing after thread-end notification.
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.cs Collects wrappers to remove and clears RCW cache entries during thread-end external object release.
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs Adds bulk RCW cache removal support and refactors removal logic to share a locked helper.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 19, 2026 23:22
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@jkoritzinsky
Copy link
Member Author

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0 (link to workflow run)

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment on lines 88 to +92
nativeObjectWrapper.DisconnectTracker();

if (nativeObjectWrapper.ComWrappers == GlobalInstanceForTrackerSupport)
{
wrappersToRemove.Add(nativeObjectWrapper);
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

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

ReleaseExternalObjectsFromCurrentThread calls DisconnectTracker() for all ReferenceTrackerNativeObjectWrapper instances in the current context, regardless of owning ComWrappers, but only removes wrappers from the RCW cache when nativeObjectWrapper.ComWrappers == GlobalInstanceForTrackerSupport. This leaves disconnected wrappers in other ComWrappers instances' RCW caches, so those instances can still return a stale/disconnected wrapper for the same COM address later. Consider removing from each wrapper's owning ComWrappers cache (eg group wrappers by nativeObjectWrapper.ComWrappers and call RemoveWrappersFromCache per instance), or alternatively limit the disconnect/release flow to only wrappers owned by the global tracker-support instance.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Runtime.InteropServices partner-impact This issue impacts a partner who needs to be kept updated

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants