From 07d02099cb2946bde62bc249f42716ac636a7f30 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 21:53:26 +0000 Subject: [PATCH 1/7] Implement GetModuleSimpleName on DacDbiImpl using ILoader contract Replace the legacy-delegation stub with a contract-based implementation that uses ILoader.GetModuleHandleFromModulePtr and TryGetSimpleName. Follows the GetAppDomainFullName pattern with try/catch and DEBUG legacy validation. Add dump-based integration test. Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d565028d-e96a-4a77-961a-592e8f591a34 Co-authored-by: barosiak <76071368+barosiak@users.noreply.github.com> --- .../Dbi/DacDbiImpl.cs | 25 ++++++++++++++++++- .../DumpTests/DacDbi/DacDbiLoaderDumpTests.cs | 23 +++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index b08fabbc175a0b..55747eb6d6558c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -145,7 +145,30 @@ public int GetAppDomainFullName(ulong vmAppDomain, nint pStrName) } public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) - => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetModuleSimpleName(vmModule, pStrFilename) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + Contracts.ILoader loader = _target.Contracts.Loader; + Contracts.ModuleHandle handle = loader.GetModuleHandleFromModulePtr(new TargetPointer(vmModule)); + if (loader.TryGetSimpleName(handle, out string simpleName)) + { + hr = StringHolderAssignCopy(pStrFilename, simpleName); + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + int hrLocal = _legacy.GetModuleSimpleName(vmModule, pStrFilename); + Debug.ValidateHResult(hr, hrLocal); + } +#endif + return hr; + } public int GetAssemblyPath(ulong vmAssembly, nint pStrFilename, Interop.BOOL* pResult) { diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs index 5b8937bd8c66a4..da0f95fd9238a5 100644 --- a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs @@ -102,6 +102,29 @@ public unsafe void GetModuleData_ReturnsValidFields(TestConfiguration config) Assert.True(testedAtLeastOne, "Expected at least one module in the dump"); } + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public void GetModuleSimpleName_ReturnsNonEmpty(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + ILoader loader = Target.Contracts.Loader; + + bool testedAtLeastOne = false; + foreach (ModuleHandle module in GetAllModules()) + { + TargetPointer moduleAddr = loader.GetModule(module); + + using var holder = new NativeStringHolder(); + int hr = dbi.GetModuleSimpleName(moduleAddr.Value, holder.Ptr); + Assert.Equal(System.HResults.S_OK, hr); + Assert.False(string.IsNullOrEmpty(holder.Value), "Module simple name should not be empty"); + + testedAtLeastOne = true; + } + Assert.True(testedAtLeastOne, "Expected at least one module in the dump"); + } + [ConditionalTheory] [MemberData(nameof(TestConfigurations))] public unsafe void IsModuleMapped_ReturnsValidResult(TestConfiguration config) From baa787b9bf2ee53fd96284459bb34e0ce8230ce2 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Fri, 24 Apr 2026 16:15:57 -0700 Subject: [PATCH 2/7] Code cleanup --- .../Dbi/DacDbiImpl.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index 55747eb6d6558c..52d9b3332628a8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -151,10 +151,8 @@ public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) { Contracts.ILoader loader = _target.Contracts.Loader; Contracts.ModuleHandle handle = loader.GetModuleHandleFromModulePtr(new TargetPointer(vmModule)); - if (loader.TryGetSimpleName(handle, out string simpleName)) - { - hr = StringHolderAssignCopy(pStrFilename, simpleName); - } + loader.TryGetSimpleName(handle, out string simpleName); + hr = StringHolderAssignCopy(pStrFilename, simpleName ?? string.Empty); } catch (System.Exception ex) { From 83df67b71122bd39f21cc76f94a5dcadf09b50b0 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Mon, 27 Apr 2026 12:44:10 -0700 Subject: [PATCH 3/7] Address pr comments --- .../Dbi/DacDbiImpl.cs | 72 ++++++++++++++++++- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index c5d5bd92967ab6..ae1905f120ad29 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -147,12 +147,19 @@ public int GetAppDomainFullName(ulong vmAppDomain, nint pStrName) public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) { int hr = HResults.S_OK; + string? cdacSimpleName = null; try { Contracts.ILoader loader = _target.Contracts.Loader; Contracts.ModuleHandle handle = loader.GetModuleHandleFromModulePtr(new TargetPointer(vmModule)); - loader.TryGetSimpleName(handle, out string simpleName); - hr = StringHolderAssignCopy(pStrFilename, simpleName ?? string.Empty); + if (!loader.TryGetSimpleName(handle, out cdacSimpleName)) + { + hr = HResults.E_FAIL; + } + else + { + hr = StringHolderAssignCopy(pStrFilename, cdacSimpleName); + } } catch (System.Exception ex) { @@ -161,8 +168,15 @@ public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) #if DEBUG if (_legacy is not null) { - int hrLocal = _legacy.GetModuleSimpleName(vmModule, pStrFilename); + using var legacyHolder = new DebugStringHolder(); + int hrLocal = _legacy.GetModuleSimpleName(vmModule, legacyHolder.Ptr); Debug.ValidateHResult(hr, hrLocal); + if (hr >= 0 && hrLocal >= 0) + { + Debug.Assert( + string.Equals(cdacSimpleName, legacyHolder.Value, System.StringComparison.Ordinal), + $"GetModuleSimpleName string mismatch - cDAC: '{cdacSimpleName}', DAC: '{legacyHolder.Value}'"); + } } #endif return hr; @@ -1761,4 +1775,56 @@ public int GetAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, nint pAsyn public int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex) => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetGenericArgTokenIndex(vmMethod, pIndex) : HResults.E_NOTIMPL; + +#if DEBUG + /// + /// A managed IStringHolder that captures the string written via AssignCopy, + /// used in DEBUG builds to compare cDAC and legacy DAC string outputs + /// without overwriting the caller-provided string holder. + /// + private sealed class DebugStringHolder : IDisposable + { + private readonly IntPtr _objectPtr; + private readonly IntPtr _vtablePtr; + private readonly GCHandle _delegateHandle; + private bool _disposed; + + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate int AssignCopyDelegate(IntPtr thisPtr, IntPtr psz); + + public string? Value { get; private set; } + + public DebugStringHolder() + { + AssignCopyDelegate assignCopy = AssignCopyImpl; + _delegateHandle = GCHandle.Alloc(assignCopy); + IntPtr fnPtr = Marshal.GetFunctionPointerForDelegate(assignCopy); + + _vtablePtr = Marshal.AllocHGlobal(IntPtr.Size); + Marshal.WriteIntPtr(_vtablePtr, fnPtr); + + _objectPtr = Marshal.AllocHGlobal(IntPtr.Size); + Marshal.WriteIntPtr(_objectPtr, _vtablePtr); + } + + public nint Ptr => _objectPtr; + + private int AssignCopyImpl(IntPtr thisPtr, IntPtr psz) + { + Value = Marshal.PtrToStringUni(psz); + return HResults.S_OK; + } + + public void Dispose() + { + if (!_disposed) + { + Marshal.FreeHGlobal(_objectPtr); + Marshal.FreeHGlobal(_vtablePtr); + _delegateHandle.Free(); + _disposed = true; + } + } + } +#endif } From 6a51bb64c97e67a8390b1894434b53646d722c2f Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Tue, 28 Apr 2026 11:07:48 -0700 Subject: [PATCH 4/7] De-duplicate NativeStringHolder --- .../Dbi/DacDbiImpl.cs | 54 +------------------ .../NativeStringHolder.cs | 4 +- 2 files changed, 3 insertions(+), 55 deletions(-) rename src/native/managed/cdac/{tests/DumpTests/DacDbi => Microsoft.Diagnostics.DataContractReader.Legacy}/NativeStringHolder.cs (95%) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index ed70dd145314c7..fe9d65ab956c6f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -168,7 +168,7 @@ public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) #if DEBUG if (_legacy is not null) { - using var legacyHolder = new DebugStringHolder(); + using var legacyHolder = new NativeStringHolder(); int hrLocal = _legacy.GetModuleSimpleName(vmModule, legacyHolder.Ptr); Debug.ValidateHResult(hr, hrLocal); if (hr >= 0 && hrLocal >= 0) @@ -1800,56 +1800,4 @@ public int GetAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, nint pAsyn public int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex) => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetGenericArgTokenIndex(vmMethod, pIndex) : HResults.E_NOTIMPL; - -#if DEBUG - /// - /// A managed IStringHolder that captures the string written via AssignCopy, - /// used in DEBUG builds to compare cDAC and legacy DAC string outputs - /// without overwriting the caller-provided string holder. - /// - private sealed class DebugStringHolder : IDisposable - { - private readonly IntPtr _objectPtr; - private readonly IntPtr _vtablePtr; - private readonly GCHandle _delegateHandle; - private bool _disposed; - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - private delegate int AssignCopyDelegate(IntPtr thisPtr, IntPtr psz); - - public string? Value { get; private set; } - - public DebugStringHolder() - { - AssignCopyDelegate assignCopy = AssignCopyImpl; - _delegateHandle = GCHandle.Alloc(assignCopy); - IntPtr fnPtr = Marshal.GetFunctionPointerForDelegate(assignCopy); - - _vtablePtr = Marshal.AllocHGlobal(IntPtr.Size); - Marshal.WriteIntPtr(_vtablePtr, fnPtr); - - _objectPtr = Marshal.AllocHGlobal(IntPtr.Size); - Marshal.WriteIntPtr(_objectPtr, _vtablePtr); - } - - public nint Ptr => _objectPtr; - - private int AssignCopyImpl(IntPtr thisPtr, IntPtr psz) - { - Value = Marshal.PtrToStringUni(psz); - return HResults.S_OK; - } - - public void Dispose() - { - if (!_disposed) - { - Marshal.FreeHGlobal(_objectPtr); - Marshal.FreeHGlobal(_vtablePtr); - _delegateHandle.Free(); - _disposed = true; - } - } - } -#endif } diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/NativeStringHolder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/NativeStringHolder.cs similarity index 95% rename from src/native/managed/cdac/tests/DumpTests/DacDbi/NativeStringHolder.cs rename to src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/NativeStringHolder.cs index 8bca8e70b1bb24..9cf51b96b66c26 100644 --- a/src/native/managed/cdac/tests/DumpTests/DacDbi/NativeStringHolder.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/NativeStringHolder.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.InteropServices; -namespace Microsoft.Diagnostics.DataContractReader.DumpTests; +namespace Microsoft.Diagnostics.DataContractReader.Legacy; /// /// Creates a native-memory object that mimics the C++ IStringHolder vtable layout. @@ -52,7 +52,7 @@ public NativeStringHolder() private int AssignCopyImpl(IntPtr thisPtr, IntPtr psz) { Value = Marshal.PtrToStringUni(psz); - return System.HResults.S_OK; + return HResults.S_OK; } public void Dispose() From b0788105442c7efae80847e41bd537018e51df09 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 29 Apr 2026 11:19:12 -0700 Subject: [PATCH 5/7] trygetsimplename -> getssimplename --- docs/design/datacontracts/Loader.md | 9 +++------ .../Contracts/ILoader.cs | 2 +- .../Contracts/Loader_1.cs | 12 +++--------- .../ClrDataModule.cs | 3 +-- .../Dbi/DacDbiImpl.cs | 12 +++--------- src/native/managed/cdac/tests/LoaderTests.cs | 17 ++++------------- 6 files changed, 15 insertions(+), 40 deletions(-) diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index cefb2d8d5548e4..ee3ef4f1b30eea 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -80,7 +80,7 @@ IEnumerable GetInstantiatedMethods(ModuleHandle handle); bool IsProbeExtensionResultValid(ModuleHandle handle); ModuleFlags GetFlags(ModuleHandle handle); bool IsReadyToRun(ModuleHandle handle); -bool TryGetSimpleName(ModuleHandle handle, out string simpleName); +string GetSimpleName(ModuleHandle handle); string GetPath(ModuleHandle handle); string GetFileName(ModuleHandle handle); TargetPointer GetLoaderAllocator(ModuleHandle handle); @@ -622,14 +622,11 @@ ModuleFlags GetFlags(ModuleHandle handle) return GetFlags(target.Read(handle.Address + /* Module::Flags offset */)); } -bool TryGetSimpleName(ModuleHandle handle, out string simpleName) +string GetSimpleName(ModuleHandle handle) { TargetPointer simpleNameStart = target.ReadPointer(handle.Address + /* Module::SimpleName offset */); - if (simpleNameStart == TargetPointer.Null) - return false; byte[] simpleNameBytes = // Read from target starting at simpleNameStart until null terminator - simpleName = // convert to string, throw on invalid UTF-8 - return true; + return // convert to string, throw on invalid UTF-8 } string GetPath(ModuleHandle handle) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs index 96310c327c262b..76a07d7753696f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs @@ -103,7 +103,7 @@ public interface ILoader : IContract bool IsProbeExtensionResultValid(ModuleHandle handle) => throw new NotImplementedException(); ModuleFlags GetFlags(ModuleHandle handle) => throw new NotImplementedException(); bool IsReadyToRun(ModuleHandle handle) => throw new NotImplementedException(); - bool TryGetSimpleName(ModuleHandle handle, out string simpleName) => throw new NotImplementedException(); + string GetSimpleName(ModuleHandle handle) => throw new NotImplementedException(); string GetPath(ModuleHandle handle) => throw new NotImplementedException(); string GetFileName(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetLoaderAllocator(ModuleHandle handle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index cc517fbacb60ee..609a39ffc98b77 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -447,17 +447,11 @@ bool ILoader.IsReadyToRun(ModuleHandle handle) return module.ReadyToRunInfo != TargetPointer.Null; } - bool ILoader.TryGetSimpleName(ModuleHandle handle, out string simpleName) + string ILoader.GetSimpleName(ModuleHandle handle) { - simpleName = string.Empty; Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); - if (module.SimpleName != TargetPointer.Null) - { - simpleName = _target.ReadUtf8String(module.SimpleName, strict: true); - return true; - } - else - return false; + + return _target.ReadUtf8String(module.SimpleName, strict: true); } string ILoader.GetPath(ModuleHandle handle) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs index 552c484239d96e..5bdd38d8a1a782 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs @@ -460,8 +460,7 @@ int IXCLRDataModule.GetName(uint bufLen, uint* nameLen, char* name) *nameLen = 0; Contracts.ILoader loader = _target.Contracts.Loader; Contracts.ModuleHandle handle = loader.GetModuleHandleFromModulePtr(_address); - if (!loader.TryGetSimpleName(handle, out string result)) - throw new ArgumentException("Module does not have a simple name"); + string result = loader.GetSimpleName(handle); uint nameLenLocal = 0; OutputBufferHelpers.CopyStringToBuffer(name, bufLen, &nameLenLocal, result); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index 90ad503c8664c4..9f31efc01ec4c9 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -152,14 +152,8 @@ public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) { Contracts.ILoader loader = _target.Contracts.Loader; Contracts.ModuleHandle handle = loader.GetModuleHandleFromModulePtr(new TargetPointer(vmModule)); - if (!loader.TryGetSimpleName(handle, out cdacSimpleName)) - { - hr = HResults.E_FAIL; - } - else - { - hr = StringHolderAssignCopy(pStrFilename, cdacSimpleName); - } + cdacSimpleName = loader.GetSimpleName(handle); + hr = StringHolderAssignCopy(pStrFilename, cdacSimpleName); } catch (System.Exception ex) { @@ -171,7 +165,7 @@ public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) using var legacyHolder = new NativeStringHolder(); int hrLocal = _legacy.GetModuleSimpleName(vmModule, legacyHolder.Ptr); Debug.ValidateHResult(hr, hrLocal); - if (hr >= 0 && hrLocal >= 0) + if (hr == HResults.S_OK) { Debug.Assert( string.Equals(cdacSimpleName, legacyHolder.Value, System.StringComparison.Ordinal), diff --git a/src/native/managed/cdac/tests/LoaderTests.cs b/src/native/managed/cdac/tests/LoaderTests.cs index 5150460f4ef698..fc72b9ec4fa350 100644 --- a/src/native/managed/cdac/tests/LoaderTests.cs +++ b/src/native/managed/cdac/tests/LoaderTests.cs @@ -112,35 +112,26 @@ public void GetFileName(MockTarget.Architecture arch) [Theory] [ClassData(typeof(MockTarget.StdArch))] - public void TryGetSimpleName(MockTarget.Architecture arch) + public void GetSimpleName(MockTarget.Architecture arch) { string expected = "TestModule"; TargetPointer moduleAddr = TargetPointer.Null; - TargetPointer moduleAddrEmptyName = TargetPointer.Null; ILoader contract = CreateLoaderContract(arch, loader => { moduleAddr = loader.AddModule(simpleName: expected).Address; - moduleAddrEmptyName = loader.AddModule().Address; }); { Contracts.ModuleHandle handle = contract.GetModuleHandleFromModulePtr(moduleAddr); - bool result = contract.TryGetSimpleName(handle, out string actual); - Assert.True(result); + string actual = contract.GetSimpleName(handle); Assert.Equal(expected, actual); } - { - Contracts.ModuleHandle handle = contract.GetModuleHandleFromModulePtr(moduleAddrEmptyName); - bool result = contract.TryGetSimpleName(handle, out string actual); - Assert.False(result); - Assert.Equal(string.Empty, actual); - } } [Theory] [ClassData(typeof(MockTarget.StdArch))] - public void TryGetSimpleName_InvalidUtf8(MockTarget.Architecture arch) + public void GetSimpleName_InvalidUtf8(MockTarget.Architecture arch) { // 0xFF is not valid UTF-8 byte[] invalidUtf8 = [0xFF, 0xFE]; @@ -151,7 +142,7 @@ public void TryGetSimpleName_InvalidUtf8(MockTarget.Architecture arch) }); Contracts.ModuleHandle handle = contract.GetModuleHandleFromModulePtr(moduleAddr); - Assert.Throws(() => contract.TryGetSimpleName(handle, out _)); + Assert.Throws(() => contract.GetSimpleName(handle)); } private static readonly Dictionary MockHeapDictionary = new() From ce00eeb2d3c9f95762662bb367277cdab8ca5f83 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Wed, 29 Apr 2026 17:04:34 -0700 Subject: [PATCH 6/7] Change debuggee --- .../cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs index 68eb9cdb95a7f1..59df2071049170 100644 --- a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs @@ -10,11 +10,11 @@ namespace Microsoft.Diagnostics.DataContractReader.DumpTests; /// /// Dump-based integration tests for DacDbiImpl loader, assembly, and module methods. -/// Uses the MultiModule debuggee (full dump), which loads assemblies from multiple ALCs. +/// Uses the StackRefs debuggee (full dump), which loads assemblies from multiple ALCs. /// public class DacDbiLoaderDumpTests : DumpTestBase { - protected override string DebuggeeName => "MultiModule"; + protected override string DebuggeeName => "StackRefs"; private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); private IEnumerable GetAllModules() From cc4b218d97094b60c60bcf8612a0ca32eca39c57 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Thu, 30 Apr 2026 13:02:06 -0700 Subject: [PATCH 7/7] Address pr comments --- .../Contracts/Loader_1.cs | 5 +++-- .../DumpTests/DacDbi/DacDbiLoaderDumpTests.cs | 3 ++- src/native/managed/cdac/tests/LoaderTests.cs | 22 +++++++++++++++---- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index 609a39ffc98b77..1a4ddc04445b03 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -450,8 +450,9 @@ bool ILoader.IsReadyToRun(ModuleHandle handle) string ILoader.GetSimpleName(ModuleHandle handle) { Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); - - return _target.ReadUtf8String(module.SimpleName, strict: true); + return module.SimpleName != TargetPointer.Null + ? _target.ReadUtf8String(module.SimpleName, strict: true) + : string.Empty; } string ILoader.GetPath(ModuleHandle handle) diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs index 59df2071049170..d82ddc0c29dc0d 100644 --- a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.Diagnostics.DataContractReader.DumpTests; /// /// Dump-based integration tests for DacDbiImpl loader, assembly, and module methods. -/// Uses the StackRefs debuggee (full dump), which loads assemblies from multiple ALCs. +/// Uses the StackRefs debuggee (full dump). /// public class DacDbiLoaderDumpTests : DumpTestBase { @@ -154,6 +154,7 @@ public void GetModuleSimpleName_ReturnsNonEmpty(TestConfiguration config) int hr = dbi.GetModuleSimpleName(moduleAddr.Value, holder.Ptr); Assert.Equal(System.HResults.S_OK, hr); Assert.False(string.IsNullOrEmpty(holder.Value), "Module simple name should not be empty"); + Assert.Equal(loader.GetSimpleName(module), holder.Value); testedAtLeastOne = true; } diff --git a/src/native/managed/cdac/tests/LoaderTests.cs b/src/native/managed/cdac/tests/LoaderTests.cs index fc72b9ec4fa350..cd3b2be5f8cc8e 100644 --- a/src/native/managed/cdac/tests/LoaderTests.cs +++ b/src/native/managed/cdac/tests/LoaderTests.cs @@ -122,11 +122,25 @@ public void GetSimpleName(MockTarget.Architecture arch) moduleAddr = loader.AddModule(simpleName: expected).Address; }); + Contracts.ModuleHandle handle = contract.GetModuleHandleFromModulePtr(moduleAddr); + string actual = contract.GetSimpleName(handle); + Assert.Equal(expected, actual); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetSimpleName_NullSimpleName(MockTarget.Architecture arch) + { + TargetPointer moduleAddr = TargetPointer.Null; + + ILoader contract = CreateLoaderContract(arch, loader => { - Contracts.ModuleHandle handle = contract.GetModuleHandleFromModulePtr(moduleAddr); - string actual = contract.GetSimpleName(handle); - Assert.Equal(expected, actual); - } + moduleAddr = loader.AddModule().Address; + }); + + Contracts.ModuleHandle handle = contract.GetModuleHandleFromModulePtr(moduleAddr); + string actual = contract.GetSimpleName(handle); + Assert.Equal(string.Empty, actual); } [Theory]