Skip to content

AddLoadedRuntime#1497

Open
leculver wants to merge 10 commits into
microsoft:mainfrom
leculver:new-startup-path
Open

AddLoadedRuntime#1497
leculver wants to merge 10 commits into
microsoft:mainfrom
leculver:new-startup-path

Conversation

@leculver

Copy link
Copy Markdown
Contributor

This pull request introduces several improvements and refactorings to the ClrMD runtime detection and hosting APIs, with a focus on supporting host-supplied runtimes (such as those provided by SOS), improving test coverage, and simplifying some internal code paths. The most important changes are outlined below.

Host-supplied runtime support and API improvements

  • Refactored the ClrInfo class to support construction for host-supplied runtimes, allowing external hosts to provide their own IXCLRDataProcess and DAC lock, rather than relying solely on ClrMD's runtime detection and DAC loading. This includes adding the ClrDataProcessFactory and DacLock properties and updating runtime creation logic to use them when present. [1] [2] [3]
  • Added a new overload and logic in DacServiceProvider to support host-owned IXCLRDataProcess pointers, ensuring proper reference counting and lock sharing for thread safety.

Test coverage enhancements

  • Added comprehensive tests in DataTargetTests.cs to verify that host-supplied runtimes are correctly registered and replace existing entries, and that heap enumeration matches between normal and host-supplied runtimes.

Internal refactoring and simplification

  • Moved thin lock layout selection from DacHeap constructor arguments to TargetProperties, simplifying the interface and centralizing layout logic. [1] [2] [3] [4]
  • Split DAC library resolution into dedicated methods (GetDacLibraryFromPath and CreateDacFromPath) in ClrInfo for improved readability and maintainability.

Minor fixes and code cleanup

  • Updated several wrapper and helper classes to remove unnecessary parameters and streamline initialization, such as in ClrSymbolProviderWrapper and ClrModuleInfo. [1] [2]
  • Ensured proper disposal order in test helper Scope.Dispose to avoid resource leaks.

These changes collectively improve ClrMD's flexibility for advanced hosting scenarios, increase test reliability, and simplify internal APIs.

leculver added 9 commits July 15, 2026 08:23
Move the ThinLockLayout enum out of DacHeap into its own file and carry it on TargetProperties, computed once per runtime in DacServiceProvider. DacHeap now reads _target.ThinLockLayout instead of a separate ctor parameter. Pointer-size-only TargetProperties instances (DacLibrary, DacDataTarget) use the conservative Legacy layout since their layout is never consumed.

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

Copilot-Session: 9f6a7174-a30a-45e3-8475-430831714734
SkipRuntimeEnumeration (default false) makes ClrMD skip all runtime detection so ClrVersions is empty unless a host registers runtimes via AddLoadedRuntime, avoiding paying for enumeration a host does itself.

AddLoadedRuntime now replaces an existing runtime that has the same ModuleInfo instead of appending a duplicate, so a module maps to a single runtime.

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

Copilot-Session: 9f6a7174-a30a-45e3-8475-430831714734
- Stable/shared dacLock: AddLoadedRuntime now stores a single non-null lock per ClrInfo (not a fresh one per CreateRuntime), so host-registered runtimes serialize consistently.
- Synchronize _clrs: AddLoadedRuntime mutation and ClrVersions lazy init now share a lock (double-checked), preventing lost-update races.
- Foreign IXCLRDataProcess: release the pre-wrapper Marshal.AddRef if ClrDataProcess construction fails, and dispose the process (releasing the ref) if the DacServiceProvider QI chain throws.
- DacTypeHelpers.GetILMap: dispose each ClrDataMethod in a finally so a DAC throw no longer leaks native COM (release builds have no finalizer net).
- DacServiceProvider.Dispose is now idempotent (returns instead of throwing on repeat).
- Nit: thinLockLayout casing; drop the duplicate GetThinLockLayout computation in CreateForeignProcess (pointer-only target uses Legacy).
- Test: ClrObjectTests.Scope.Dispose now disposes the ClrRuntime (not just the DataTarget); it was leaking a runtime whose cached ClrDataModule tripped the DEBUG finalizer at host shutdown.

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

Copilot-Session: 9f6a7174-a30a-45e3-8475-430831714734
@leculver leculver requested a review from hoyosjs July 15, 2026 19:27

if (_clrs.IsDefault)
if (!_clrs.IsDefault)
return _clrs;

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 don't know if this should be both the list and sentinel - it means AddRuntime immediately causes ClrVersions to never iterate (once registration is used, no other runtime is discovered), But if iteration is done and then registration happens, you get the 2 of them.

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.

Good point, fixed.

AddLoadedRuntime populated _clrs, and GetOrCreateClrVersions gated enumeration on _clrs.IsDefault, so registering a runtime before the first ClrVersions query silently suppressed ClrMD's own enumeration. Add an explicit _enumerated flag so enumeration is gated solely by SkipRuntimeEnumeration. ClrMD's enumerated runtimes are now merged with any already-registered ones, with the host registration winning on a matching ModuleInfo.

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

Copilot-Session: 9f6a7174-a30a-45e3-8475-430831714734
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.

2 participants