Skip to content

Replace the process-wide externally-owned mark in ObjectTracker with per-owner tracking #7378

Closed

Description

@thomhurst

Raised by the Claude review of #7328 (comment 6569591414, point 3), which fixes #7205.

What: #7328 stops the object tracker from disposing services that a disposable dependency injection scope owns. It does this with a process-wide, permanent mark: ObjectTracker.MarkExternallyOwned (src/TUnit.Core/Tracking/ObjectTracker.cs) adds the object to a static ConditionalWeakTable. Several places compensate for that mark: UntrackObject, ShouldSkipTracking, the session-end sweep, and the TryAddInjected/TryAddOwned/heldByExternalOwner branch of ObjectGraphDiscoverer.DiscoverNestedObjectsForTracking. That branch marks nested initializer objects as a side effect of discovery. The check-then-mark is not atomic. ExternallyOwnedSingletonTests covers the interleaving the remarks describe.

Proposed: track ownership per owner instead of process-wide. The data source returns or registers an owner handle (the scope or row), and the tracker skips objects registered under it. That removes the static table, the race, and the mutation during traversal.

Acceptance:

  • No process-wide ownership state in ObjectTracker.
  • Objects that a scope owns are still initialized and never disposed by the tracker. Objects TUnit injected beneath them are still disposed once.
  • Bugs._7205 and ExternallyOwnedSingletonTests (or their replacements) pass in source-generated and reflection modes.

Prerequisite

Blocked by #7382, the ownership portion of replacement PR #7384. PR #7328 was closed without merging; its review remains historical context.

Activity

  1. added
    enhancementNew feature or request
    P3Low: cleanup, minor enhancement, or rare edge case
    on Nov 2, 2026
  2. thomhurst commented on Nov 2, 2026

    @thomhurst
    OwnerAuthor

    Triage: #7328 was closed without merging. Its external-ownership implementation is now in open PR #7384, which closes #7382. Replaced the broad #7205 parent dependency with #7382 so this follow-up can proceed as soon as ownership lands, without waiting for unrelated session-lifetime work in #7383. The requested work is still absent from main d8badac.

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

    P3Low: cleanup, minor enhancement, or rare edge caseenhancementNew feature or requestin-progressWork is in progress

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions