From 3d345dfbaadf36c708fc75a8848b45c98ebee6ad Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 12 Apr 2026 20:46:01 +0000
Subject: [PATCH 01/10] Agent-Logs-Url:
https://github.com/dotnet/runtime/sessions/3366f85c-89fb-4c74-a840-d9c748b9f2a3
Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3366f85c-89fb-4c74-a840-d9c748b9f2a3
Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3366f85c-89fb-4c74-a840-d9c748b9f2a3
Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com>
add interop APIs
---
.../Dbi/DacDbiImpl.cs | 83 ++++++++++++++++++-
.../DumpTests/DacDbi/DacDbiCCWDumpTests.cs | 74 +++++++++++++++++
.../DacDbi/DacDbiComWrappersDumpTests.cs | 60 ++++++++++++++
.../DumpTests/DacDbi/DacDbiRCWDumpTests.cs | 80 ++++++++++++++++++
4 files changed, 295 insertions(+), 2 deletions(-)
create mode 100644 src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs
create mode 100644 src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs
create mode 100644 src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRCWDumpTests.cs
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 95fdef60493597..b11a6bc8610cee 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
@@ -16,6 +16,7 @@ public sealed unsafe partial class DacDbiImpl : IDacDbiInterface
{
private readonly Target _target;
private readonly IDacDbiInterface? _legacy;
+ private readonly ulong _rcwMask = 1UL;
// IStringHolder is a native C++ abstract class (not COM) with a single virtual method:
// virtual HRESULT AssignCopy(const WCHAR* psz) = 0;
@@ -546,7 +547,61 @@ public int GetCurrentException(ulong vmThread, ulong* pRetVal)
}
public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal)
- => _legacy is not null ? _legacy.GetObjectForCCW(ccwPtr, pRetVal) : HResults.E_NOTIMPL;
+ {
+ *pRetVal = 0;
+ int hr = HResults.S_OK;
+ try
+ {
+ TargetPointer objectHandle = TargetPointer.Null;
+ TargetPointer ccwAddress = new(ccwPtr);
+
+ try
+ {
+ IComWrappers comWrappers = _target.Contracts.ComWrappers;
+ TargetPointer managedObjectWrapper = comWrappers.GetManagedObjectWrapperFromCCW(ccwAddress);
+ if (managedObjectWrapper != TargetPointer.Null)
+ {
+ objectHandle = _target.ReadPointer(managedObjectWrapper);
+ }
+ }
+ catch (NotImplementedException)
+ {
+ // Targets without ComWrappers support should still try BuiltInCOM.
+ }
+
+ if (objectHandle == TargetPointer.Null)
+ {
+ IBuiltInCOM builtInCOM = _target.Contracts.BuiltInCOM;
+ TargetPointer ccw = builtInCOM.GetCCWFromInterfacePointer(ccwAddress);
+ if (ccw != TargetPointer.Null)
+ {
+ objectHandle = builtInCOM.GetObjectHandle(ccw);
+ }
+ else
+ {
+ // not an interface pointer
+ objectHandle = builtInCOM.GetObjectHandle(ccwAddress);
+ }
+ }
+
+ *pRetVal = objectHandle.Value;
+ }
+ catch (System.Exception ex)
+ {
+ hr = ex.HResult;
+ }
+#if DEBUG
+ if (_legacy is not null)
+ {
+ ulong retValLocal;
+ int hrLocal = _legacy.GetObjectForCCW(ccwPtr, &retValLocal);
+ Debug.ValidateHResult(hr, hrLocal);
+ if (hr == HResults.S_OK)
+ Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal:x}, DAC: {retValLocal:x}");
+ }
+#endif
+ return hr;
+ }
public int GetCurrentCustomDebuggerNotification(ulong vmThread, ulong* pRetVal)
=> _legacy is not null ? _legacy.GetCurrentCustomDebuggerNotification(vmThread, pRetVal) : HResults.E_NOTIMPL;
@@ -822,7 +877,31 @@ public int GetStackFramesFromException(ulong vmObject, nint pDacStackFrames)
=> _legacy is not null ? _legacy.GetStackFramesFromException(vmObject, pDacStackFrames) : HResults.E_NOTIMPL;
public int IsRcw(ulong vmObject, Interop.BOOL* pResult)
- => _legacy is not null ? _legacy.IsRcw(vmObject, pResult) : HResults.E_NOTIMPL;
+ {
+ *pResult = Interop.BOOL.FALSE;
+ int hr = HResults.S_OK;
+ try
+ {
+ IObject obj = _target.Contracts.Object;
+ _ = obj.GetBuiltInComData(new TargetPointer(vmObject), out TargetPointer rcw, out _, out _);
+ *pResult = (rcw & _rcwMask) != TargetPointer.Null ? Interop.BOOL.TRUE : Interop.BOOL.FALSE;
+ }
+ catch (System.Exception ex)
+ {
+ hr = ex.HResult;
+ }
+#if DEBUG
+ if (_legacy is not null)
+ {
+ Interop.BOOL resultLocal;
+ int hrLocal = _legacy.IsRcw(vmObject, &resultLocal);
+ Debug.ValidateHResult(hr, hrLocal);
+ if (hr == HResults.S_OK)
+ Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
+ }
+#endif
+ return hr;
+ }
public int GetRcwCachedInterfaceTypes(ulong vmObject, ulong vmAppDomain, Interop.BOOL bIInspectableOnly, nint pDacInterfaces)
=> _legacy is not null ? _legacy.GetRcwCachedInterfaceTypes(vmObject, vmAppDomain, bIInspectableOnly, pDacInterfaces) : HResults.E_NOTIMPL;
diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs
new file mode 100644
index 00000000000000..6c765b236f467e
--- /dev/null
+++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Diagnostics.DataContractReader.Contracts;
+using Microsoft.Diagnostics.DataContractReader.Legacy;
+using Microsoft.DotNet.XUnitExtensions;
+using Xunit;
+
+namespace Microsoft.Diagnostics.DataContractReader.DumpTests;
+
+///
+/// Dump-based integration tests for DacDbiImpl.GetObjectForCCW.
+/// Uses the CCW debuggee (full dump).
+///
+public class DacDbiCCWDumpTests : DumpTestBase
+{
+ protected override string DebuggeeName => "CCW";
+ protected override string DumpType => "full";
+
+ private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null);
+
+ private (TargetPointer Ccw, TargetPointer InterfacePointer) FindBuiltInComCcwWithInterface()
+ {
+ IGC gc = Target.Contracts.GC;
+ IObject obj = Target.Contracts.Object;
+ IBuiltInCOM builtInCOM = Target.Contracts.BuiltInCOM;
+
+ foreach (HandleData handleData in gc.GetHandles([HandleType.Strong]))
+ {
+ TargetPointer objectAddress = Target.ReadPointer(handleData.Handle);
+ if (objectAddress == TargetPointer.Null)
+ continue;
+
+ if (!obj.GetBuiltInComData(objectAddress, out _, out TargetPointer ccw, out _)
+ || ccw == TargetPointer.Null)
+ {
+ continue;
+ }
+
+ List interfaces = builtInCOM.GetCCWInterfaces(ccw).ToList();
+ if (interfaces.Count == 0)
+ continue;
+
+ TargetPointer interfacePointer = Target.ReadPointer(interfaces[0].InterfacePointerAddress);
+ if (interfacePointer == TargetPointer.Null)
+ continue;
+
+ return (ccw, interfacePointer);
+ }
+
+ throw new SkipTestException("No BuiltInCOM CCW interface pointer found in dump.");
+ }
+
+ [ConditionalTheory]
+ [MemberData(nameof(TestConfigurations))]
+ [SkipOnOS(IncludeOnly = "windows", Reason = "COM callable wrappers require Windows")]
+ public unsafe void GetObjectForCCW_ReturnsBuiltInComObjectHandle(TestConfiguration config)
+ {
+ InitializeDumpTest(config);
+ DacDbiImpl dbi = CreateDacDbi();
+ IBuiltInCOM builtInCOM = Target.Contracts.BuiltInCOM;
+
+ (TargetPointer ccw, TargetPointer interfacePointer) = FindBuiltInComCcwWithInterface();
+
+ ulong resultHandle;
+ int hr = dbi.GetObjectForCCW(interfacePointer.Value, &resultHandle);
+
+ Assert.Equal(System.HResults.S_OK, hr);
+ Assert.Equal(builtInCOM.GetObjectHandle(ccw).Value, resultHandle);
+ Assert.NotEqual(TargetPointer.Null, Target.ReadPointer(new TargetPointer(resultHandle)));
+ }
+}
diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs
new file mode 100644
index 00000000000000..f7d3a980aa6553
--- /dev/null
+++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using Microsoft.Diagnostics.DataContractReader.Contracts;
+using Microsoft.Diagnostics.DataContractReader.Legacy;
+using Microsoft.DotNet.XUnitExtensions;
+using Xunit;
+
+namespace Microsoft.Diagnostics.DataContractReader.DumpTests;
+
+///
+/// Dump-based integration tests for DacDbiImpl.GetObjectForCCW via the ComWrappers path.
+/// Uses the ComWrappers debuggee (full dump).
+///
+public class DacDbiComWrappersDumpTests : DumpTestBase
+{
+ protected override string DebuggeeName => "ComWrappers";
+ protected override string DumpType => "full";
+
+ private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null);
+
+ [ConditionalTheory]
+ [MemberData(nameof(TestConfigurations))]
+ [SkipOnVersion("net10.0", "ComWrappers cDAC support not available in .NET 10")]
+ [SkipOnOS(IncludeOnly = "windows", Reason = "COM/ComWrappers CCW scenarios are validated on Windows")]
+ public unsafe void GetObjectForCCW_ComWrappersIdentityPointer_ReturnsManagedObjectWrapperHandle(TestConfiguration config)
+ {
+ InitializeDumpTest(config);
+ DacDbiImpl dbi = CreateDacDbi();
+ IGC gc = Target.Contracts.GC;
+ IComWrappers comWrappers = Target.Contracts.ComWrappers;
+
+ foreach (HandleData handleData in gc.GetHandles([HandleType.Strong]))
+ {
+ TargetPointer objectAddress = Target.ReadPointer(handleData.Handle);
+ if (objectAddress == TargetPointer.Null)
+ continue;
+
+ List mows = comWrappers.GetMOWs(objectAddress, out bool hasMowTable);
+ if (!hasMowTable || mows.Count == 0)
+ continue;
+
+ TargetPointer mow = mows[0];
+ TargetPointer identity = comWrappers.GetIdentityForMOW(mow);
+ if (identity == TargetPointer.Null)
+ continue;
+
+ ulong expectedHandle = Target.ReadPointer(mow).Value;
+ ulong actualHandle;
+ int hr = dbi.GetObjectForCCW(identity.Value, &actualHandle);
+
+ Assert.Equal(System.HResults.S_OK, hr);
+ Assert.Equal(expectedHandle, actualHandle);
+ return;
+ }
+
+ throw new SkipTestException("No ComWrappers MOW/CCW identity found in dump.");
+ }
+}
diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRCWDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRCWDumpTests.cs
new file mode 100644
index 00000000000000..47f6ed89748625
--- /dev/null
+++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRCWDumpTests.cs
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Diagnostics.DataContractReader.Contracts;
+using Microsoft.Diagnostics.DataContractReader.Legacy;
+using Microsoft.DotNet.XUnitExtensions;
+using Xunit;
+
+namespace Microsoft.Diagnostics.DataContractReader.DumpTests;
+
+///
+/// Dump-based integration tests for DacDbiImpl.IsRcw.
+/// Uses the RCW debuggee (full dump).
+///
+public class DacDbiRCWDumpTests : DumpTestBase
+{
+ protected override string DebuggeeName => "RCW";
+ protected override string DumpType => "full";
+
+ private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null);
+
+ [ConditionalTheory]
+ [MemberData(nameof(TestConfigurations))]
+ [SkipOnOS(IncludeOnly = "windows", Reason = "COM interop (RCW) is only supported on Windows")]
+ public unsafe void IsRcw_ReturnsTrueForBuiltInRcwObject(TestConfiguration config)
+ {
+ InitializeDumpTest(config);
+ DacDbiImpl dbi = CreateDacDbi();
+ IGC gc = Target.Contracts.GC;
+ IObject obj = Target.Contracts.Object;
+
+ foreach (HandleData handleData in gc.GetHandles([HandleType.Strong]))
+ {
+ TargetPointer objectAddress = Target.ReadPointer(handleData.Handle);
+ if (objectAddress == TargetPointer.Null)
+ continue;
+
+ if (!obj.GetBuiltInComData(objectAddress, out TargetPointer rcw, out _, out _) || rcw == TargetPointer.Null)
+ continue;
+
+ Interop.BOOL result;
+ int hr = dbi.IsRcw(objectAddress.Value, &result);
+ Assert.Equal(System.HResults.S_OK, hr);
+ Assert.Equal(Interop.BOOL.TRUE, result);
+ return;
+ }
+
+ throw new SkipTestException("No built-in RCW object found in dump.");
+ }
+
+ [ConditionalTheory]
+ [MemberData(nameof(TestConfigurations))]
+ [SkipOnOS(IncludeOnly = "windows", Reason = "COM interop (RCW) is only supported on Windows")]
+ public unsafe void IsRcw_ReturnsFalseForNonRcwObject(TestConfiguration config)
+ {
+ InitializeDumpTest(config);
+ DacDbiImpl dbi = CreateDacDbi();
+ IGC gc = Target.Contracts.GC;
+ IObject obj = Target.Contracts.Object;
+
+ foreach (HandleData handleData in gc.GetHandles([HandleType.Strong]))
+ {
+ TargetPointer objectAddress = Target.ReadPointer(handleData.Handle);
+ if (objectAddress == TargetPointer.Null)
+ continue;
+
+ _ = obj.GetBuiltInComData(objectAddress, out TargetPointer rcw, out _, out _);
+ if (rcw != TargetPointer.Null)
+ continue;
+
+ Interop.BOOL result;
+ int hr = dbi.IsRcw(objectAddress.Value, &result);
+ Assert.Equal(System.HResults.S_OK, hr);
+ Assert.Equal(Interop.BOOL.FALSE, result);
+ return;
+ }
+
+ throw new SkipTestException("No non-RCW object found in dump.");
+ }
+}
From 80e52d17a79250d0cee7f526ca26a96d8ecb370b Mon Sep 17 00:00:00 2001
From: Rachel
Date: Wed, 15 Apr 2026 12:16:52 -0700
Subject: [PATCH 02/10] Update DacDbiComWrappersDumpTests.cs
---
.../cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs
index f7d3a980aa6553..ab282ce322fc09 100644
--- a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs
+++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs
@@ -23,7 +23,6 @@ public class DacDbiComWrappersDumpTests : DumpTestBase
[ConditionalTheory]
[MemberData(nameof(TestConfigurations))]
[SkipOnVersion("net10.0", "ComWrappers cDAC support not available in .NET 10")]
- [SkipOnOS(IncludeOnly = "windows", Reason = "COM/ComWrappers CCW scenarios are validated on Windows")]
public unsafe void GetObjectForCCW_ComWrappersIdentityPointer_ReturnsManagedObjectWrapperHandle(TestConfiguration config)
{
InitializeDumpTest(config);
From 7258f1addb5e4fa62616e2e6b597dd9a86899625 Mon Sep 17 00:00:00 2001
From: rcj1
Date: Wed, 15 Apr 2026 12:51:57 -0700
Subject: [PATCH 03/10] copilot comments
---
.../Dbi/DacDbiImpl.cs | 12 ++++--------
1 file changed, 4 insertions(+), 8 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 b11a6bc8610cee..801d6d796ef032 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
@@ -16,7 +16,6 @@ public sealed unsafe partial class DacDbiImpl : IDacDbiInterface
{
private readonly Target _target;
private readonly IDacDbiInterface? _legacy;
- private readonly ulong _rcwMask = 1UL;
// IStringHolder is a native C++ abstract class (not COM) with a single virtual method:
// virtual HRESULT AssignCopy(const WCHAR* psz) = 0;
@@ -575,13 +574,10 @@ public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal)
TargetPointer ccw = builtInCOM.GetCCWFromInterfacePointer(ccwAddress);
if (ccw != TargetPointer.Null)
{
- objectHandle = builtInCOM.GetObjectHandle(ccw);
- }
- else
- {
- // not an interface pointer
- objectHandle = builtInCOM.GetObjectHandle(ccwAddress);
+ ccw = ccwAddress;
}
+ ccw = builtInCOM.GetStartWrapper(ccw);
+ objectHandle = builtInCOM.GetObjectFromCCW(ccw);
}
*pRetVal = objectHandle.Value;
@@ -884,7 +880,7 @@ public int IsRcw(ulong vmObject, Interop.BOOL* pResult)
{
IObject obj = _target.Contracts.Object;
_ = obj.GetBuiltInComData(new TargetPointer(vmObject), out TargetPointer rcw, out _, out _);
- *pResult = (rcw & _rcwMask) != TargetPointer.Null ? Interop.BOOL.TRUE : Interop.BOOL.FALSE;
+ *pResult = rcw != TargetPointer.Null ? Interop.BOOL.TRUE : Interop.BOOL.FALSE;
}
catch (System.Exception ex)
{
From c82b05e7568c97119caeabc528706b7ba18f3ffb Mon Sep 17 00:00:00 2001
From: Rachel
Date: Wed, 15 Apr 2026 17:42:10 -0700
Subject: [PATCH 04/10] Rename method GetObjectFromCCW to GetObjectHandle
---
.../Dbi/DacDbiImpl.cs | 2 +-
1 file changed, 1 insertion(+), 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 801d6d796ef032..3cffa06e8fbd84 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
@@ -577,7 +577,7 @@ public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal)
ccw = ccwAddress;
}
ccw = builtInCOM.GetStartWrapper(ccw);
- objectHandle = builtInCOM.GetObjectFromCCW(ccw);
+ objectHandle = builtInCOM.GetObjectHandle(ccw);
}
*pRetVal = objectHandle.Value;
From acb652fe146f6e2729c64dc7029fec56328d7706 Mon Sep 17 00:00:00 2001
From: Rachel
Date: Wed, 15 Apr 2026 22:17:02 -0700
Subject: [PATCH 05/10] Update DacDbiImpl.cs
---
.../Dbi/DacDbiImpl.cs | 2 +-
1 file changed, 1 insertion(+), 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 3cffa06e8fbd84..d728f0892bf005 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
@@ -572,7 +572,7 @@ public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal)
{
IBuiltInCOM builtInCOM = _target.Contracts.BuiltInCOM;
TargetPointer ccw = builtInCOM.GetCCWFromInterfacePointer(ccwAddress);
- if (ccw != TargetPointer.Null)
+ if (ccw == TargetPointer.Null)
{
ccw = ccwAddress;
}
From f66279f4ff7fdfdb769932741d1b6a1a0143a631 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Apr 2026 16:47:26 +0000
Subject: [PATCH 06/10] Fix two unresolved dump test review comments
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/65246430-549d-4bcc-b123-778dbb73db29
Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com>
---
.../cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs | 8 ++++++--
.../tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs | 5 +++++
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs
index 6c765b236f467e..a855ebe056b3a1 100644
--- a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs
+++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs
@@ -39,7 +39,11 @@ public class DacDbiCCWDumpTests : DumpTestBase
continue;
}
- List interfaces = builtInCOM.GetCCWInterfaces(ccw).ToList();
+ // Normalize to the start wrapper, matching what DacDbiImpl.GetObjectForCCW does
+ // before calling GetObjectHandle, so the expected handle in the test is consistent.
+ TargetPointer startCcw = builtInCOM.GetStartWrapper(ccw);
+
+ List interfaces = builtInCOM.GetCCWInterfaces(startCcw).ToList();
if (interfaces.Count == 0)
continue;
@@ -47,7 +51,7 @@ public class DacDbiCCWDumpTests : DumpTestBase
if (interfacePointer == TargetPointer.Null)
continue;
- return (ccw, interfacePointer);
+ return (startCcw, interfacePointer);
}
throw new SkipTestException("No BuiltInCOM CCW interface pointer found in dump.");
diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs
index ab282ce322fc09..0bcb2521ee5f92 100644
--- a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs
+++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs
@@ -51,6 +51,11 @@ public unsafe void GetObjectForCCW_ComWrappersIdentityPointer_ReturnsManagedObje
Assert.Equal(System.HResults.S_OK, hr);
Assert.Equal(expectedHandle, actualHandle);
+
+ // Verify the returned handle dereferences to a live object in the dump.
+ TargetPointer actualHandleTarget = new(actualHandle);
+ TargetPointer actualObjectAddress = Target.ReadPointer(actualHandleTarget);
+ Assert.NotEqual(TargetPointer.Null, actualObjectAddress);
return;
}
From 54275e73ecd642e3172d21015384a682b1bb2598 Mon Sep 17 00:00:00 2001
From: rcj1
Date: Fri, 17 Apr 2026 10:00:57 -0700
Subject: [PATCH 07/10] use trygetcontract
---
.../Dbi/DacDbiImpl.cs | 12 ++++--------
1 file changed, 4 insertions(+), 8 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 eaf9bf0a5b191c..756f137d6fa5a5 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
@@ -488,22 +488,18 @@ public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal)
{
TargetPointer objectHandle = TargetPointer.Null;
TargetPointer ccwAddress = new(ccwPtr);
+ bool comWrappersSuccess = false;
- try
+ if (_target.Contracts.TryGetContract(out IComWrappers? comWrappers))
{
- IComWrappers comWrappers = _target.Contracts.ComWrappers;
TargetPointer managedObjectWrapper = comWrappers.GetManagedObjectWrapperFromCCW(ccwAddress);
if (managedObjectWrapper != TargetPointer.Null)
{
- objectHandle = _target.ReadPointer(managedObjectWrapper);
+ comWrappersSuccess = _target.TryReadPointer(managedObjectWrapper, out objectHandle);
}
}
- catch (NotImplementedException)
- {
- // Targets without ComWrappers support should still try BuiltInCOM.
- }
- if (objectHandle == TargetPointer.Null)
+ if (!comWrappersSuccess || objectHandle == TargetPointer.Null)
{
IBuiltInCOM builtInCOM = _target.Contracts.BuiltInCOM;
TargetPointer ccw = builtInCOM.GetCCWFromInterfacePointer(ccwAddress);
From 2478f6147dd6690d7cf8ffd51b90ebc2f4f42780 Mon Sep 17 00:00:00 2001
From: rcj1
Date: Thu, 23 Apr 2026 10:28:30 -0700
Subject: [PATCH 08/10] fix test
---
.../cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs
index a855ebe056b3a1..a08cfe17300e1c 100644
--- a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs
+++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs
@@ -47,11 +47,7 @@ public class DacDbiCCWDumpTests : DumpTestBase
if (interfaces.Count == 0)
continue;
- TargetPointer interfacePointer = Target.ReadPointer(interfaces[0].InterfacePointerAddress);
- if (interfacePointer == TargetPointer.Null)
- continue;
-
- return (startCcw, interfacePointer);
+ return (startCcw, interfaces[0].InterfacePointerAddress);
}
throw new SkipTestException("No BuiltInCOM CCW interface pointer found in dump.");
From 0f3960533d21e8bd720810929b28ea02f38b33d4 Mon Sep 17 00:00:00 2001
From: rcj1
Date: Thu, 23 Apr 2026 13:31:12 -0700
Subject: [PATCH 09/10] code review
---
.../Contracts/ComWrappers_1.cs | 5 +++--
.../Dbi/DacDbiImpl.cs | 3 +--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ComWrappers_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ComWrappers_1.cs
index 6d12808352319a..b3fcc3c5b255f8 100644
--- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ComWrappers_1.cs
+++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ComWrappers_1.cs
@@ -56,8 +56,9 @@ private bool IsComWrappersCCW(TargetPointer ccw)
if (!GetComWrappersCCWVTableQIAddress(ccw, out _, out TargetPointer qiAddress))
return false;
- TargetPointer comWrappersVtablePtrs = _target.ReadGlobalPointer(Constants.Globals.ComWrappersVtablePtrs);
- Data.ComWrappersVtablePtrs comWrappersVtableStruct = _target.ProcessedData.GetOrAdd(comWrappersVtablePtrs);
+ if (!_target.TryReadPointer(Constants.Globals.ComWrappersVtablePtrs, out TargetPointer? comWrappersVtablePtrs))
+ return false;
+ Data.ComWrappersVtablePtrs comWrappersVtableStruct = _target.ProcessedData.GetOrAdd(comWrappersVtablePtrs.Value);
return comWrappersVtableStruct.ComWrappersInterfacePointers.Contains(CodePointerUtils.CodePointerFromAddress(qiAddress, _target));
}
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 fcc846c2a52c56..3103c306e4a3d2 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
@@ -670,9 +670,8 @@ public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal)
}
}
- if (!comWrappersSuccess || objectHandle == TargetPointer.Null)
+ if (!comWrappersSuccess && _target.Contracts.TryGetContract(out IBuiltInCOM? builtInCOM))
{
- IBuiltInCOM builtInCOM = _target.Contracts.BuiltInCOM;
TargetPointer ccw = builtInCOM.GetCCWFromInterfacePointer(ccwAddress);
if (ccw == TargetPointer.Null)
{
From e27006e732764ed6d6c71abbe673b7e09dbf4111 Mon Sep 17 00:00:00 2001
From: Rachel Jarvi
Date: Thu, 23 Apr 2026 14:58:13 -0700
Subject: [PATCH 10/10] Update pointer reading method in ComWrappers_1.cs
---
.../Contracts/ComWrappers_1.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ComWrappers_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ComWrappers_1.cs
index b3fcc3c5b255f8..e7cdfc0400c0f7 100644
--- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ComWrappers_1.cs
+++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ComWrappers_1.cs
@@ -56,7 +56,7 @@ private bool IsComWrappersCCW(TargetPointer ccw)
if (!GetComWrappersCCWVTableQIAddress(ccw, out _, out TargetPointer qiAddress))
return false;
- if (!_target.TryReadPointer(Constants.Globals.ComWrappersVtablePtrs, out TargetPointer? comWrappersVtablePtrs))
+ if (!_target.TryReadGlobalPointer(Constants.Globals.ComWrappersVtablePtrs, out TargetPointer? comWrappersVtablePtrs))
return false;
Data.ComWrappersVtablePtrs comWrappersVtableStruct = _target.ProcessedData.GetOrAdd(comWrappersVtablePtrs.Value);
return comWrappersVtableStruct.ComWrappersInterfacePointers.Contains(CodePointerUtils.CodePointerFromAddress(qiAddress, _target));