From 2888d44b93e19c519d7b5f2f6e09309a859badf3 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sun, 21 Sep 2025 16:16:07 -0700 Subject: [PATCH 01/23] e --- src/coreclr/interop/comwrappers.hpp | 18 +++ src/coreclr/interop/inc/interoplibabi.h | 10 +- .../vm/datadescriptor/datadescriptor.h | 3 + .../vm/datadescriptor/datadescriptor.inc | 15 +++ .../vm/interoplibinterface_comwrappers.h | 7 ++ .../Contracts/IComWrappers.cs | 4 + .../DataType.cs | 2 + .../Constants.cs | 3 + .../Contracts/ComWrappers_1.cs | 65 ++++++++++ .../Data/ManagedObjectWrapperHolderObject.cs | 18 +++ .../Data/ManagedObjectWrapperLayout.cs | 18 +++ .../Legacy/SOSDacImpl.cs | 114 +++++++++++++++++- src/tests/profiler/rejit/rejit.cs | 2 + 13 files changed, 275 insertions(+), 4 deletions(-) create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ManagedObjectWrapperHolderObject.cs create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ManagedObjectWrapperLayout.cs diff --git a/src/coreclr/interop/comwrappers.hpp b/src/coreclr/interop/comwrappers.hpp index 00ebfc39194b96..75fa058dcd407a 100644 --- a/src/coreclr/interop/comwrappers.hpp +++ b/src/coreclr/interop/comwrappers.hpp @@ -169,4 +169,22 @@ struct ComHolder } } }; + +// Keep these forward declarations in sync with the method definitions in interop/comwrappers.cpp +namespace InteropLib +{ + namespace ABI + { + struct ComInterfaceDispatch; + } +} +HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface( + _In_ InteropLib::ABI::ComInterfaceDispatch* disp, + /* [in] */ REFIID riid, + /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject); +HRESULT STDMETHODCALLTYPE TrackerTarget_QueryInterface( + _In_ InteropLib::ABI::ComInterfaceDispatch* disp, + /* [in] */ REFIID riid, + /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject); + #endif // _INTEROP_COMWRAPPERS_HPP_ diff --git a/src/coreclr/interop/inc/interoplibabi.h b/src/coreclr/interop/inc/interoplibabi.h index 217ecda8b73e28..c8ad0deb4f9b01 100644 --- a/src/coreclr/interop/inc/interoplibabi.h +++ b/src/coreclr/interop/inc/interoplibabi.h @@ -6,6 +6,7 @@ #include #include +#include "../../vm/cdacdata.h" namespace InteropLib { @@ -22,7 +23,7 @@ namespace InteropLib constexpr size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2. #endif - constexpr intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1); + constexpr uintptr_t DispatchThisPtrMask = ~(static_cast((DispatchAlignmentThisPtr) - 1u)); static_assert(sizeof(void*) < DispatchAlignmentThisPtr, "DispatchAlignmentThisPtr must be larger than sizeof(void*)."); @@ -55,6 +56,7 @@ namespace InteropLib // This is designed to codify the binary layout. struct ManagedObjectWrapperLayout { + friend struct ::cdac_data; public: LONGLONG GetRawRefCount() const { @@ -81,4 +83,10 @@ namespace InteropLib } } +template<> +struct cdac_data +{ + static constexpr size_t RefCount = offsetof(InteropLib::ABI::ManagedObjectWrapperLayout, _refCount); +}; + #endif // _INTEROP_INC_INTEROPLIBABI_H_ diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.h b/src/coreclr/vm/datadescriptor/datadescriptor.h index 651975ba0cc4c7..6f81ace686545f 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.h +++ b/src/coreclr/vm/datadescriptor/datadescriptor.h @@ -22,6 +22,9 @@ #include "../debug/ee/debugger.h" #include "patchpointinfo.h" +#ifdef FEATURE_COMWRAPPERS +#include "../interop/comwrappers.hpp" +#endif // FEATURE_COMWRAPPERS #ifdef HAVE_GCCOVER #include "gccover.h" diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 3844f70514e612..64abab80af64e2 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -153,6 +153,16 @@ CDAC_TYPE_BEGIN(NativeObjectWrapperObject) CDAC_TYPE_INDETERMINATE(NativeObjectWrapperObject) CDAC_TYPE_FIELD(NativeObjectWrapperObject, /*pointer*/, ExternalComObject, cdac_data::ExternalComObject) CDAC_TYPE_END(NativeObjectWrapperObject) + +CDAC_TYPE_BEGIN(ManagedObjectWrapperHolderObject) +CDAC_TYPE_INDETERMINATE(ManagedObjectWrapperHolderObject) +CDAC_TYPE_FIELD(ManagedObjectWrapperHolderObject, /*pointer*/, WrappedObject, cdac_data::WrappedObject) +CDAC_TYPE_END(ManagedObjectWrapperHolderObject) + +CDAC_TYPE_BEGIN(ManagedObjectWrapperLayout) +CDAC_TYPE_INDETERMINATE(ManagedObjectWrapperLayout) +CDAC_TYPE_FIELD(ManagedObjectWrapperLayout, /*int64*/, RefCount, cdac_data::RefCount) +CDAC_TYPE_END(ManagedObjectWrapperLayout) #endif // FEATURE_COMWRAPPERS CDAC_TYPE_BEGIN(SyncTableEntry) @@ -1012,6 +1022,11 @@ CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize) CDAC_GLOBAL_POINTER(DacNotificationFlags, &::g_dacNotificationFlags) CDAC_GLOBAL_POINTER(OffsetOfCurrentThreadInfo, &::g_offsetOfCurrentThreadInfo) CDAC_GLOBAL_POINTER(ThinlockThreadIdDispenser, &::g_pThinLockThreadIdDispenser) +#ifdef FEATURE_COMWRAPPERS +CDAC_GLOBAL(DispatchThisPtrMask, uintptr_t, InteropLib::ABI::DispatchThisPtrMask) +CDAC_GLOBAL_POINTER(MOWQueryInterface, &ManagedObjectWrapper_QueryInterface) +CDAC_GLOBAL_POINTER(TrackerTargetQueryInterface, &TrackerTarget_QueryInterface) +#endif // FEATURE_COMWRAPPERS #ifdef TARGET_WINDOWS CDAC_GLOBAL_POINTER(TlsIndexBase, &::_tls_index) #endif // TARGET_WINDOWS diff --git a/src/coreclr/vm/interoplibinterface_comwrappers.h b/src/coreclr/vm/interoplibinterface_comwrappers.h index ce19830fa98119..2defdae7b5931f 100644 --- a/src/coreclr/vm/interoplibinterface_comwrappers.h +++ b/src/coreclr/vm/interoplibinterface_comwrappers.h @@ -77,6 +77,13 @@ class ManagedObjectWrapperHolderObject : public Object public: OBJECTREF _wrappedObject; DPTR(InteropLib::ABI::ManagedObjectWrapperLayout) _wrapper; + friend struct ::cdac_data; +}; + +template<> +struct cdac_data +{ + static constexpr size_t WrappedObject = offsetof(ManagedObjectWrapperHolderObject, _wrappedObject); }; class NativeObjectWrapperObject : public Object diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IComWrappers.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IComWrappers.cs index 257012cb5528e0..2904e98ccda794 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IComWrappers.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IComWrappers.cs @@ -9,6 +9,10 @@ public interface IComWrappers : IContract { static string IContract.Name { get; } = nameof(ComWrappers); TargetPointer GetComWrappersIdentity(TargetPointer address) => throw new NotImplementedException(); + TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) => throw new NotImplementedException(); + TargetPointer GetComWrappersObjectFromMOW(TargetPointer mow) => throw new NotImplementedException(); + long GetMOWReferenceCount(TargetPointer mow) => throw new NotImplementedException(); + bool IsComWrappersRCW(TargetPointer rcw) => throw new NotImplementedException(); } public readonly struct ComWrappers : IComWrappers diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index d2cf878cb8a6c7..cae3f0a9319424 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -67,6 +67,8 @@ public enum DataType StressMsgHeader, Object, NativeObjectWrapperObject, + ManagedObjectWrapperHolderObject, + ManagedObjectWrapperLayout, String, MethodDesc, MethodDescChunk, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index 084afe879f99c1..0c1b1d78390f80 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -32,6 +32,9 @@ public static class Globals public const string OffsetOfCurrentThreadInfo = nameof(OffsetOfCurrentThreadInfo); public const string TlsIndexBase = nameof(TlsIndexBase); public const string ThinlockThreadIdDispenser = nameof(ThinlockThreadIdDispenser); + public const string DispatchThisPtrMask = nameof(DispatchThisPtrMask); + public const string MOWQueryInterface = nameof(MOWQueryInterface); + public const string TrackerTargetQueryInterface = nameof(TrackerTargetQueryInterface); public const string StressLogEnabled = nameof(StressLogEnabled); public const string StressLogHasModuleTable = nameof(StressLogHasModuleTable); 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 98b0a54dc0c416..f3e3894f5b1c75 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 @@ -22,4 +22,69 @@ public TargetPointer GetComWrappersIdentity(TargetPointer address) Data.NativeObjectWrapperObject wrapper = _target.ProcessedData.GetOrAdd(address); return wrapper.ExternalComObject; } + + private bool GetComWrappersCCWVTableQIAddress(TargetPointer ccw, out TargetPointer vtable, out TargetPointer qiAddress) + { + vtable = TargetPointer.Null; + qiAddress = TargetPointer.Null; + try + { + TargetPointer vtableAddress = _target.ReadPointer(ccw); + if (vtableAddress == TargetPointer.Null) + return false; + qiAddress = _target.ReadPointer(vtableAddress); + if (qiAddress == TargetPointer.Null) + return false; + } + catch (VirtualReadException) + { + return false; + } + qiAddress = CodePointerUtils.AddressFromCodePointer(qiAddress.Value, _target); + return true; + } + + private bool IsComWrappersCCW(TargetPointer ccw) + { + if (!GetComWrappersCCWVTableQIAddress(ccw, out _, out TargetPointer qiAddress)) + return false; + + return qiAddress == _target.ReadGlobalPointer(Constants.Globals.MOWQueryInterface) || + qiAddress == _target.ReadGlobalPointer(Constants.Globals.TrackerTargetQueryInterface); + } + + public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) + { + if (!IsComWrappersCCW(ccw)) + return TargetPointer.Null; + try + { + return _target.ReadPointer(ccw & _target.ReadGlobalPointer(Constants.Globals.DispatchThisPtrMask)); + } + catch (VirtualReadException) + { + return TargetPointer.Null; + } + } + + public TargetPointer GetComWrappersObjectFromMOW(TargetPointer mow) + { + TargetPointer objHandle = _target.ReadPointer(mow); + Data.ObjectHandle handle = _target.ProcessedData.GetOrAdd(objHandle); + Data.ManagedObjectWrapperHolderObject mowHolderObject = _target.ProcessedData.GetOrAdd(handle.Object); + return mowHolderObject.WrappedObject; + } + + public long GetMOWReferenceCount(TargetPointer mow) + { + Data.ManagedObjectWrapperLayout layout = _target.ProcessedData.GetOrAdd(mow); + return layout.RefCount; + } + + public bool IsComWrappersRCW(TargetPointer rcw) + { + Contracts.IObject objContract = _target.Contracts.Object; + TargetPointer mt = objContract.GetMethodTableAddress(rcw); + return mt != TargetPointer.Null; + } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ManagedObjectWrapperHolderObject.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ManagedObjectWrapperHolderObject.cs new file mode 100644 index 00000000000000..39c4851d87790c --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ManagedObjectWrapperHolderObject.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class ManagedObjectWrapperHolderObject : IData +{ + static ManagedObjectWrapperHolderObject IData.Create(Target target, TargetPointer address) => new ManagedObjectWrapperHolderObject(target, address); + public ManagedObjectWrapperHolderObject(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ManagedObjectWrapperHolderObject); + WrappedObject = target.ReadPointer(address + (ulong)type.Fields[nameof(WrappedObject)].Offset); + } + + public TargetPointer WrappedObject { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ManagedObjectWrapperLayout.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ManagedObjectWrapperLayout.cs new file mode 100644 index 00000000000000..0dfbc1d0bc124b --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ManagedObjectWrapperLayout.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class ManagedObjectWrapperLayout : IData +{ + static ManagedObjectWrapperLayout IData.Create(Target target, TargetPointer address) => new ManagedObjectWrapperLayout(target, address); + public ManagedObjectWrapperLayout(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ManagedObjectWrapperLayout); + RefCount = target.Read(address + (ulong)type.Fields[nameof(RefCount)].Offset); + } + + public long RefCount { get; init; } +} diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 157406337bbd22..f9ee2a96aa5e30 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -3353,11 +3353,119 @@ int ISOSDacInterface9.GetBreakingChangeVersion() int ISOSDacInterface10.GetObjectComWrappersData(ClrDataAddress objAddr, ClrDataAddress* rcw, uint count, ClrDataAddress* mowList, uint* pNeeded) => _legacyImpl10 is not null ? _legacyImpl10.GetObjectComWrappersData(objAddr, rcw, count, mowList, pNeeded) : HResults.E_NOTIMPL; int ISOSDacInterface10.IsComWrappersCCW(ClrDataAddress ccw, Interop.BOOL* isComWrappersCCW) - => _legacyImpl10 is not null ? _legacyImpl10.IsComWrappersCCW(ccw, isComWrappersCCW) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + Contracts.IComWrappers comWrappersContract = _target.Contracts.ComWrappers; + if (ccw == 0) + throw new ArgumentException(); + + if (isComWrappersCCW != null) + { + TargetPointer ccwPtr = comWrappersContract.GetManagedObjectWrapperFromCCW(ccw.ToTargetPointer(_target)); + *isComWrappersCCW = (ccwPtr != TargetPointer.Null) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + hr = (ccwPtr != TargetPointer.Null) ? HResults.S_OK : HResults.S_FALSE; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl10 is not null) + { + Interop.BOOL isComWrappersCCWLocal; + int hrLocal = _legacyImpl10.IsComWrappersCCW(ccw, &isComWrappersCCWLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK || hr == HResults.S_FALSE) + { + Debug.Assert(*isComWrappersCCW == isComWrappersCCWLocal); + } + } +#endif + return hr; + } int ISOSDacInterface10.GetComWrappersCCWData(ClrDataAddress ccw, ClrDataAddress* managedObject, int* refCount) - => _legacyImpl10 is not null ? _legacyImpl10.GetComWrappersCCWData(ccw, managedObject, refCount) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + if (ccw == 0) + throw new ArgumentException(); + TargetPointer ccwPtr = ccw.ToTargetPointer(_target); + Contracts.IComWrappers comWrappersContract = _target.Contracts.ComWrappers; + TargetPointer managedObjectPtr = comWrappersContract.GetManagedObjectWrapperFromCCW(ccwPtr); + if (managedObjectPtr == TargetPointer.Null) + throw new ArgumentException(); + + if (managedObject != null) + *managedObject = comWrappersContract.GetComWrappersObjectFromMOW(managedObjectPtr).ToClrDataAddress(_target); + + if (refCount != null) + *refCount = (int)comWrappersContract.GetMOWReferenceCount(managedObjectPtr); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl10 is not null) + { + ClrDataAddress managedObjectLocal; + int refCountLocal; + int hrLocal = _legacyImpl10.GetComWrappersCCWData(ccw, &managedObjectLocal, &refCountLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK) + { + if (managedObject != null) + Debug.Assert(*managedObject == managedObjectLocal); + if (refCount != null) + Debug.Assert(*refCount == refCountLocal); + } + } +#endif + return hr; + } int ISOSDacInterface10.IsComWrappersRCW(ClrDataAddress rcw, Interop.BOOL* isComWrappersRCW) - => _legacyImpl10 is not null ? _legacyImpl10.IsComWrappersRCW(rcw, isComWrappersRCW) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + ulong rcwMask = 1UL; + Contracts.IComWrappers comWrappersContract = _target.Contracts.ComWrappers; + if (rcw == 0) + throw new ArgumentException(); + else if (isComWrappersRCW != null) + { + if ((rcw & rcwMask) == 0) + *isComWrappersRCW = Interop.BOOL.FALSE; + else + { + TargetPointer rcwPtr = rcw.ToTargetPointer(_target) & ~rcwMask; + *isComWrappersRCW = comWrappersContract.IsComWrappersRCW(rcwPtr) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + hr = (*isComWrappersRCW != Interop.BOOL.FALSE) ? HResults.S_OK : HResults.S_FALSE; + } + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl10 is not null) + { + Interop.BOOL isComWrappersRCWLocal; + int hrLocal = _legacyImpl10.IsComWrappersRCW(rcw, &isComWrappersRCWLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK || hr == HResults.S_FALSE) + { + Debug.Assert(*isComWrappersRCW == isComWrappersRCWLocal); + } + } +#endif + return hr; + } int ISOSDacInterface10.GetComWrappersRCWData(ClrDataAddress rcw, ClrDataAddress* identity) { int hr = HResults.S_OK; diff --git a/src/tests/profiler/rejit/rejit.cs b/src/tests/profiler/rejit/rejit.cs index fc69720d270786..a5fb64bbe531c0 100644 --- a/src/tests/profiler/rejit/rejit.cs +++ b/src/tests/profiler/rejit/rejit.cs @@ -36,6 +36,8 @@ private static int MaxInlining() TriggerDirectInlining(); CallMethodWithoutInlining(); TriggerInliningChain(); + Console.Write("helloo"); + Console.ReadKey(); string matchString = "Hello from profiler rejit method 'InlineeTarget'!"; int numRejittedTargets = OutputBuilder.ToString().Split(matchString).Length; From 8a54a7a97a1bb86c78a9ac9ed6571785a8e6fa28 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 25 Sep 2025 12:01:10 -0700 Subject: [PATCH 02/23] adding simple comwrappers cDAC APIs --- docs/design/datacontracts/ComWrappers.md | 72 +++++++++++++++++++ docs/design/datacontracts/SignatureDecoder.md | 2 +- src/coreclr/debug/daccess/request.cpp | 6 -- src/coreclr/interop/inc/interoplibabi.h | 2 +- src/coreclr/vm/appdomain.cpp | 5 ++ .../vm/datadescriptor/datadescriptor.inc | 3 +- .../Contracts/IRuntimeTypeSystem.cs | 2 +- .../Constants.cs | 1 + .../Contracts/ComWrappers_1.cs | 7 +- .../Contracts/RuntimeTypeSystem_1.cs | 4 +- .../Signature/SignatureTypeProvider.cs | 2 +- .../Legacy/SOSDacImpl.cs | 13 ++-- src/tests/profiler/rejit/rejit.cs | 2 - 13 files changed, 96 insertions(+), 25 deletions(-) diff --git a/docs/design/datacontracts/ComWrappers.md b/docs/design/datacontracts/ComWrappers.md index 73c3bcd9930728..5e3a4e4194b9e6 100644 --- a/docs/design/datacontracts/ComWrappers.md +++ b/docs/design/datacontracts/ComWrappers.md @@ -7,6 +7,14 @@ This contract is for getting information related to COM wrappers. ``` csharp // Get the address of the external COM object TargetPointer GetComWrappersIdentity(TargetPointer rcw); +// Given a ccw pointer, return the managed object wrapper +public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw); +// Given a managed object wrapper, return the comwrappers pointer +public TargetPointer GetComWrappersObjectFromMOW(TargetPointer mow); +// Given a managed object wrapper, return its reference count +public long GetMOWReferenceCount(TargetPointer mow); +// Determine if a pointer represents a ComWrappers RCW +public bool IsComWrappersRCW(TargetPointer rcw); ``` ## Version 1 @@ -15,14 +23,22 @@ Data descriptors used: | Data Descriptor Name | Field | Meaning | | --- | --- | --- | | `NativeObjectWrapperObject` | `ExternalComObject` | Address of the external COM object | +| `ManagedObjectWrapperHolderObject` | `WrappedObject` | Address of the wrapped object | +| `ManagedObjectWrapperLayout` | `RefCount` | Reference count of the managed object wrapper | Global variables used: | Global Name | Type | Purpose | | --- | --- | --- | +| `MOWQueryInterface` | TargetPointer | Code address of ManagedObjectWrapper_QueryInterface | +| `TrackerTargetQueryInterface` | TargetPointer | Code address of TrackerTarget_QueryInterface | +| `DispatchThisPtrMask` | TargetPointer | Used to mask low bits of CCW pointer to the nearest valid address from which to read a managed object wrapper | +| `NativeObjectWrapperClass` | ushort | The index of the native object wrapper class into the CoreLibBinder classes | Contracts used: | Contract Name | | --- | +| `Object` | +| `RuntimeTypeSystem` | ``` csharp @@ -30,4 +46,60 @@ public TargetPointer GetComWrappersIdentity(TargetPointer address) { return _target.ReadPointer(address + /* NativeObjectWrapperObject::ExternalComObject offset */); } + +private bool GetComWrappersCCWVTableQIAddress(TargetPointer ccw, out TargetPointer vtable, out TargetPointer qiAddress) +{ + vtable = TargetPointer.Null; + qiAddress = TargetPointer.Null; + try + { + // read two levels of indirection from the ccw to get the code pointer + } + catch (VirtualReadException) + { + return false; + } + qiAddress = CodePointerUtils.AddressFromCodePointer(qiAddress.Value, _target); + return true; +} + +private bool IsComWrappersCCW(TargetPointer ccw) +{ + if (!GetComWrappersCCWVTableQIAddress(ccw, out _, out TargetPointer qiAddress)) + return false; + + return qiAddress == _target.ReadGlobalPointer("MOWQueryInterface") || + qiAddress == _target.ReadGlobalPointer("TrackerTargetQueryInterface"); +} + +public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) +{ + if (!IsComWrappersCCW(ccw)) + return TargetPointer.Null; + try + { + return _target.ReadPointer(ccw & _target.ReadGlobalPointer("DispatchThisPtrMask")); + } + catch (VirtualReadException) + { + return TargetPointer.Null; + } +} + +public TargetPointer GetComWrappersObjectFromMOW(TargetPointer mow) +{ + TargetPointer mowHolderObject = /* read two layers of indirection from MOW */; + return mowHolderObject + /* ManagedObjectWrapperHolderObject::WrappedObject offset */; +} + +public long GetMOWReferenceCount(TargetPointer mow) +{ + return target.Read(mow + /* ManagedObjectWrapperLayout::RefCount offset */); +} + +public bool IsComWrappersRCW(TargetPointer rcw) +{ + // get method table from rcw using Object contract GetMethodTableAddress + // and ensure it matches the MT of NativeObjectWrapperClass in the CoreLibBinder with RuntimeTypeSystem.GetBinderType +} ``` diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md index 08f41f49917dd3..93544b4064cc8d 100644 --- a/docs/design/datacontracts/SignatureDecoder.md +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -34,7 +34,7 @@ The cDAC implements the ISignatureTypeProvider with TType A cDAC SignatureTypeProvider is instantiated over a Module which is used to lookup types. -The following ISignatureTypeProvider APIs are trivially implemented using RuntimeTypeSystem.GetPrimitiveType and RuntimeTypeSystem.GetConstructedType: +The following ISignatureTypeProvider APIs are trivially implemented using RuntimeTypeSystem.GetBinderType and RuntimeTypeSystem.GetConstructedType: * GetArrayType - GetConstructedType * GetByReferenceType - GetConstructedType diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index b20be8fd8eca41..960b6af22f3dc5 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -4346,12 +4346,6 @@ BOOL ClrDataAccess::DACGetComWrappersCCWVTableQIAddress(CLRDATA_ADDRESS ccwPtr, return FALSE; } - -#ifdef TARGET_ARM - // clear the THUMB bit on qiAddress before comparing with known vtable entry - *qiAddress &= ~THUMB_CODE; -#endif - return TRUE; } diff --git a/src/coreclr/interop/inc/interoplibabi.h b/src/coreclr/interop/inc/interoplibabi.h index c8ad0deb4f9b01..5520d212fe02d3 100644 --- a/src/coreclr/interop/inc/interoplibabi.h +++ b/src/coreclr/interop/inc/interoplibabi.h @@ -23,7 +23,7 @@ namespace InteropLib constexpr size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2. #endif - constexpr uintptr_t DispatchThisPtrMask = ~(static_cast((DispatchAlignmentThisPtr) - 1u)); + constexpr intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1); static_assert(sizeof(void*) < DispatchAlignmentThisPtr, "DispatchAlignmentThisPtr must be larger than sizeof(void*)."); diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 7b247b2b8bfd02..af10a77bbf7d9c 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1078,6 +1078,11 @@ void SystemDomain::LoadBaseSystemClasses() CoreLibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC); CoreLibBinder::GetClass(CLASS__IREADONLYLISTGENERIC); + // cache the method table here for cDAC IsComWrappersRCW + #ifdef FEATURE_COMWRAPPERS + CoreLibBinder::GetClass(CLASS__NATIVE_OBJECT_WRAPPER); + #endif + // Load String g_pStringClass = CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING); diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index fb699b48058da8..9cf566adb3fab8 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1036,7 +1036,8 @@ CDAC_GLOBAL_POINTER(DacNotificationFlags, &::g_dacNotificationFlags) CDAC_GLOBAL_POINTER(OffsetOfCurrentThreadInfo, &::g_offsetOfCurrentThreadInfo) CDAC_GLOBAL_POINTER(ThinlockThreadIdDispenser, &::g_pThinLockThreadIdDispenser) #ifdef FEATURE_COMWRAPPERS -CDAC_GLOBAL(DispatchThisPtrMask, uintptr_t, InteropLib::ABI::DispatchThisPtrMask) +CDAC_GLOBAL(DispatchThisPtrMask, intptr_t, InteropLib::ABI::DispatchThisPtrMask) +CDAC_GLOBAL(NativeObjectWrapperClass, uint32, CLASS__NATIVE_OBJECT_WRAPPER) CDAC_GLOBAL_POINTER(MOWQueryInterface, &ManagedObjectWrapper_QueryInterface) CDAC_GLOBAL_POINTER(TrackerTargetQueryInterface, &TrackerTarget_QueryInterface) #endif // FEATURE_COMWRAPPERS diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index cebe10538db5a4..b061183526c8a3 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -142,7 +142,7 @@ public interface IRuntimeTypeSystem : IContract bool IsArray(TypeHandle typeHandle, out uint rank) => throw new NotImplementedException(); TypeHandle GetTypeParam(TypeHandle typeHandle) => throw new NotImplementedException(); TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) => throw new NotImplementedException(); - TypeHandle GetPrimitiveType(CorElementType typeCode) => throw new NotImplementedException(); + TypeHandle GetBinderType(ushort typeCode) => throw new NotImplementedException(); bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) => throw new NotImplementedException(); bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv) => throw new NotImplementedException(); bool IsPointer(TypeHandle typeHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index b81a39f3887c17..9bb1513f414d75 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -33,6 +33,7 @@ public static class Globals public const string TlsIndexBase = nameof(TlsIndexBase); public const string ThinlockThreadIdDispenser = nameof(ThinlockThreadIdDispenser); public const string DispatchThisPtrMask = nameof(DispatchThisPtrMask); + public const string NativeObjectWrapperClass = nameof(NativeObjectWrapperClass); public const string MOWQueryInterface = nameof(MOWQueryInterface); public const string TrackerTargetQueryInterface = nameof(TrackerTargetQueryInterface); 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 f3e3894f5b1c75..c1eb7378ccf6cd 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 @@ -83,8 +83,9 @@ public long GetMOWReferenceCount(TargetPointer mow) public bool IsComWrappersRCW(TargetPointer rcw) { - Contracts.IObject objContract = _target.Contracts.Object; - TargetPointer mt = objContract.GetMethodTableAddress(rcw); - return mt != TargetPointer.Null; + TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(rcw); + ushort typeCode = _target.ReadGlobal(Constants.Globals.NativeObjectWrapperClass); + TargetPointer typeHandlePtr = _target.Contracts.RuntimeTypeSystem.GetBinderType(typeCode).Address; + return mt == typeHandlePtr; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index c5b011aaeae35b..51f6573a070f40 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -793,11 +793,11 @@ TypeHandle IRuntimeTypeSystem.GetConstructedType(TypeHandle typeHandle, CorEleme return new TypeHandle(TargetPointer.Null); } - TypeHandle IRuntimeTypeSystem.GetPrimitiveType(CorElementType typeCode) + TypeHandle IRuntimeTypeSystem.GetBinderType(ushort typeCode) { TargetPointer coreLib = _target.ReadGlobalPointer(Constants.Globals.CoreLib); CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); - TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + (ulong)typeCode * (ulong)_target.PointerSize); + TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + typeCode * (ulong)_target.PointerSize); return GetTypeHandle(typeHandlePtr); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs index 82672504975f49..67a8ca35c94271 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -66,7 +66,7 @@ public TypeHandle GetPointerType(TypeHandle elementType) => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Ptr, 0, []); public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) - => _runtimeTypeSystem.GetPrimitiveType((CorElementType)typeCode); + => _runtimeTypeSystem.GetBinderType((ushort)typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, []); diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 3837ffd30c9b47..72c999843f3f12 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -41,6 +41,7 @@ internal sealed unsafe partial class SOSDacImpl // They should be set when actually requested via other DAC APIs, so we lazily read the global pointers. private readonly Lazy _stringMethodTable; private readonly Lazy _objectMethodTable; + private readonly ulong _rcwMask = 1UL; private readonly ISOSDacInterface? _legacyImpl; private readonly ISOSDacInterface2? _legacyImpl2; @@ -792,7 +793,7 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat // In the future we may want to return a TypeHandle instead of a MethodTable, and modify SOS to do more complete pretty-printing. // DAC equivalent: src/coreclr/vm/typehandle.inl TypeHandle::GetMethodTable if (rtsContract.IsFunctionPointer(foundTypeHandle, out _, out _) || rtsContract.IsPointer(foundTypeHandle)) - data->MTOfType = rtsContract.GetPrimitiveType(CorElementType.U).Address.ToClrDataAddress(_target); + data->MTOfType = rtsContract.GetBinderType((ushort)CorElementType.U).Address.ToClrDataAddress(_target); // array MTs else if (rtsContract.IsArray(foundTypeHandle, out _)) data->MTOfType = foundTypeHandle.Address.ToClrDataAddress(_target); @@ -4005,17 +4006,16 @@ int ISOSDacInterface10.IsComWrappersRCW(ClrDataAddress rcw, Interop.BOOL* isComW int hr = HResults.S_OK; try { - ulong rcwMask = 1UL; Contracts.IComWrappers comWrappersContract = _target.Contracts.ComWrappers; if (rcw == 0) throw new ArgumentException(); else if (isComWrappersRCW != null) { - if ((rcw & rcwMask) == 0) + if ((rcw & _rcwMask) == 0) *isComWrappersRCW = Interop.BOOL.FALSE; else { - TargetPointer rcwPtr = rcw.ToTargetPointer(_target) & ~rcwMask; + TargetPointer rcwPtr = rcw.ToTargetPointer(_target) & ~_rcwMask; *isComWrappersRCW = comWrappersContract.IsComWrappersRCW(rcwPtr) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; hr = (*isComWrappersRCW != Interop.BOOL.FALSE) ? HResults.S_OK : HResults.S_FALSE; } @@ -4044,15 +4044,14 @@ int ISOSDacInterface10.GetComWrappersRCWData(ClrDataAddress rcw, ClrDataAddress* int hr = HResults.S_OK; try { - ulong rcwMask = 1UL; Contracts.IComWrappers comWrappersContract = _target.Contracts.ComWrappers; if (rcw == 0 || identity == null) throw new ArgumentException(); - else if ((rcw & rcwMask) == 0) + else if ((rcw & _rcwMask) == 0) *identity = 0; else if (identity != null) { - TargetPointer identityPtr = comWrappersContract.GetComWrappersIdentity((rcw.ToTargetPointer(_target) & ~rcwMask)); + TargetPointer identityPtr = comWrappersContract.GetComWrappersIdentity(rcw.ToTargetPointer(_target) & ~_rcwMask); *identity = identityPtr.ToClrDataAddress(_target); } } diff --git a/src/tests/profiler/rejit/rejit.cs b/src/tests/profiler/rejit/rejit.cs index a5fb64bbe531c0..fc69720d270786 100644 --- a/src/tests/profiler/rejit/rejit.cs +++ b/src/tests/profiler/rejit/rejit.cs @@ -36,8 +36,6 @@ private static int MaxInlining() TriggerDirectInlining(); CallMethodWithoutInlining(); TriggerInliningChain(); - Console.Write("helloo"); - Console.ReadKey(); string matchString = "Hello from profiler rejit method 'InlineeTarget'!"; int numRejittedTargets = OutputBuilder.ToString().Split(matchString).Length; From 1a145d9a1b23f20047f3d31cf114a877811aa379 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 25 Sep 2025 15:00:23 -0700 Subject: [PATCH 03/23] uint --- src/coreclr/interop/inc/interoplibabi.h | 2 +- src/coreclr/vm/datadescriptor/datadescriptor.inc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/interop/inc/interoplibabi.h b/src/coreclr/interop/inc/interoplibabi.h index 5520d212fe02d3..bf066c92a47b50 100644 --- a/src/coreclr/interop/inc/interoplibabi.h +++ b/src/coreclr/interop/inc/interoplibabi.h @@ -23,7 +23,7 @@ namespace InteropLib constexpr size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2. #endif - constexpr intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1); + constexpr uintptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1u); static_assert(sizeof(void*) < DispatchAlignmentThisPtr, "DispatchAlignmentThisPtr must be larger than sizeof(void*)."); diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 9cf566adb3fab8..e2392be2806a18 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1036,7 +1036,7 @@ CDAC_GLOBAL_POINTER(DacNotificationFlags, &::g_dacNotificationFlags) CDAC_GLOBAL_POINTER(OffsetOfCurrentThreadInfo, &::g_offsetOfCurrentThreadInfo) CDAC_GLOBAL_POINTER(ThinlockThreadIdDispenser, &::g_pThinLockThreadIdDispenser) #ifdef FEATURE_COMWRAPPERS -CDAC_GLOBAL(DispatchThisPtrMask, intptr_t, InteropLib::ABI::DispatchThisPtrMask) +CDAC_GLOBAL(DispatchThisPtrMask, uintptr_t, InteropLib::ABI::DispatchThisPtrMask) CDAC_GLOBAL(NativeObjectWrapperClass, uint32, CLASS__NATIVE_OBJECT_WRAPPER) CDAC_GLOBAL_POINTER(MOWQueryInterface, &ManagedObjectWrapper_QueryInterface) CDAC_GLOBAL_POINTER(TrackerTargetQueryInterface, &TrackerTarget_QueryInterface) From 82361c3ae81cd1179bcd5ae425a3e85097397a6d Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 26 Sep 2025 13:21:46 -0700 Subject: [PATCH 04/23] fixing function pointer cast --- docs/design/datacontracts/ComWrappers.md | 5 +++-- src/coreclr/interop/comwrappers.hpp | 10 +++++++++ .../vm/datadescriptor/datadescriptor.inc | 10 +++++++-- .../DataType.cs | 1 + .../Constants.cs | 3 +-- .../Contracts/ComWrappers_1.cs | 6 ++++-- .../Data/ComWrappersVtablePtrs.cs | 21 +++++++++++++++++++ 7 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs diff --git a/docs/design/datacontracts/ComWrappers.md b/docs/design/datacontracts/ComWrappers.md index 5e3a4e4194b9e6..808c2fc56db674 100644 --- a/docs/design/datacontracts/ComWrappers.md +++ b/docs/design/datacontracts/ComWrappers.md @@ -25,12 +25,13 @@ Data descriptors used: | `NativeObjectWrapperObject` | `ExternalComObject` | Address of the external COM object | | `ManagedObjectWrapperHolderObject` | `WrappedObject` | Address of the wrapped object | | `ManagedObjectWrapperLayout` | `RefCount` | Reference count of the managed object wrapper | +| `ComWrappersVtablePtrs` | `MowQueryInterface` | Function pointer of ManagedObjectWrapper_QueryInterface | +| `ComWrappersVtablePtrs` | `TtQueryInterface` | Function pointer of TrackerTarget_QueryInterface | Global variables used: | Global Name | Type | Purpose | | --- | --- | --- | -| `MOWQueryInterface` | TargetPointer | Code address of ManagedObjectWrapper_QueryInterface | -| `TrackerTargetQueryInterface` | TargetPointer | Code address of TrackerTarget_QueryInterface | +| `ComWrappersVtablePtrs` | TargetPointer | Pointer to struct containing ComWrappers-related function pointers | | `DispatchThisPtrMask` | TargetPointer | Used to mask low bits of CCW pointer to the nearest valid address from which to read a managed object wrapper | | `NativeObjectWrapperClass` | ushort | The index of the native object wrapper class into the CoreLibBinder classes | diff --git a/src/coreclr/interop/comwrappers.hpp b/src/coreclr/interop/comwrappers.hpp index 75fa058dcd407a..4964130d6e0adc 100644 --- a/src/coreclr/interop/comwrappers.hpp +++ b/src/coreclr/interop/comwrappers.hpp @@ -187,4 +187,14 @@ HRESULT STDMETHODCALLTYPE TrackerTarget_QueryInterface( /* [in] */ REFIID riid, /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject); +const struct ComWrappersVtablePtrs +{ + decltype(&ManagedObjectWrapper_QueryInterface) MowQueryInterface; + decltype(&TrackerTarget_QueryInterface) TtQueryInterface; +}; + +const ComWrappersVtablePtrs g_ComWrappersVtablePtrs = { + &ManagedObjectWrapper_QueryInterface, + &TrackerTarget_QueryInterface +}; #endif // _INTEROP_COMWRAPPERS_HPP_ diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index e2392be2806a18..8f570d218afd68 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -943,6 +943,13 @@ CDAC_TYPE_FIELD(DynamicILBlobTable, /*uint32*/, EntryMethodToken, cdac_data::EntryIL) CDAC_TYPE_END(DynamicILBlobTable) +#ifdef FEATURE_COMWRAPPERS +CDAC_TYPE_BEGIN(ComWrappersVtablePtrs) +CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, MowQueryInterface, offsetof(ComWrappersVtablePtrs, MowQueryInterface)) +CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, TtQueryInterface, offsetof(ComWrappersVtablePtrs, TtQueryInterface)) +CDAC_TYPE_END(ComWrappersVtablePtrs) +#endif + CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() @@ -1038,8 +1045,7 @@ CDAC_GLOBAL_POINTER(ThinlockThreadIdDispenser, &::g_pThinLockThreadIdDispenser) #ifdef FEATURE_COMWRAPPERS CDAC_GLOBAL(DispatchThisPtrMask, uintptr_t, InteropLib::ABI::DispatchThisPtrMask) CDAC_GLOBAL(NativeObjectWrapperClass, uint32, CLASS__NATIVE_OBJECT_WRAPPER) -CDAC_GLOBAL_POINTER(MOWQueryInterface, &ManagedObjectWrapper_QueryInterface) -CDAC_GLOBAL_POINTER(TrackerTargetQueryInterface, &TrackerTarget_QueryInterface) +CDAC_GLOBAL_POINTER(ComWrappersVtablePtrs, &g_ComWrappersVtablePtrs) #endif // FEATURE_COMWRAPPERS CDAC_GLOBAL_POINTER(CoreLib, &::g_CoreLib) #ifdef TARGET_WINDOWS diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index ed7a74be3aa394..6be64a591afb9d 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -71,6 +71,7 @@ public enum DataType NativeObjectWrapperObject, ManagedObjectWrapperHolderObject, ManagedObjectWrapperLayout, + ComWrappersVtablePtrs, String, MethodDesc, MethodDescChunk, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index 9bb1513f414d75..94e7f3d0934753 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -34,8 +34,7 @@ public static class Globals public const string ThinlockThreadIdDispenser = nameof(ThinlockThreadIdDispenser); public const string DispatchThisPtrMask = nameof(DispatchThisPtrMask); public const string NativeObjectWrapperClass = nameof(NativeObjectWrapperClass); - public const string MOWQueryInterface = nameof(MOWQueryInterface); - public const string TrackerTargetQueryInterface = nameof(TrackerTargetQueryInterface); + public const string ComWrappersVtablePtrs = nameof(ComWrappersVtablePtrs); public const string StressLogEnabled = nameof(StressLogEnabled); public const string StressLogHasModuleTable = nameof(StressLogHasModuleTable); 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 c1eb7378ccf6cd..682ad17325c4c9 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 @@ -49,8 +49,10 @@ private bool IsComWrappersCCW(TargetPointer ccw) if (!GetComWrappersCCWVTableQIAddress(ccw, out _, out TargetPointer qiAddress)) return false; - return qiAddress == _target.ReadGlobalPointer(Constants.Globals.MOWQueryInterface) || - qiAddress == _target.ReadGlobalPointer(Constants.Globals.TrackerTargetQueryInterface); + TargetPointer comWrappersVtablePtrs = _target.ReadGlobalPointer(Constants.Globals.ComWrappersVtablePtrs); + Data.ComWrappersVtablePtrs comWrappersVtableStruct = _target.ProcessedData.GetOrAdd(comWrappersVtablePtrs); + return qiAddress == comWrappersVtableStruct.MowQueryInterface || + qiAddress == comWrappersVtableStruct.TtQueryInterface; } public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs new file mode 100644 index 00000000000000..61bb6f5f1ed26d --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class ComWrappersVtablePtrs : IData +{ + static ComWrappersVtablePtrs IData.Create(Target target, TargetPointer address) => new ComWrappersVtablePtrs(target, address); + public ComWrappersVtablePtrs(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ComWrappersVtablePtrs); + + MowQueryInterface = target.ReadPointer(address + (ulong)type.Fields[nameof(MowQueryInterface)].Offset); + TtQueryInterface = target.ReadPointer(address + (ulong)type.Fields[nameof(TtQueryInterface)].Offset); + } + + public TargetPointer MowQueryInterface { get; init; } + public TargetPointer TtQueryInterface { get; init; } +} From 8439a7dac6ac5926a5ab73fe0b987e9adbf9ee68 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 26 Sep 2025 13:47:19 -0700 Subject: [PATCH 05/23] e --- src/coreclr/interop/comwrappers.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/interop/comwrappers.hpp b/src/coreclr/interop/comwrappers.hpp index 4964130d6e0adc..3cfb0722a57bfd 100644 --- a/src/coreclr/interop/comwrappers.hpp +++ b/src/coreclr/interop/comwrappers.hpp @@ -187,7 +187,7 @@ HRESULT STDMETHODCALLTYPE TrackerTarget_QueryInterface( /* [in] */ REFIID riid, /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject); -const struct ComWrappersVtablePtrs +struct ComWrappersVtablePtrs { decltype(&ManagedObjectWrapper_QueryInterface) MowQueryInterface; decltype(&TrackerTarget_QueryInterface) TtQueryInterface; From 759f27f79bb8722b0fac7e42e703f053170c79ef Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 26 Sep 2025 16:39:27 -0700 Subject: [PATCH 06/23] code review --- docs/design/datacontracts/ComWrappers.md | 19 ++++++------- src/coreclr/debug/daccess/request.cpp | 10 +++++-- .../Target.cs | 16 +++++++++++ .../Contracts/ComWrappers_1.cs | 27 +++++-------------- .../ContractDescriptorTarget.cs | 26 ++++++++++++++++++ .../cdac/tests/TestPlaceholderTarget.cs | 9 +++++++ 6 files changed, 73 insertions(+), 34 deletions(-) diff --git a/docs/design/datacontracts/ComWrappers.md b/docs/design/datacontracts/ComWrappers.md index 808c2fc56db674..9d7d87cc558817 100644 --- a/docs/design/datacontracts/ComWrappers.md +++ b/docs/design/datacontracts/ComWrappers.md @@ -52,15 +52,11 @@ private bool GetComWrappersCCWVTableQIAddress(TargetPointer ccw, out TargetPoint { vtable = TargetPointer.Null; qiAddress = TargetPointer.Null; - try - { - // read two levels of indirection from the ccw to get the code pointer - } - catch (VirtualReadException) - { - return false; - } - qiAddress = CodePointerUtils.AddressFromCodePointer(qiAddress.Value, _target); + + // read two levels of indirection from the ccw to get the code pointer into qiAddress + // if read fails, return false + + qiAddress = CodePointerUtils.AddressFromCodePointer(qiAddress, _target); return true; } @@ -69,8 +65,9 @@ private bool IsComWrappersCCW(TargetPointer ccw) if (!GetComWrappersCCWVTableQIAddress(ccw, out _, out TargetPointer qiAddress)) return false; - return qiAddress == _target.ReadGlobalPointer("MOWQueryInterface") || - qiAddress == _target.ReadGlobalPointer("TrackerTargetQueryInterface"); + TargetPointer comWrappersVtablePtrs = _target.ReadGlobalPointer("ComWrappersVtablePtrs"); + + return /* qiAddress matches either entry in ComWrappersVtablePtrs */ ; } public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 960b6af22f3dc5..975796e101594e 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -4346,6 +4346,12 @@ BOOL ClrDataAccess::DACGetComWrappersCCWVTableQIAddress(CLRDATA_ADDRESS ccwPtr, return FALSE; } + +#ifdef TARGET_ARM + // clear the THUMB bit on qiAddress before comparing with known vtable entry + *qiAddress &= ~THUMB_CODE; +#endif + return TRUE; } @@ -4358,8 +4364,8 @@ BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr) return FALSE; } - return (qiAddress == GetEEFuncEntryPoint(ManagedObjectWrapper_QueryInterface) - || qiAddress == GetEEFuncEntryPoint(TrackerTarget_QueryInterface)); + return (qiAddress == GFN_TADDR(ManagedObjectWrapper_QueryInterface) + || qiAddress == GFN_TADDR(TrackerTarget_QueryInterface)); } TADDR ClrDataAccess::DACGetManagedObjectWrapperFromCCW(CLRDATA_ADDRESS ccwPtr) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs index e6bb21976d84b3..850aab0f488320 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs @@ -59,6 +59,14 @@ public abstract class Target /// Thrown when the read operation fails public abstract TargetPointer ReadPointer(ulong address); + /// + /// Read a pointer from the target in target endianness + /// + /// Address to start reading from + /// Pointer read from the target + /// True if read succeeds, false otherwise. + public abstract bool TryReadPointer(ulong address, out TargetPointer value); + /// /// Read a code pointer from the target in target endianness /// @@ -67,6 +75,14 @@ public abstract class Target /// Thrown when the read operation fails public abstract TargetCodePointer ReadCodePointer(ulong address); + /// + /// Read a code pointer from the target in target endianness + /// + /// Address to start reading from + /// Pointer read from the target + /// True if read succeeds, false otherwise. + public abstract bool TryReadCodePointer(ulong address, out TargetCodePointer value); + /// /// Read some bytes from the target /// 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 682ad17325c4c9..c159333b28d074 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 @@ -25,22 +25,12 @@ public TargetPointer GetComWrappersIdentity(TargetPointer address) private bool GetComWrappersCCWVTableQIAddress(TargetPointer ccw, out TargetPointer vtable, out TargetPointer qiAddress) { - vtable = TargetPointer.Null; qiAddress = TargetPointer.Null; - try - { - TargetPointer vtableAddress = _target.ReadPointer(ccw); - if (vtableAddress == TargetPointer.Null) - return false; - qiAddress = _target.ReadPointer(vtableAddress); - if (qiAddress == TargetPointer.Null) - return false; - } - catch (VirtualReadException) - { + if (!_target.TryReadPointer(ccw, out vtable)) return false; - } - qiAddress = CodePointerUtils.AddressFromCodePointer(qiAddress.Value, _target); + if (!_target.TryReadCodePointer(vtable, out TargetCodePointer qiCodePtr)) + return false; + qiAddress = CodePointerUtils.AddressFromCodePointer(qiCodePtr, _target); return true; } @@ -59,14 +49,9 @@ public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) { if (!IsComWrappersCCW(ccw)) return TargetPointer.Null; - try - { - return _target.ReadPointer(ccw & _target.ReadGlobalPointer(Constants.Globals.DispatchThisPtrMask)); - } - catch (VirtualReadException) - { + if (!_target.TryReadPointer(ccw & _target.ReadGlobalPointer(Constants.Globals.DispatchThisPtrMask), out TargetPointer MOWWrapper)) return TargetPointer.Null; - } + return MOWWrapper; } public TargetPointer GetComWrappersObjectFromMOW(TargetPointer mow) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs index bec5c1cb7dc3f1..0275eba1f54df8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs @@ -522,6 +522,9 @@ public override TargetPointer ReadPointer(ulong address) return pointer; } + public override bool TryReadPointer(ulong address, out TargetPointer value) + => TryReadPointer(address, _config, _dataTargetDelegates, out value); + public override TargetPointer ReadPointerFromSpan(ReadOnlySpan bytes) { if (_config.PointerSize == sizeof(uint)) @@ -548,6 +551,29 @@ public override TargetCodePointer ReadCodePointer(ulong address) throw new VirtualReadException($"Failed to read code pointer at 0x{address:x8} because CodePointer size is not 4 or 8"); } + public override bool TryReadCodePointer(ulong address, out TargetCodePointer value) + { + TypeInfo codePointerTypeInfo = GetTypeInfo(DataType.CodePointer); + if (codePointerTypeInfo.Size is sizeof(uint)) + { + if (TryRead(address, out uint val)) + { + value = new TargetCodePointer(val); + return true; + } + } + else if (codePointerTypeInfo.Size is sizeof(ulong)) + { + if (TryRead(address, out ulong val)) + { + value = new TargetCodePointer(val); + return true; + } + } + value = default; + return false; + } + public void ReadPointers(ulong address, Span buffer) { // TODO(cdac) - This could do a single read, and then swizzle in place if it is useful for performance diff --git a/src/native/managed/cdac/tests/TestPlaceholderTarget.cs b/src/native/managed/cdac/tests/TestPlaceholderTarget.cs index 289873f6222ca2..f503c9eeb5adc1 100644 --- a/src/native/managed/cdac/tests/TestPlaceholderTarget.cs +++ b/src/native/managed/cdac/tests/TestPlaceholderTarget.cs @@ -77,7 +77,16 @@ public override TargetPointer ReadGlobalPointer(string name) } public override TargetPointer ReadPointer(ulong address) => DefaultReadPointer(address); + public override bool TryReadPointer(ulong address, out TargetPointer value) => DefaultTryReadPointer(address, out value); public override TargetCodePointer ReadCodePointer(ulong address) => DefaultReadCodePointer(address); + public override bool TryReadCodePointer(ulong address, out TargetCodePointer value) + { + value = default; + if (!DefaultTryReadPointer(address, out TargetPointer ptr)) + return false; + value = new TargetCodePointer(ptr); + return true; + } public override void ReadBuffer(ulong address, Span buffer) { if (_dataReader(address, buffer) < 0) From 45d66bc8631bf98a786350065fb246932502e887 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 2 Oct 2025 08:15:15 -0700 Subject: [PATCH 07/23] e --- .../Contracts/RuntimeTypeSystem_1.cs | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 51f6573a070f40..bba50e8ee2a812 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -9,6 +9,7 @@ using Microsoft.Diagnostics.DataContractReader.Data; using System.Reflection.Metadata; using System.Collections.Immutable; +using System.Reflection; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -801,6 +802,106 @@ TypeHandle IRuntimeTypeSystem.GetBinderType(ushort typeCode) return GetTypeHandle(typeHandlePtr); } + private static bool ModuleMatch(AssemblyReference assemblyRef, AssemblyDefinition assemblyDef) + { + AssemblyName assemblyRefName = assemblyRef.GetAssemblyName(); + AssemblyName assemblyDefName = assemblyDef.GetAssemblyName(); + return ((assemblyRefName.Name == assemblyDefName.Name) && + (assemblyRefName.Version == assemblyDefName.Version) && + (assemblyRefName.CultureName == assemblyDefName.CultureName)); + } + + private MetadataReader? LookForHandle(AssemblyReference exportedAssemblyRef) + { + foreach (ModuleHandle mdhandle in _target.Contracts.Loader.GetModuleHandles(TargetPointer.Null, AssemblyIterationFlags.IncludeLoaded)) + { + MetadataReader? md2 = _target.Contracts.EcmaMetadata.GetMetadata(mdhandle); + if (md2 == null) + continue; + AssemblyDefinition assemblyDefinition = md2.GetAssemblyDefinition(); + if (ModuleMatch(exportedAssemblyRef, assemblyDefinition)) + { + return md2; + } + } + return null; + } + + private TypeHandle LookupByName(string name, string nameSpace, ModuleHandle moduleHandle) + { + string[] parts = name.Split('+'); + MetadataReader? md = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle); + TypeDefinitionHandle currentHandle = default; + // create a hash set of MDs and if we come across the same one more than once in a loop then we return error + HashSet seenMDs = new(); + while (true) + { + if (md == null || !seenMDs.Add(md)) + return new TypeHandle(TargetPointer.Null); + // if our metadata is null or we have a cycle in type forwarding return null + + foreach (TypeDefinitionHandle typeDefHandle in md.TypeDefinitions) + { + TypeDefinition typedef = md.GetTypeDefinition(typeDefHandle); + if (md.GetString(typedef.Name) == parts[0] && md.GetString(typedef.Namespace) == nameSpace) + { + // found our outermost type, remember it + currentHandle = typeDefHandle; + break; + } + } + + if (currentHandle == default) + { + // look for forwarded types + foreach (ExportedTypeHandle exportedTypeHandle in md.ExportedTypes) + { + ExportedType exportedType = md.GetExportedType(exportedTypeHandle); + if (exportedType.Implementation.Kind != HandleKind.AssemblyReference || !exportedType.IsForwarder) + continue; + if (md.GetString(exportedType.Name) == parts[0] && md.GetString(exportedType.Namespace) == nameSpace) + { + // get the assembly ref for target + AssemblyReferenceHandle arefHandle = (AssemblyReferenceHandle)exportedType.Implementation; + AssemblyReference exportedAssemblyRef = md.GetAssemblyReference(arefHandle); + md = LookForHandle(exportedAssemblyRef); + if (md == null || !seenMDs.Add(md)) + return new TypeHandle(TargetPointer.Null); + break; + } + } + } + else break; + } + + // 2. Walk down the nested types + for (int i = 1; i < parts.Length; i++) + { + string nestedName = parts[i]; + bool found = false; + foreach (TypeDefinitionHandle nestedHandle in md.GetTypeDefinition(currentHandle).GetNestedTypes()) + { + TypeDefinition nestedDef = md.GetTypeDefinition(nestedHandle); + if (md.GetString(nestedDef.Name) == nestedName) + { + currentHandle = nestedHandle; + found = true; + break; + } + } + if (!found) + throw new NotImplementedException(); + } + + // 3. We have the handle, look up the type handle + int token = MetadataTokens.GetToken((EntityHandle)currentHandle); + ILoader loader = _target.Contracts.Loader; + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + TargetPointer typeDefToMethodTable = loader.GetLookupTables(moduleHandle).TypeDefToMethodTable; + TargetPointer typeHandlePtr = loader.GetModuleLookupMapElement(typeDefToMethodTable, (uint)token, out _); + return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : rts.GetTypeHandle(typeHandlePtr); + } + public bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) { module = TargetPointer.Null; From 4e1385cdb347f9a74df46cdcf9e292940a93eb22 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 2 Oct 2025 11:37:18 -0700 Subject: [PATCH 08/23] e --- docs/design/datacontracts/ComWrappers.md | 2 +- docs/design/datacontracts/SignatureDecoder.md | 2 +- src/coreclr/vm/appdomain.hpp | 1 + src/coreclr/vm/binder.h | 1 + .../vm/datadescriptor/datadescriptor.inc | 8 ++++ .../Contracts/ILoader.cs | 1 + .../Contracts/IRuntimeTypeSystem.cs | 4 +- .../DataType.cs | 1 + .../Contracts/ComWrappers_1.cs | 13 ++++- .../Contracts/Loader_1.cs | 7 +++ .../Contracts/RuntimeTypeSystem_1.cs | 48 ++++++++++++------- .../Signature/SignatureTypeProvider.cs | 2 +- .../Data/CoreLibBinder.cs | 2 + .../Data/SystemDomain.cs | 2 + .../Legacy/SOSDacImpl.cs | 2 +- 15 files changed, 72 insertions(+), 24 deletions(-) diff --git a/docs/design/datacontracts/ComWrappers.md b/docs/design/datacontracts/ComWrappers.md index 9d7d87cc558817..23eb0a2eda6b52 100644 --- a/docs/design/datacontracts/ComWrappers.md +++ b/docs/design/datacontracts/ComWrappers.md @@ -98,6 +98,6 @@ public long GetMOWReferenceCount(TargetPointer mow) public bool IsComWrappersRCW(TargetPointer rcw) { // get method table from rcw using Object contract GetMethodTableAddress - // and ensure it matches the MT of NativeObjectWrapperClass in the CoreLibBinder with RuntimeTypeSystem.GetBinderType + // and ensure it matches the MT of NativeObjectWrapperClass in the CoreLibBinder with RuntimeTypeSystem.GetPrimitiveType } ``` diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md index 93544b4064cc8d..08f41f49917dd3 100644 --- a/docs/design/datacontracts/SignatureDecoder.md +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -34,7 +34,7 @@ The cDAC implements the ISignatureTypeProvider with TType A cDAC SignatureTypeProvider is instantiated over a Module which is used to lookup types. -The following ISignatureTypeProvider APIs are trivially implemented using RuntimeTypeSystem.GetBinderType and RuntimeTypeSystem.GetConstructedType: +The following ISignatureTypeProvider APIs are trivially implemented using RuntimeTypeSystem.GetPrimitiveType and RuntimeTypeSystem.GetConstructedType: * GetArrayType - GetConstructedType * GetByReferenceType - GetConstructedType diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index f171294c3739f0..b8377796748011 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1878,6 +1878,7 @@ struct cdac_data { static constexpr PTR_SystemDomain* SystemDomainPtr = &SystemDomain::m_pSystemDomain; static constexpr size_t GlobalLoaderAllocator = offsetof(SystemDomain, m_GlobalAllocator); + static constexpr size_t SystemAssembly = offsetof(SystemDomain, m_pSystemAssembly); }; #endif // DACCESS_COMPILE diff --git a/src/coreclr/vm/binder.h b/src/coreclr/vm/binder.h index ba3cc41aba0e9e..3b3366323f8ed0 100644 --- a/src/coreclr/vm/binder.h +++ b/src/coreclr/vm/binder.h @@ -318,6 +318,7 @@ template<> struct cdac_data { static constexpr size_t Classes = offsetof(CoreLibBinder, m_pClasses); + static constexpr size_t ClassDescriptions = offsetof(CoreLibBinder, m_classDescriptions); }; // diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 40d0ac307513b6..f827fbcd0cc110 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -269,6 +269,7 @@ CDAC_TYPE_END(AppDomain) CDAC_TYPE_BEGIN(SystemDomain) CDAC_TYPE_INDETERMINATE(SystemDomain) CDAC_TYPE_FIELD(SystemDomain, /*GlobalLoaderAllocator*/, GlobalLoaderAllocator, cdac_data::GlobalLoaderAllocator) +CDAC_TYPE_FIELD(SystemDomain, /*pointer*/, SystemAssembly, cdac_data::SystemAssembly) CDAC_TYPE_END(SystemDomain) CDAC_TYPE_BEGIN(ArrayListBase) @@ -932,8 +933,15 @@ CDAC_TYPE_END(InstMethodHashTable) CDAC_TYPE_BEGIN(CoreLibBinder) CDAC_TYPE_INDETERMINATE(CoreLibBinder) CDAC_TYPE_FIELD(CoreLibBinder, /*pointer*/, Classes, cdac_data::Classes) +CDAC_TYPE_FIELD(CoreLibBinder, /*pointer*/, ClassDescriptions, cdac_data::ClassDescriptions) CDAC_TYPE_END(CoreLibBinder) +CDAC_TYPE_BEGIN(CoreLibClassDescription) +CDAC_TYPE_SIZE(sizeof(CoreLibClassDescription)) +CDAC_TYPE_FIELD(CoreLibClassDescription, /*pointer*/, NameSpace, offsetof(CoreLibClassDescription, nameSpace)) +CDAC_TYPE_FIELD(CoreLibClassDescription, /*pointer*/, Name, offsetof(CoreLibClassDescription, name)) +CDAC_TYPE_END(CoreLibClassDescription) + // this is an SHash type CDAC_TYPE_BEGIN(DynamicILBlobTable) CDAC_TYPE_SIZE(cdac_data::EntrySize) 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 4e688f799c6358..cbbf816c73684f 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 @@ -104,6 +104,7 @@ public interface ILoader : IContract bool IsAssemblyLoaded(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetGlobalLoaderAllocator() => throw new NotImplementedException(); + TargetPointer GetSystemAssembly() => throw new NotImplementedException(); TargetPointer GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); TargetPointer GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index b061183526c8a3..3c73b3fbc51ed0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -142,7 +142,9 @@ public interface IRuntimeTypeSystem : IContract bool IsArray(TypeHandle typeHandle, out uint rank) => throw new NotImplementedException(); TypeHandle GetTypeParam(TypeHandle typeHandle) => throw new NotImplementedException(); TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) => throw new NotImplementedException(); - TypeHandle GetBinderType(ushort typeCode) => throw new NotImplementedException(); + TypeHandle GetPrimitiveType(CorElementType typeCode) => throw new NotImplementedException(); + TypeHandle GetTypeByNameAndModule(string name, string nameSpace, ModuleHandle moduleHandle) => throw new NotImplementedException(); + void GetNameSpaceAndNameFromBinder(ushort index, out string nameSpace, out string name) => throw new NotImplementedException(); bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) => throw new NotImplementedException(); bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv) => throw new NotImplementedException(); bool IsPointer(TypeHandle typeHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index 6be64a591afb9d..45945d4af54be8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -51,6 +51,7 @@ public enum DataType DynamicStaticsInfo, EEClass, CoreLibBinder, + CoreLibClassDescription, ArrayClass, MethodTableAuxiliaryData, GenericsDictInfo, 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 c159333b28d074..85712827f7ff52 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 @@ -72,7 +72,18 @@ public bool IsComWrappersRCW(TargetPointer rcw) { TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(rcw); ushort typeCode = _target.ReadGlobal(Constants.Globals.NativeObjectWrapperClass); - TargetPointer typeHandlePtr = _target.Contracts.RuntimeTypeSystem.GetBinderType(typeCode).Address; + + // get name and namespace from corelibbinder + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + rts.GetNameSpaceAndNameFromBinder(typeCode, out string nameSpace, out string name); + + // get system module + ILoader loader = _target.Contracts.Loader; + TargetPointer systemAssembly = loader.GetSystemAssembly(); + ModuleHandle moduleHandle = loader.GetModuleHandleFromAssemblyPtr(systemAssembly); + + // lookup by name + TargetPointer typeHandlePtr = rts.GetTypeByNameAndModule(name, nameSpace, moduleHandle).Address; return mt == typeHandlePtr; } } 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 592ee98f8b79a6..205c8697c53628 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 @@ -504,6 +504,13 @@ TargetPointer ILoader.GetGlobalLoaderAllocator() return systemDomain.GlobalLoaderAllocator; } + TargetPointer ILoader.GetSystemAssembly() + { + TargetPointer systemDomainPointer = _target.ReadGlobalPointer(Constants.Globals.SystemDomain); + Data.SystemDomain systemDomain = _target.ProcessedData.GetOrAdd(_target.ReadPointer(systemDomainPointer)); + return systemDomain.SystemAssembly; + } + TargetPointer ILoader.GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer) { Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd(loaderAllocatorPointer); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index bba50e8ee2a812..7573fd47000f9c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -794,11 +794,11 @@ TypeHandle IRuntimeTypeSystem.GetConstructedType(TypeHandle typeHandle, CorEleme return new TypeHandle(TargetPointer.Null); } - TypeHandle IRuntimeTypeSystem.GetBinderType(ushort typeCode) + TypeHandle IRuntimeTypeSystem.GetPrimitiveType(CorElementType typeCode) { TargetPointer coreLib = _target.ReadGlobalPointer(Constants.Globals.CoreLib); CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); - TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + typeCode * (ulong)_target.PointerSize); + TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + (ulong)typeCode * (ulong)_target.PointerSize); return GetTypeHandle(typeHandlePtr); } @@ -813,7 +813,9 @@ private static bool ModuleMatch(AssemblyReference assemblyRef, AssemblyDefinitio private MetadataReader? LookForHandle(AssemblyReference exportedAssemblyRef) { - foreach (ModuleHandle mdhandle in _target.Contracts.Loader.GetModuleHandles(TargetPointer.Null, AssemblyIterationFlags.IncludeLoaded)) + TargetPointer appDomainPointer = _target.ReadGlobalPointer(Constants.Globals.AppDomain); + TargetPointer appDomain = _target.ReadPointer(appDomainPointer); + foreach (ModuleHandle mdhandle in _target.Contracts.Loader.GetModuleHandles(appDomain, AssemblyIterationFlags.IncludeLoaded)) { MetadataReader? md2 = _target.Contracts.EcmaMetadata.GetMetadata(mdhandle); if (md2 == null) @@ -827,23 +829,21 @@ private static bool ModuleMatch(AssemblyReference assemblyRef, AssemblyDefinitio return null; } - private TypeHandle LookupByName(string name, string nameSpace, ModuleHandle moduleHandle) + TypeHandle IRuntimeTypeSystem.GetTypeByNameAndModule(string name, string nameSpace, ModuleHandle moduleHandle) { string[] parts = name.Split('+'); + string outerName = parts[0]; MetadataReader? md = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle); TypeDefinitionHandle currentHandle = default; - // create a hash set of MDs and if we come across the same one more than once in a loop then we return error + // create a hash set of MDs and if we come across the same one more than once in a loop then we return null typehandle HashSet seenMDs = new(); - while (true) + // 1. find the outer type + while (md != null && seenMDs.Add(md)) { - if (md == null || !seenMDs.Add(md)) - return new TypeHandle(TargetPointer.Null); - // if our metadata is null or we have a cycle in type forwarding return null - foreach (TypeDefinitionHandle typeDefHandle in md.TypeDefinitions) { TypeDefinition typedef = md.GetTypeDefinition(typeDefHandle); - if (md.GetString(typedef.Name) == parts[0] && md.GetString(typedef.Namespace) == nameSpace) + if (md.GetString(typedef.Name) == outerName && md.GetString(typedef.Namespace) == nameSpace) { // found our outermost type, remember it currentHandle = typeDefHandle; @@ -859,27 +859,28 @@ private TypeHandle LookupByName(string name, string nameSpace, ModuleHandle modu ExportedType exportedType = md.GetExportedType(exportedTypeHandle); if (exportedType.Implementation.Kind != HandleKind.AssemblyReference || !exportedType.IsForwarder) continue; - if (md.GetString(exportedType.Name) == parts[0] && md.GetString(exportedType.Namespace) == nameSpace) + if (md.GetString(exportedType.Name) == outerName && md.GetString(exportedType.Namespace) == nameSpace) { // get the assembly ref for target AssemblyReferenceHandle arefHandle = (AssemblyReferenceHandle)exportedType.Implementation; AssemblyReference exportedAssemblyRef = md.GetAssemblyReference(arefHandle); md = LookForHandle(exportedAssemblyRef); - if (md == null || !seenMDs.Add(md)) - return new TypeHandle(TargetPointer.Null); break; } } } - else break; + else break; // if we found our typedef without forwarding break out of the while loop } + if (currentHandle == default) + return new TypeHandle(TargetPointer.Null); + // 2. Walk down the nested types for (int i = 1; i < parts.Length; i++) { string nestedName = parts[i]; bool found = false; - foreach (TypeDefinitionHandle nestedHandle in md.GetTypeDefinition(currentHandle).GetNestedTypes()) + foreach (TypeDefinitionHandle nestedHandle in md!.GetTypeDefinition(currentHandle).GetNestedTypes()) { TypeDefinition nestedDef = md.GetTypeDefinition(nestedHandle); if (md.GetString(nestedDef.Name) == nestedName) @@ -896,10 +897,21 @@ private TypeHandle LookupByName(string name, string nameSpace, ModuleHandle modu // 3. We have the handle, look up the type handle int token = MetadataTokens.GetToken((EntityHandle)currentHandle); ILoader loader = _target.Contracts.Loader; - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; TargetPointer typeDefToMethodTable = loader.GetLookupTables(moduleHandle).TypeDefToMethodTable; TargetPointer typeHandlePtr = loader.GetModuleLookupMapElement(typeDefToMethodTable, (uint)token, out _); - return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : rts.GetTypeHandle(typeHandlePtr); + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + return (typeHandlePtr == TargetPointer.Null) ? new TypeHandle(TargetPointer.Null) : rts.GetTypeHandle(typeHandlePtr); + } + + void IRuntimeTypeSystem.GetNameSpaceAndNameFromBinder(ushort index, out string nameSpace, out string name) + { + TargetPointer coreLib = _target.ReadGlobalPointer(Constants.Globals.CoreLib); + CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); + var typeInfo = _target.GetTypeInfo(DataType.CoreLibClassDescription); + TargetPointer coreLibClassDescriptionPtr = coreLibData.ClassDescriptions + index * typeInfo.Size!.Value; + CoreLibClassDescription coreLibClassDescription = _target.ProcessedData.GetOrAdd(coreLibClassDescriptionPtr); + nameSpace = coreLibClassDescription.NameSpace; + name = coreLibClassDescription.Name; } public bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs index 67a8ca35c94271..82672504975f49 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -66,7 +66,7 @@ public TypeHandle GetPointerType(TypeHandle elementType) => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Ptr, 0, []); public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) - => _runtimeTypeSystem.GetBinderType((ushort)typeCode); + => _runtimeTypeSystem.GetPrimitiveType((CorElementType)typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, []); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs index 49e6155d680cfa..ddb67102ce31b4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs @@ -13,7 +13,9 @@ public CoreLibBinder(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.CoreLibBinder); Classes = target.ReadPointer(address + (ulong)type.Fields[nameof(Classes)].Offset); + ClassDescriptions = target.ReadPointer(address + (ulong)type.Fields[nameof(ClassDescriptions)].Offset); } public TargetPointer Classes { get; init; } + public TargetPointer ClassDescriptions { get; init; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/SystemDomain.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/SystemDomain.cs index e3596be4def1bb..526ff3cdda71d0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/SystemDomain.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/SystemDomain.cs @@ -12,7 +12,9 @@ public SystemDomain(Target target, TargetPointer address) { Target.TypeInfo type = target.GetTypeInfo(DataType.SystemDomain); GlobalLoaderAllocator = address + (ulong)type.Fields[nameof(GlobalLoaderAllocator)].Offset; + SystemAssembly = target.ReadPointer(address + (ulong)type.Fields[nameof(SystemAssembly)].Offset); } public TargetPointer GlobalLoaderAllocator { get; init; } + public TargetPointer SystemAssembly { get; init; } } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 72c999843f3f12..6b574fbdf0b911 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -793,7 +793,7 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat // In the future we may want to return a TypeHandle instead of a MethodTable, and modify SOS to do more complete pretty-printing. // DAC equivalent: src/coreclr/vm/typehandle.inl TypeHandle::GetMethodTable if (rtsContract.IsFunctionPointer(foundTypeHandle, out _, out _) || rtsContract.IsPointer(foundTypeHandle)) - data->MTOfType = rtsContract.GetBinderType((ushort)CorElementType.U).Address.ToClrDataAddress(_target); + data->MTOfType = rtsContract.GetPrimitiveType(CorElementType.U).Address.ToClrDataAddress(_target); // array MTs else if (rtsContract.IsArray(foundTypeHandle, out _)) data->MTOfType = foundTypeHandle.Address.ToClrDataAddress(_target); From 161df491d2ba612cd1778e96908dff56901e5196 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 10 Oct 2025 14:45:53 -0700 Subject: [PATCH 09/23] [skip ci] --- docs/design/datacontracts/ComWrappers.md | 8 +- docs/design/datacontracts/Loader.md | 11 ++- src/coreclr/debug/daccess/request.cpp | 6 +- src/coreclr/debug/ee/dactable.cpp | 20 ----- src/coreclr/inc/dacvars.h | 4 + src/coreclr/inc/gfunc_list.h | 4 - src/coreclr/interop/comwrappers.cpp | 90 +++++++++++-------- src/coreclr/interop/comwrappers.hpp | 27 ------ src/coreclr/interop/inc/interoplibabi.h | 5 ++ src/coreclr/vm/appdomain.cpp | 5 -- .../vm/datadescriptor/datadescriptor.h | 6 +- .../vm/datadescriptor/datadescriptor.inc | 14 +-- src/coreclr/vm/vars.hpp | 12 +++ 13 files changed, 102 insertions(+), 110 deletions(-) diff --git a/docs/design/datacontracts/ComWrappers.md b/docs/design/datacontracts/ComWrappers.md index 23eb0a2eda6b52..297f13bc6876ae 100644 --- a/docs/design/datacontracts/ComWrappers.md +++ b/docs/design/datacontracts/ComWrappers.md @@ -40,6 +40,7 @@ Contracts used: | --- | | `Object` | | `RuntimeTypeSystem` | +| `Loader` | ``` csharp @@ -97,7 +98,10 @@ public long GetMOWReferenceCount(TargetPointer mow) public bool IsComWrappersRCW(TargetPointer rcw) { - // get method table from rcw using Object contract GetMethodTableAddress - // and ensure it matches the MT of NativeObjectWrapperClass in the CoreLibBinder with RuntimeTypeSystem.GetPrimitiveType + // Get method table from rcw using Object contract GetMethodTableAddress + // Then look up the name and namespace of the native object wrapper class in corelibbinder using RuntimeTypeSystem.GetNameSpaceAndNameFromBinder + // Find module from the system assembly + // Then use RuntimeTypeSystem contract to look up type handle by name/namespace/module + // Then compare the rcw method table with the method table found by name/namespace/module } ``` diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index 77ef18e9e8cff6..412aac01fb29ac 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -79,6 +79,7 @@ IEnumerable<(TargetPointer, uint)> EnumerateModuleLookupMap(TargetPointer table) bool IsCollectible(ModuleHandle handle); bool IsAssemblyLoaded(ModuleHandle handle); TargetPointer GetGlobalLoaderAllocator(); +TargetPointer GetSystemAssembly(); TargetPointer GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer); TargetPointer GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer); TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer); @@ -132,6 +133,7 @@ TargetPointer GetObjectHandle(TargetPointer loaderAllocatorPointer); | `AppDomain` | `DomainAssemblyList` | ArrayListBase of assemblies in the AppDomain | | `AppDomain` | `FriendlyName` | Friendly name of the AppDomain | | `SystemDomain` | `GlobalLoaderAllocator` | global LoaderAllocator | +| `SystemDomain` | `SystemAssembly` | pointer to the system Assembly | | `LoaderAllocator` | `ReferenceCount` | Reference count of LoaderAllocator | | `LoaderAllocator` | `HighFrequencyHeap` | High-frequency heap of LoaderAllocator | | `LoaderAllocator` | `LowFrequencyHeap` | Low-frequency heap of LoaderAllocator | @@ -615,7 +617,14 @@ TargetPointer GetGlobalLoaderAllocator() { TargetPointer systemDomainPointer = target.ReadGlobalPointer("SystemDomain"); TargetPointer systemDomain = target.ReadPointer(systemDomainPointer); - return target.ReadPointer(systemDomain + /* SystemDomain::GlobalLoaderAllocator offset */); + return systemDomain + /* SystemDomain::GlobalLoaderAllocator offset */; +} + +TargetPointer GetSystemAssembly() +{ + TargetPointer systemDomainPointer = target.ReadGlobalPointer("SystemDomain"); + TargetPointer systemDomain = target.ReadPointer(systemDomainPointer); + return target.ReadPointer(systemDomain + /* SystemDomain::SystemAssembly offset */); } TargetPointer GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 975796e101594e..cdab27b3491496 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -4364,8 +4364,10 @@ BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr) return FALSE; } - return (qiAddress == GFN_TADDR(ManagedObjectWrapper_QueryInterface) - || qiAddress == GFN_TADDR(TrackerTarget_QueryInterface)); + PTR_QueryInterfaceMethod methods = dac_cast(InteropLib::ABI::g_knownQueryInterfaceImplementations); + + return (qiAddress == (TADDR)methods[0] + || qiAddress == (TADDR)methods[1]); } TADDR ClrDataAccess::DACGetManagedObjectWrapperFromCCW(CLRDATA_ADDRESS ccwPtr) diff --git a/src/coreclr/debug/ee/dactable.cpp b/src/coreclr/debug/ee/dactable.cpp index 9c65b163cf2799..4c8fe9ab7bc0d7 100644 --- a/src/coreclr/debug/ee/dactable.cpp +++ b/src/coreclr/debug/ee/dactable.cpp @@ -25,26 +25,6 @@ extern PCODE g_FCDynamicallyAssignedImplementations[ECall::NUM_DYNAMICALLY_ASSIGNED_FCALL_IMPLEMENTATIONS]; extern "C" void STDCALL ThePreStubPatchLabel(void); -#ifdef FEATURE_COMWRAPPERS -// Keep these forward declarations in sync with the method definitions in interop/comwrappers.cpp -namespace InteropLib -{ - namespace ABI - { - struct ComInterfaceDispatch; - } -} -HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface( - _In_ InteropLib::ABI::ComInterfaceDispatch* disp, - /* [in] */ REFIID riid, - /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject); -HRESULT STDMETHODCALLTYPE TrackerTarget_QueryInterface( - _In_ InteropLib::ABI::ComInterfaceDispatch* disp, - /* [in] */ REFIID riid, - /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject); - -#endif - template class U> struct is_type_template_instantiation { diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index 151335e6daa60b..ca5b0e9f6ac1d1 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -203,6 +203,10 @@ DEFINE_DACVAR(PTR_SyncTableEntry, dac__g_pSyncTable, ::g_pSyncTable) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pRCWCleanupList, ::g_pRCWCleanupList) #endif // FEATURE_COMINTEROP +#ifdef FEATURE_COMWRAPPERS +DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_knownQueryInterfaceImplementations, InteropLib::ABI::g_knownQueryInterfaceImplementations) +#endif // FEATURE_COMWRAPPERS + #ifndef TARGET_UNIX DEFINE_DACVAR(SIZE_T, dac__g_runtimeLoadedBaseAddress, ::g_runtimeLoadedBaseAddress) DEFINE_DACVAR(SIZE_T, dac__g_runtimeVirtualSize, ::g_runtimeVirtualSize) diff --git a/src/coreclr/inc/gfunc_list.h b/src/coreclr/inc/gfunc_list.h index b7bfa5dc6a5ebd..9631099ff92f46 100644 --- a/src/coreclr/inc/gfunc_list.h +++ b/src/coreclr/inc/gfunc_list.h @@ -19,7 +19,3 @@ DEFINE_DACGFN(Unknown_AddRef) DEFINE_DACGFN(Unknown_AddRefSpecial) DEFINE_DACGFN(Unknown_AddRefInner) #endif -#ifdef FEATURE_COMWRAPPERS -DEFINE_DACGFN(ManagedObjectWrapper_QueryInterface) -DEFINE_DACGFN(TrackerTarget_QueryInterface) -#endif diff --git a/src/coreclr/interop/comwrappers.cpp b/src/coreclr/interop/comwrappers.cpp index 05fb629cf2282f..ab681e57f75372 100644 --- a/src/coreclr/interop/comwrappers.cpp +++ b/src/coreclr/interop/comwrappers.cpp @@ -59,19 +59,17 @@ namespace ABI } } -// ManagedObjectWrapper_QueryInterface needs to be visible outside of this compilation unit -// to support the DAC (look for the GetEEFuncEntryPoint call). -HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface( +namespace +{ + HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface( _In_ ABI::ComInterfaceDispatch* disp, /* [in] */ REFIID riid, /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) -{ - ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp); - return wrapper->QueryInterface(riid, ppvObject); -} + { + ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp); + return wrapper->QueryInterface(riid, ppvObject); + } -namespace -{ ULONG STDMETHODCALLTYPE ManagedObjectWrapper_AddRef(_In_ ABI::ComInterfaceDispatch* disp) { ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp); @@ -99,36 +97,6 @@ namespace static_assert(sizeof(ManagedObjectWrapper_IUnknownImpl) == (3 * sizeof(void*)), "Unexpected vtable size"); } -// TrackerTarget_QueryInterface needs to be visible outside of this compilation unit -// to support the DAC (look for the GetEEFuncEntryPoint call). -HRESULT STDMETHODCALLTYPE TrackerTarget_QueryInterface( - _In_ ABI::ComInterfaceDispatch* disp, - /* [in] */ REFIID riid, - /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) -{ - ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp); - - // AddRef is "safe" at this point because since it is a MOW with an outstanding - // Reference Tracker reference, we know for sure the MOW is not claimed yet - // but the managed object could be. If the managed object is alive at this - // moment the AddRef will ensure it remains alive for the duration of the - // QueryInterface. - ComHolder ensureStableLifetime{ wrapper }; - - // For MOWs that have outstanding Reference Tracker reference, they could be either: - // 1. Marked to Destroy - in this case it is unsafe to touch wrapper. - // 2. Object Handle target has been NULLed out by GC. - if (wrapper->IsMarkedToDestroy() - || !InteropLibImports::HasValidTarget(wrapper->GetTarget())) - { - // It is unsafe to proceed with a QueryInterface call. The MOW has been - // marked destroyed or the associated managed object has been collected. - return COR_E_ACCESSING_CCW; - } - - return wrapper->QueryInterface(riid, ppvObject); -} - namespace { const int32_t TrackerRefShift = 32; @@ -152,6 +120,34 @@ namespace return (c & DestroySentinel) != 0; } + HRESULT STDMETHODCALLTYPE TrackerTarget_QueryInterface( + _In_ ABI::ComInterfaceDispatch* disp, + /* [in] */ REFIID riid, + /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) + { + ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp); + + // AddRef is "safe" at this point because since it is a MOW with an outstanding + // Reference Tracker reference, we know for sure the MOW is not claimed yet + // but the managed object could be. If the managed object is alive at this + // moment the AddRef will ensure it remains alive for the duration of the + // QueryInterface. + ComHolder ensureStableLifetime{ wrapper }; + + // For MOWs that have outstanding Reference Tracker reference, they could be either: + // 1. Marked to Destroy - in this case it is unsafe to touch wrapper. + // 2. Object Handle target has been NULLed out by GC. + if (wrapper->IsMarkedToDestroy() + || !InteropLibImports::HasValidTarget(wrapper->GetTarget())) + { + // It is unsafe to proceed with a QueryInterface call. The MOW has been + // marked destroyed or the associated managed object has been collected. + return COR_E_ACCESSING_CCW; + } + + return wrapper->QueryInterface(riid, ppvObject); + } + ULONG STDMETHODCALLTYPE TrackerTarget_AddRefFromReferenceTracker(_In_ ABI::ComInterfaceDispatch* disp) { _ASSERTE(disp != nullptr && disp->vtable != nullptr); @@ -527,3 +523,19 @@ InteropLib::OBJECTHANDLE ManagedObjectWrapper::GetTarget() const { return _target; } + + +#ifndef DACCESS_COMPILE +using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); +namespace InteropLib { namespace ABI { + struct ComInterfaceDispatch; + QueryInterfaceMethod g_knownQueryInterfaceImplementations[2] = { + &ManagedObjectWrapper_QueryInterface, + &TrackerTarget_QueryInterface + }; + } +} +#endif // DACCESS_COMPILE +typedef DPTR(QueryInterfaceMethod) PTR_QueryInterfaceMethod; + +GARY_IMPL(PTR_QueryInterfaceMethod, InteropLib::ABI::g_knownQueryInterfaceImplementations, 2); diff --git a/src/coreclr/interop/comwrappers.hpp b/src/coreclr/interop/comwrappers.hpp index 3cfb0722a57bfd..8bcd604dafffbb 100644 --- a/src/coreclr/interop/comwrappers.hpp +++ b/src/coreclr/interop/comwrappers.hpp @@ -170,31 +170,4 @@ struct ComHolder } }; -// Keep these forward declarations in sync with the method definitions in interop/comwrappers.cpp -namespace InteropLib -{ - namespace ABI - { - struct ComInterfaceDispatch; - } -} -HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface( - _In_ InteropLib::ABI::ComInterfaceDispatch* disp, - /* [in] */ REFIID riid, - /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject); -HRESULT STDMETHODCALLTYPE TrackerTarget_QueryInterface( - _In_ InteropLib::ABI::ComInterfaceDispatch* disp, - /* [in] */ REFIID riid, - /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject); - -struct ComWrappersVtablePtrs -{ - decltype(&ManagedObjectWrapper_QueryInterface) MowQueryInterface; - decltype(&TrackerTarget_QueryInterface) TtQueryInterface; -}; - -const ComWrappersVtablePtrs g_ComWrappersVtablePtrs = { - &ManagedObjectWrapper_QueryInterface, - &TrackerTarget_QueryInterface -}; #endif // _INTEROP_COMWRAPPERS_HPP_ diff --git a/src/coreclr/interop/inc/interoplibabi.h b/src/coreclr/interop/inc/interoplibabi.h index bf066c92a47b50..a80bbec552b907 100644 --- a/src/coreclr/interop/inc/interoplibabi.h +++ b/src/coreclr/interop/inc/interoplibabi.h @@ -80,6 +80,11 @@ namespace InteropLib ComInterfaceDispatch* entries = dispatch->_entries; return entries + (i % EntriesPerThisPtr); } + + #ifndef DACCESS_COMPILE + using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); + QueryInterfaceMethod g_knownQueryInterfaceImplementations[2]; + #endif // DACCESS_COMPILE } } diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index ed2cde552bf60a..3d8ddd6df0bee0 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1078,11 +1078,6 @@ void SystemDomain::LoadBaseSystemClasses() CoreLibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC); CoreLibBinder::GetClass(CLASS__IREADONLYLISTGENERIC); - // cache the method table here for cDAC IsComWrappersRCW - #ifdef FEATURE_COMWRAPPERS - CoreLibBinder::GetClass(CLASS__NATIVE_OBJECT_WRAPPER); - #endif - // Load String g_pStringClass = CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING); diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.h b/src/coreclr/vm/datadescriptor/datadescriptor.h index 6f81ace686545f..f97b5b7947ef63 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.h +++ b/src/coreclr/vm/datadescriptor/datadescriptor.h @@ -22,9 +22,9 @@ #include "../debug/ee/debugger.h" #include "patchpointinfo.h" -#ifdef FEATURE_COMWRAPPERS -#include "../interop/comwrappers.hpp" -#endif // FEATURE_COMWRAPPERS +// #ifdef FEATURE_COMWRAPPERS +// #include "../interop/comwrappers.hpp" +// #endif // FEATURE_COMWRAPPERS #ifdef HAVE_GCCOVER #include "gccover.h" diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index f827fbcd0cc110..50f3b866589019 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -951,12 +951,12 @@ CDAC_TYPE_FIELD(DynamicILBlobTable, /*uint32*/, EntryMethodToken, cdac_data::EntryIL) CDAC_TYPE_END(DynamicILBlobTable) -#ifdef FEATURE_COMWRAPPERS -CDAC_TYPE_BEGIN(ComWrappersVtablePtrs) -CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, MowQueryInterface, offsetof(ComWrappersVtablePtrs, MowQueryInterface)) -CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, TtQueryInterface, offsetof(ComWrappersVtablePtrs, TtQueryInterface)) -CDAC_TYPE_END(ComWrappersVtablePtrs) -#endif +// #ifdef FEATURE_COMWRAPPERS +// CDAC_TYPE_BEGIN(ComWrappersVtablePtrs) +// CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, MowQueryInterface, offsetof(ComWrappersVtablePtrs, MowQueryInterface)) +// CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, TtQueryInterface, offsetof(ComWrappersVtablePtrs, TtQueryInterface)) +// CDAC_TYPE_END(ComWrappersVtablePtrs) +// #endif CDAC_TYPES_END() @@ -1053,7 +1053,7 @@ CDAC_GLOBAL_POINTER(ThinlockThreadIdDispenser, &::g_pThinLockThreadIdDispenser) #ifdef FEATURE_COMWRAPPERS CDAC_GLOBAL(DispatchThisPtrMask, uintptr_t, InteropLib::ABI::DispatchThisPtrMask) CDAC_GLOBAL(NativeObjectWrapperClass, uint32, CLASS__NATIVE_OBJECT_WRAPPER) -CDAC_GLOBAL_POINTER(ComWrappersVtablePtrs, &g_ComWrappersVtablePtrs) +CDAC_GLOBAL_POINTER(ComWrappersVtablePtrs, InteropLib::ABI::g_knownQueryInterfaceImplementations) #endif // FEATURE_COMWRAPPERS CDAC_GLOBAL_POINTER(GcNotificationFlags, &::g_gcNotificationFlags) CDAC_GLOBAL_POINTER(CoreLib, &::g_CoreLib) diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index 05b9be59bf7f47..3d2d3d65cb65fb 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -40,6 +40,18 @@ class SyncBlockCache; class SyncTableEntry; class ThreadStore; namespace ETW { class CEtwTracer; }; +#ifdef FEATURE_COMWRAPPERS +namespace InteropLib { namespace ABI { + struct ComInterfaceDispatch; + using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); + QueryInterfaceMethod g_knownQueryInterfaceImplementations[2]; +} } + +using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); +typedef DPTR(QueryInterfaceMethod) PTR_QueryInterfaceMethod; +GARY_DECL(PTR_QueryInterfaceMethod, g_knownQueryInterfaceImplementations, 2); + +#endif // FEATURE_COMWRAPPERS class DebugInterface; class DebugInfoManager; class EEDbgInterfaceImpl; From c161ed5a01dc279acde0b667f889db6db753fd4f Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 12 Feb 2026 17:53:32 -0800 Subject: [PATCH 10/23] code review --- docs/design/datacontracts/ComWrappers.md | 10 +++++++--- src/coreclr/debug/daccess/request.cpp | 6 ++---- src/coreclr/interop/comwrappers.cpp | 6 ------ src/coreclr/interop/comwrappers.hpp | 1 - src/coreclr/interop/inc/interoplibabi.h | 5 ----- src/coreclr/vm/binder.h | 1 - src/coreclr/vm/corelib.h | 2 +- .../vm/datadescriptor/datadescriptor.h | 3 --- .../vm/datadescriptor/datadescriptor.inc | 20 ++++++------------- src/coreclr/vm/vars.cpp | 4 ++++ src/coreclr/vm/vars.hpp | 8 ++++---- .../Contracts/IRuntimeTypeSystem.cs | 1 - .../DataType.cs | 1 - .../Constants.cs | 1 - .../Contracts/ComWrappers_1.cs | 10 ++++------ .../Contracts/RuntimeTypeSystem_1.cs | 11 ---------- .../Data/CoreLibBinder.cs | 2 -- .../SOSDacImpl.cs | 5 ++++- 18 files changed, 32 insertions(+), 65 deletions(-) diff --git a/docs/design/datacontracts/ComWrappers.md b/docs/design/datacontracts/ComWrappers.md index 297f13bc6876ae..c339a2666feba7 100644 --- a/docs/design/datacontracts/ComWrappers.md +++ b/docs/design/datacontracts/ComWrappers.md @@ -33,7 +33,12 @@ Global variables used: | --- | --- | --- | | `ComWrappersVtablePtrs` | TargetPointer | Pointer to struct containing ComWrappers-related function pointers | | `DispatchThisPtrMask` | TargetPointer | Used to mask low bits of CCW pointer to the nearest valid address from which to read a managed object wrapper | -| `NativeObjectWrapperClass` | ushort | The index of the native object wrapper class into the CoreLibBinder classes | + +### Contract Constants: +| Name | Type | Purpose | Value | +| --- | --- | --- | --- | +| `NativeObjectWrapperNamespace` | string | Namespace of System.Runtime.InteropServices.ComWrappers+NativeObjectWrapper | `System.Runtime.InteropServices` | +| `NativeObjectWrapperName` | string | Name of System.Runtime.InteropServices.ComWrappers+NativeObjectWrapper | `ComWrappers+NativeObjectWrapper` | Contracts used: | Contract Name | @@ -99,9 +104,8 @@ public long GetMOWReferenceCount(TargetPointer mow) public bool IsComWrappersRCW(TargetPointer rcw) { // Get method table from rcw using Object contract GetMethodTableAddress - // Then look up the name and namespace of the native object wrapper class in corelibbinder using RuntimeTypeSystem.GetNameSpaceAndNameFromBinder // Find module from the system assembly - // Then use RuntimeTypeSystem contract to look up type handle by name/namespace/module + // Then use RuntimeTypeSystem contract to look up type handle by name/namespace/module hardcoded in contract // Then compare the rcw method table with the method table found by name/namespace/module } ``` diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index dbf5083034cc03..1b4527de21b3f8 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -4361,10 +4361,8 @@ BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr) return FALSE; } - PTR_QueryInterfaceMethod methods = dac_cast(InteropLib::ABI::g_knownQueryInterfaceImplementations); - - return (qiAddress == (TADDR)methods[0] - || qiAddress == (TADDR)methods[1]); + return (qiAddress == g_knownQueryInterfaceImplementations[0] + || qiAddress == g_knownQueryInterfaceImplementations[1]); } TADDR ClrDataAccess::DACGetManagedObjectWrapperFromCCW(CLRDATA_ADDRESS ccwPtr) diff --git a/src/coreclr/interop/comwrappers.cpp b/src/coreclr/interop/comwrappers.cpp index ab681e57f75372..1fdfe14492e523 100644 --- a/src/coreclr/interop/comwrappers.cpp +++ b/src/coreclr/interop/comwrappers.cpp @@ -524,8 +524,6 @@ InteropLib::OBJECTHANDLE ManagedObjectWrapper::GetTarget() const return _target; } - -#ifndef DACCESS_COMPILE using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); namespace InteropLib { namespace ABI { struct ComInterfaceDispatch; @@ -535,7 +533,3 @@ namespace InteropLib { namespace ABI { }; } } -#endif // DACCESS_COMPILE -typedef DPTR(QueryInterfaceMethod) PTR_QueryInterfaceMethod; - -GARY_IMPL(PTR_QueryInterfaceMethod, InteropLib::ABI::g_knownQueryInterfaceImplementations, 2); diff --git a/src/coreclr/interop/comwrappers.hpp b/src/coreclr/interop/comwrappers.hpp index 8bcd604dafffbb..00ebfc39194b96 100644 --- a/src/coreclr/interop/comwrappers.hpp +++ b/src/coreclr/interop/comwrappers.hpp @@ -169,5 +169,4 @@ struct ComHolder } } }; - #endif // _INTEROP_COMWRAPPERS_HPP_ diff --git a/src/coreclr/interop/inc/interoplibabi.h b/src/coreclr/interop/inc/interoplibabi.h index a80bbec552b907..bf066c92a47b50 100644 --- a/src/coreclr/interop/inc/interoplibabi.h +++ b/src/coreclr/interop/inc/interoplibabi.h @@ -80,11 +80,6 @@ namespace InteropLib ComInterfaceDispatch* entries = dispatch->_entries; return entries + (i % EntriesPerThisPtr); } - - #ifndef DACCESS_COMPILE - using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); - QueryInterfaceMethod g_knownQueryInterfaceImplementations[2]; - #endif // DACCESS_COMPILE } } diff --git a/src/coreclr/vm/binder.h b/src/coreclr/vm/binder.h index 3b3366323f8ed0..ba3cc41aba0e9e 100644 --- a/src/coreclr/vm/binder.h +++ b/src/coreclr/vm/binder.h @@ -318,7 +318,6 @@ template<> struct cdac_data { static constexpr size_t Classes = offsetof(CoreLibBinder, m_pClasses); - static constexpr size_t ClassDescriptions = offsetof(CoreLibBinder, m_classDescriptions); }; // diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 185cae0dd920bc..6d14f5b05a8575 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -418,7 +418,7 @@ END_ILLINK_FEATURE_SWITCH() DEFINE_CLASS(COMWRAPPERS, Interop, ComWrappers) DEFINE_CLASS(CREATEOBJECTFLAGS, Interop, CreateObjectFlags) DEFINE_CLASS(MANAGED_OBJECT_WRAPPER_HOLDER,Interop, ComWrappers+ManagedObjectWrapperHolder) -DEFINE_CLASS(NATIVE_OBJECT_WRAPPER, Interop, ComWrappers+NativeObjectWrapper) +DEFINE_CLASS(NATIVE_OBJECT_WRAPPER, Interop, ComWrappers+NativeObjectWrapper) // cDAC depends on the exact namespace and name DEFINE_METHOD(COMWRAPPERS, CALL_ICUSTOMQUERYINTERFACE, CallICustomQueryInterface, SM_ManagedObjectWrapperHolder_RefGuid_RefIntPtr_RetInt) DEFINE_METHOD(COMWRAPPERS, GET_OR_CREATE_COM_INTERFACE_FOR_OBJECT_WITH_GLOBAL_MARSHALLING_INSTANCE, GetOrCreateComInterfaceForObjectWithGlobalMarshallingInstance, SM_Obj_RetIntPtr) DEFINE_METHOD(COMWRAPPERS, GET_OR_CREATE_OBJECT_FOR_COM_INSTANCE_WITH_GLOBAL_MARSHALLING_INSTANCE, GetOrCreateObjectForComInstanceWithGlobalMarshallingInstance, SM_IntPtr_CreateObjectFlags_RetObj) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.h b/src/coreclr/vm/datadescriptor/datadescriptor.h index f97b5b7947ef63..651975ba0cc4c7 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.h +++ b/src/coreclr/vm/datadescriptor/datadescriptor.h @@ -22,9 +22,6 @@ #include "../debug/ee/debugger.h" #include "patchpointinfo.h" -// #ifdef FEATURE_COMWRAPPERS -// #include "../interop/comwrappers.hpp" -// #endif // FEATURE_COMWRAPPERS #ifdef HAVE_GCCOVER #include "gccover.h" diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 79ced5d563cf0a..59be84108bd061 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1006,15 +1006,8 @@ CDAC_TYPE_END(InstMethodHashTable) CDAC_TYPE_BEGIN(CoreLibBinder) CDAC_TYPE_INDETERMINATE(CoreLibBinder) CDAC_TYPE_FIELD(CoreLibBinder, /*pointer*/, Classes, cdac_data::Classes) -CDAC_TYPE_FIELD(CoreLibBinder, /*pointer*/, ClassDescriptions, cdac_data::ClassDescriptions) CDAC_TYPE_END(CoreLibBinder) -CDAC_TYPE_BEGIN(CoreLibClassDescription) -CDAC_TYPE_SIZE(sizeof(CoreLibClassDescription)) -CDAC_TYPE_FIELD(CoreLibClassDescription, /*pointer*/, NameSpace, offsetof(CoreLibClassDescription, nameSpace)) -CDAC_TYPE_FIELD(CoreLibClassDescription, /*pointer*/, Name, offsetof(CoreLibClassDescription, name)) -CDAC_TYPE_END(CoreLibClassDescription) - // this is an SHash type CDAC_TYPE_BEGIN(DynamicILBlobTable) CDAC_TYPE_SIZE(cdac_data::EntrySize) @@ -1024,12 +1017,12 @@ CDAC_TYPE_FIELD(DynamicILBlobTable, /*uint32*/, EntryMethodToken, cdac_data::EntryIL) CDAC_TYPE_END(DynamicILBlobTable) -// #ifdef FEATURE_COMWRAPPERS -// CDAC_TYPE_BEGIN(ComWrappersVtablePtrs) -// CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, MowQueryInterface, offsetof(ComWrappersVtablePtrs, MowQueryInterface)) -// CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, TtQueryInterface, offsetof(ComWrappersVtablePtrs, TtQueryInterface)) -// CDAC_TYPE_END(ComWrappersVtablePtrs) -// #endif +#ifdef FEATURE_COMWRAPPERS +CDAC_TYPE_BEGIN(ComWrappersVtablePtrs) +CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, MowQueryInterface, 0) +CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, TtQueryInterface, sizeof(uintptr_t)) +CDAC_TYPE_END(ComWrappersVtablePtrs) +#endif CDAC_TYPES_END() @@ -1138,7 +1131,6 @@ CDAC_GLOBAL_POINTER(OffsetOfCurrentThreadInfo, &::g_offsetOfCurrentThreadInfo) CDAC_GLOBAL_POINTER(ThinlockThreadIdDispenser, &::g_pThinLockThreadIdDispenser) #ifdef FEATURE_COMWRAPPERS CDAC_GLOBAL(DispatchThisPtrMask, uintptr_t, InteropLib::ABI::DispatchThisPtrMask) -CDAC_GLOBAL(NativeObjectWrapperClass, uint32, CLASS__NATIVE_OBJECT_WRAPPER) CDAC_GLOBAL_POINTER(ComWrappersVtablePtrs, InteropLib::ABI::g_knownQueryInterfaceImplementations) #endif // FEATURE_COMWRAPPERS CDAC_GLOBAL_POINTER(GcNotificationFlags, &::g_gcNotificationFlags) diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index f6fd1eac774627..14eab84eeaa2fb 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -94,6 +94,10 @@ GPTR_IMPL_INIT(StressLog, g_pStressLog, &StressLog::theLog); GPTR_IMPL(RCWCleanupList,g_pRCWCleanupList); #endif // FEATURE_COMINTEROP +#ifdef FEATURE_COMWRAPPERS +GARY_IMPL(TADDR, g_knownQueryInterfaceImplementations, 2); +#endif // FEATURE_COMWRAPPERS + #ifdef FEATURE_INTEROP_DEBUGGING GVAL_IMPL_INIT(DWORD, g_debuggerWordTLSIndex, TLS_OUT_OF_INDEXES); #endif diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index acfc3e933cedc9..56b3613fe60fb4 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -44,12 +44,12 @@ namespace ETW { class CEtwTracer; }; namespace InteropLib { namespace ABI { struct ComInterfaceDispatch; using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); - QueryInterfaceMethod g_knownQueryInterfaceImplementations[2]; +#ifndef DACCESS_COMPILE + extern QueryInterfaceMethod g_knownQueryInterfaceImplementations[2]; +#endif // !DACCESS_COMPILE } } -using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); -typedef DPTR(QueryInterfaceMethod) PTR_QueryInterfaceMethod; -GARY_DECL(PTR_QueryInterfaceMethod, g_knownQueryInterfaceImplementations, 2); +GARY_DECL(TADDR, g_knownQueryInterfaceImplementations, 2); #endif // FEATURE_COMWRAPPERS class DebugInterface; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index 493ad97e7ab90d..b750abb30a753c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -144,7 +144,6 @@ public interface IRuntimeTypeSystem : IContract TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) => throw new NotImplementedException(); TypeHandle GetPrimitiveType(CorElementType typeCode) => throw new NotImplementedException(); TypeHandle GetTypeByNameAndModule(string name, string nameSpace, ModuleHandle moduleHandle) => throw new NotImplementedException(); - void GetNameSpaceAndNameFromBinder(ushort index, out string nameSpace, out string name) => throw new NotImplementedException(); bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) => throw new NotImplementedException(); bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv) => throw new NotImplementedException(); bool IsPointer(TypeHandle typeHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index 45945d4af54be8..6be64a591afb9d 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -51,7 +51,6 @@ public enum DataType DynamicStaticsInfo, EEClass, CoreLibBinder, - CoreLibClassDescription, ArrayClass, MethodTableAuxiliaryData, GenericsDictInfo, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index 7d0eb1e3307cce..427ef634e7726a 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -33,7 +33,6 @@ public static class Globals public const string TlsIndexBase = nameof(TlsIndexBase); public const string ThinlockThreadIdDispenser = nameof(ThinlockThreadIdDispenser); public const string DispatchThisPtrMask = nameof(DispatchThisPtrMask); - public const string NativeObjectWrapperClass = nameof(NativeObjectWrapperClass); public const string ComWrappersVtablePtrs = nameof(ComWrappersVtablePtrs); public const string GcNotificationFlags = nameof(GcNotificationFlags); 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 85712827f7ff52..bd2dbc14978c90 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 @@ -10,6 +10,8 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly struct ComWrappers_1 : IComWrappers { + private const string NativeObjectWrapperNamespace = "System.Runtime.InteropServices"; + private const string NativeObjectWrapperName = "ComWrappers+NativeObjectWrapper"; private readonly Target _target; public ComWrappers_1(Target target) @@ -71,11 +73,6 @@ public long GetMOWReferenceCount(TargetPointer mow) public bool IsComWrappersRCW(TargetPointer rcw) { TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(rcw); - ushort typeCode = _target.ReadGlobal(Constants.Globals.NativeObjectWrapperClass); - - // get name and namespace from corelibbinder - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - rts.GetNameSpaceAndNameFromBinder(typeCode, out string nameSpace, out string name); // get system module ILoader loader = _target.Contracts.Loader; @@ -83,7 +80,8 @@ public bool IsComWrappersRCW(TargetPointer rcw) ModuleHandle moduleHandle = loader.GetModuleHandleFromAssemblyPtr(systemAssembly); // lookup by name - TargetPointer typeHandlePtr = rts.GetTypeByNameAndModule(name, nameSpace, moduleHandle).Address; + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + TargetPointer typeHandlePtr = rts.GetTypeByNameAndModule(NativeObjectWrapperName, NativeObjectWrapperNamespace, moduleHandle).Address; return mt == typeHandlePtr; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index f84dd69dbbfea4..2dd0e204168966 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -903,17 +903,6 @@ TypeHandle IRuntimeTypeSystem.GetTypeByNameAndModule(string name, string nameSpa return (typeHandlePtr == TargetPointer.Null) ? new TypeHandle(TargetPointer.Null) : rts.GetTypeHandle(typeHandlePtr); } - void IRuntimeTypeSystem.GetNameSpaceAndNameFromBinder(ushort index, out string nameSpace, out string name) - { - TargetPointer coreLib = _target.ReadGlobalPointer(Constants.Globals.CoreLib); - CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); - var typeInfo = _target.GetTypeInfo(DataType.CoreLibClassDescription); - TargetPointer coreLibClassDescriptionPtr = coreLibData.ClassDescriptions + index * typeInfo.Size!.Value; - CoreLibClassDescription coreLibClassDescription = _target.ProcessedData.GetOrAdd(coreLibClassDescriptionPtr); - nameSpace = coreLibClassDescription.NameSpace; - name = coreLibClassDescription.Name; - } - public bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) { module = TargetPointer.Null; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs index ddb67102ce31b4..49e6155d680cfa 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs @@ -13,9 +13,7 @@ public CoreLibBinder(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.CoreLibBinder); Classes = target.ReadPointer(address + (ulong)type.Fields[nameof(Classes)].Offset); - ClassDescriptions = target.ReadPointer(address + (ulong)type.Fields[nameof(ClassDescriptions)].Offset); } public TargetPointer Classes { get; init; } - public TargetPointer ClassDescriptions { get; init; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index abce3154e28719..1943fddd71867c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -4097,7 +4097,10 @@ int ISOSDacInterface10.GetComWrappersCCWData(ClrDataAddress ccw, ClrDataAddress* throw new ArgumentException(); if (managedObject != null) + { + *managedObject = 0; *managedObject = comWrappersContract.GetComWrappersObjectFromMOW(managedObjectPtr).ToClrDataAddress(_target); + } if (refCount != null) *refCount = (int)comWrappersContract.GetMOWReferenceCount(managedObjectPtr); @@ -4140,8 +4143,8 @@ int ISOSDacInterface10.IsComWrappersRCW(ClrDataAddress rcw, Interop.BOOL* isComW { TargetPointer rcwPtr = rcw.ToTargetPointer(_target) & ~_rcwMask; *isComWrappersRCW = comWrappersContract.IsComWrappersRCW(rcwPtr) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; - hr = (*isComWrappersRCW != Interop.BOOL.FALSE) ? HResults.S_OK : HResults.S_FALSE; } + hr = (*isComWrappersRCW != Interop.BOOL.FALSE) ? HResults.S_OK : HResults.S_FALSE; } } catch (System.Exception ex) From 6063efd7904a904b180815fd17140aeca5f52951 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 13 Feb 2026 16:48:03 -0800 Subject: [PATCH 11/23] add local cache --- .../Contracts/RuntimeTypeSystem_1.cs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 2dd0e204168966..2fba7ce86ff55f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -27,6 +27,7 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem private readonly Dictionary _methodTables = new(); private readonly Dictionary _methodDescs = new(); private readonly Dictionary _typeHandles = new(); + private readonly Dictionary _typeHandlesByName = new(); internal struct MethodTable { @@ -98,6 +99,22 @@ public override int GetHashCode() } } + private readonly struct TypeKeyByName : IEquatable + { + public TypeKeyByName(string name, string namespaceName, TargetPointer module) + { + Name = name; + Namespace = namespaceName; + Module = module; + } + public string Name { get; } + public string Namespace { get; } + public TargetPointer Module { get; } + public bool Equals(TypeKeyByName other) => Name == other.Name && Namespace == other.Namespace && Module == other.Module; + public override bool Equals(object? obj) => obj is TypeKeyByName other && Equals(other); + public override int GetHashCode() => HashCode.Combine(Name, Namespace, Module); + } + // Low order bits of TypeHandle address. // If the low bits contain a 2, then it is a TypeDesc [Flags] @@ -831,6 +848,10 @@ private static bool ModuleMatch(AssemblyReference assemblyRef, AssemblyDefinitio TypeHandle IRuntimeTypeSystem.GetTypeByNameAndModule(string name, string nameSpace, ModuleHandle moduleHandle) { + ILoader loader = _target.Contracts.Loader; + TargetPointer modulePtr = loader.GetModule(moduleHandle); + if (_typeHandlesByName.TryGetValue(new TypeKeyByName(name, nameSpace, modulePtr), out TypeHandle existing)) + return existing; string[] parts = name.Split('+'); string outerName = parts[0]; MetadataReader? md = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle); @@ -896,11 +917,14 @@ TypeHandle IRuntimeTypeSystem.GetTypeByNameAndModule(string name, string nameSpa // 3. We have the handle, look up the type handle int token = MetadataTokens.GetToken((EntityHandle)currentHandle); - ILoader loader = _target.Contracts.Loader; TargetPointer typeDefToMethodTable = loader.GetLookupTables(moduleHandle).TypeDefToMethodTable; TargetPointer typeHandlePtr = loader.GetModuleLookupMapElement(typeDefToMethodTable, (uint)token, out _); IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - return (typeHandlePtr == TargetPointer.Null) ? new TypeHandle(TargetPointer.Null) : rts.GetTypeHandle(typeHandlePtr); + if (typeHandlePtr == TargetPointer.Null) + return new TypeHandle(TargetPointer.Null); + TypeHandle foundTypeHandle = rts.GetTypeHandle(typeHandlePtr); + _ = _typeHandlesByName.TryAdd(new TypeKeyByName(name, nameSpace, modulePtr), foundTypeHandle); + return foundTypeHandle; } public bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) From 45483dc94e25f00618c7a76befc6a120743e69bc Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 13 Feb 2026 17:14:57 -0800 Subject: [PATCH 12/23] copilot --- .../Contracts/RuntimeTypeSystem_1.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 2fba7ce86ff55f..fc8e5628905669 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -823,9 +823,16 @@ private static bool ModuleMatch(AssemblyReference assemblyRef, AssemblyDefinitio { AssemblyName assemblyRefName = assemblyRef.GetAssemblyName(); AssemblyName assemblyDefName = assemblyDef.GetAssemblyName(); - return ((assemblyRefName.Name == assemblyDefName.Name) && - (assemblyRefName.Version == assemblyDefName.Version) && - (assemblyRefName.CultureName == assemblyDefName.CultureName)); + if ((assemblyRefName.Name != assemblyDefName.Name) || + (assemblyRefName.Version != assemblyDefName.Version) || + (assemblyRefName.CultureName != assemblyDefName.CultureName)) + { + return false; + } + + ReadOnlySpan refToken = assemblyRefName.GetPublicKeyToken(); + ReadOnlySpan defToken = assemblyDefName.GetPublicKeyToken(); + return refToken.SequenceEqual(defToken); } private MetadataReader? LookForHandle(AssemblyReference exportedAssemblyRef) @@ -912,7 +919,7 @@ TypeHandle IRuntimeTypeSystem.GetTypeByNameAndModule(string name, string nameSpa } } if (!found) - throw new NotImplementedException(); + return new TypeHandle(TargetPointer.Null); } // 3. We have the handle, look up the type handle @@ -923,7 +930,7 @@ TypeHandle IRuntimeTypeSystem.GetTypeByNameAndModule(string name, string nameSpa if (typeHandlePtr == TargetPointer.Null) return new TypeHandle(TargetPointer.Null); TypeHandle foundTypeHandle = rts.GetTypeHandle(typeHandlePtr); - _ = _typeHandlesByName.TryAdd(new TypeKeyByName(name, nameSpace, modulePtr), foundTypeHandle); + _ = _typeHandlesByName.TryAdd(new TypeKeyByName(name, nameSpace, modulePtr), foundTypeHandle); return foundTypeHandle; } From 8b5ffe7e3af3289b5405f70973f4bdc196cf1111 Mon Sep 17 00:00:00 2001 From: Rachel Date: Fri, 13 Feb 2026 17:16:49 -0800 Subject: [PATCH 13/23] Fix comment to remove module from contract lookup --- docs/design/datacontracts/ComWrappers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/datacontracts/ComWrappers.md b/docs/design/datacontracts/ComWrappers.md index c339a2666feba7..e668f8c99ef676 100644 --- a/docs/design/datacontracts/ComWrappers.md +++ b/docs/design/datacontracts/ComWrappers.md @@ -105,7 +105,7 @@ public bool IsComWrappersRCW(TargetPointer rcw) { // Get method table from rcw using Object contract GetMethodTableAddress // Find module from the system assembly - // Then use RuntimeTypeSystem contract to look up type handle by name/namespace/module hardcoded in contract + // Then use RuntimeTypeSystem contract to look up type handle by name/namespace hardcoded in contract // Then compare the rcw method table with the method table found by name/namespace/module } ``` From cc11004b7991c47194f0abc52d0b9ae927dc3ca8 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 18 Feb 2026 10:35:30 -0800 Subject: [PATCH 14/23] arm32 --- src/coreclr/debug/daccess/request.cpp | 4 ++-- .../Contracts/ComWrappers_1.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 1b4527de21b3f8..dd9a1056a042e1 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -4361,8 +4361,8 @@ BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr) return FALSE; } - return (qiAddress == g_knownQueryInterfaceImplementations[0] - || qiAddress == g_knownQueryInterfaceImplementations[1]); + return (PINSTRToPCODE(qiAddress) == g_knownQueryInterfaceImplementations[0] + || PINSTRToPCODE(qiAddress) == g_knownQueryInterfaceImplementations[1]); } TADDR ClrDataAccess::DACGetManagedObjectWrapperFromCCW(CLRDATA_ADDRESS ccwPtr) 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 bd2dbc14978c90..bcd391cf5e81b0 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 @@ -43,8 +43,8 @@ private bool IsComWrappersCCW(TargetPointer ccw) TargetPointer comWrappersVtablePtrs = _target.ReadGlobalPointer(Constants.Globals.ComWrappersVtablePtrs); Data.ComWrappersVtablePtrs comWrappersVtableStruct = _target.ProcessedData.GetOrAdd(comWrappersVtablePtrs); - return qiAddress == comWrappersVtableStruct.MowQueryInterface || - qiAddress == comWrappersVtableStruct.TtQueryInterface; + return CodePointerUtils.CodePointerFromAddress(qiAddress, _target) == comWrappersVtableStruct.MowQueryInterface || + CodePointerUtils.CodePointerFromAddress(qiAddress, _target) == comWrappersVtableStruct.TtQueryInterface; } public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) From 511e86bfa39e011d79b9f00f12e5b1ddc26f3054 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 18 Feb 2026 15:07:36 -0800 Subject: [PATCH 15/23] code review --- docs/design/datacontracts/ComWrappers.md | 5 ++--- src/coreclr/debug/daccess/request.cpp | 10 ++++++++-- src/coreclr/vm/datadescriptor/datadescriptor.inc | 3 +-- src/coreclr/vm/vars.hpp | 5 +++-- .../Contracts/ComWrappers_1.cs | 3 +-- .../Data/ComWrappersVtablePtrs.cs | 11 ++++++----- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/docs/design/datacontracts/ComWrappers.md b/docs/design/datacontracts/ComWrappers.md index e668f8c99ef676..bfe35e9a68421b 100644 --- a/docs/design/datacontracts/ComWrappers.md +++ b/docs/design/datacontracts/ComWrappers.md @@ -25,8 +25,7 @@ Data descriptors used: | `NativeObjectWrapperObject` | `ExternalComObject` | Address of the external COM object | | `ManagedObjectWrapperHolderObject` | `WrappedObject` | Address of the wrapped object | | `ManagedObjectWrapperLayout` | `RefCount` | Reference count of the managed object wrapper | -| `ComWrappersVtablePtrs` | `MowQueryInterface` | Function pointer of ManagedObjectWrapper_QueryInterface | -| `ComWrappersVtablePtrs` | `TtQueryInterface` | Function pointer of TrackerTarget_QueryInterface | +| `ComWrappersVtablePtrs` | `Size` | Number of entries in vtable pointers array | Global variables used: | Global Name | Type | Purpose | @@ -73,7 +72,7 @@ private bool IsComWrappersCCW(TargetPointer ccw) TargetPointer comWrappersVtablePtrs = _target.ReadGlobalPointer("ComWrappersVtablePtrs"); - return /* qiAddress matches either entry in ComWrappersVtablePtrs */ ; + return /* qiAddress matches any entry in ComWrappersVtablePtrs */ ; } public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index dd9a1056a042e1..43e71db313b381 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -4361,8 +4361,14 @@ BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr) return FALSE; } - return (PINSTRToPCODE(qiAddress) == g_knownQueryInterfaceImplementations[0] - || PINSTRToPCODE(qiAddress) == g_knownQueryInterfaceImplementations[1]); + for (int i = 0; i < g_numKnownQueryInterfaceImplementations; i++) + { + if (PINSTRToPCODE(qiAddress) == g_knownQueryInterfaceImplementations[i]) + { + return TRUE; + } + } + return FALSE; } TADDR ClrDataAccess::DACGetManagedObjectWrapperFromCCW(CLRDATA_ADDRESS ccwPtr) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 59be84108bd061..02d4f22e8380fc 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1019,8 +1019,7 @@ CDAC_TYPE_END(DynamicILBlobTable) #ifdef FEATURE_COMWRAPPERS CDAC_TYPE_BEGIN(ComWrappersVtablePtrs) -CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, MowQueryInterface, 0) -CDAC_TYPE_FIELD(ComWrappersVtablePtrs, /*pointer*/, TtQueryInterface, sizeof(uintptr_t)) +CDAC_TYPE_SIZE(g_numKnownQueryInterfaceImplementations) CDAC_TYPE_END(ComWrappersVtablePtrs) #endif diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index 56b3613fe60fb4..e3c065bb9d4710 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -41,15 +41,16 @@ class SyncTableEntry; class ThreadStore; namespace ETW { class CEtwTracer; }; #ifdef FEATURE_COMWRAPPERS +inline constexpr size_t g_numKnownQueryInterfaceImplementations = 2; namespace InteropLib { namespace ABI { struct ComInterfaceDispatch; using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); #ifndef DACCESS_COMPILE - extern QueryInterfaceMethod g_knownQueryInterfaceImplementations[2]; + extern QueryInterfaceMethod g_knownQueryInterfaceImplementations[g_numKnownQueryInterfaceImplementations]; #endif // !DACCESS_COMPILE } } -GARY_DECL(TADDR, g_knownQueryInterfaceImplementations, 2); +GARY_DECL(TADDR, g_knownQueryInterfaceImplementations, g_numKnownQueryInterfaceImplementations); #endif // FEATURE_COMWRAPPERS class DebugInterface; 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 bcd391cf5e81b0..96fec96a4b6f2f 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 @@ -43,8 +43,7 @@ private bool IsComWrappersCCW(TargetPointer ccw) TargetPointer comWrappersVtablePtrs = _target.ReadGlobalPointer(Constants.Globals.ComWrappersVtablePtrs); Data.ComWrappersVtablePtrs comWrappersVtableStruct = _target.ProcessedData.GetOrAdd(comWrappersVtablePtrs); - return CodePointerUtils.CodePointerFromAddress(qiAddress, _target) == comWrappersVtableStruct.MowQueryInterface || - CodePointerUtils.CodePointerFromAddress(qiAddress, _target) == comWrappersVtableStruct.TtQueryInterface; + return comWrappersVtableStruct.ComWrappersInterfacePointers.Contains(new TargetPointer(CodePointerUtils.CodePointerFromAddress(qiAddress, _target))); } public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs index 61bb6f5f1ed26d..8737a645fb0a4c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; namespace Microsoft.Diagnostics.DataContractReader.Data; @@ -11,11 +12,11 @@ internal sealed class ComWrappersVtablePtrs : IData public ComWrappersVtablePtrs(Target target, TargetPointer address) { Target.TypeInfo type = target.GetTypeInfo(DataType.ComWrappersVtablePtrs); - - MowQueryInterface = target.ReadPointer(address + (ulong)type.Fields[nameof(MowQueryInterface)].Offset); - TtQueryInterface = target.ReadPointer(address + (ulong)type.Fields[nameof(TtQueryInterface)].Offset); + for (int i = 0; i < type.Size; i++) + { + ComWrappersInterfacePointers.Add(target.ReadPointer(address + (ulong)(i * target.PointerSize))); + } } - public TargetPointer MowQueryInterface { get; init; } - public TargetPointer TtQueryInterface { get; init; } + public List ComWrappersInterfacePointers { get; init; } = new List(); } From c2852034e4eec8d34f5bf94c776fe48a696c8fe0 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 18 Feb 2026 15:11:54 -0800 Subject: [PATCH 16/23] code review --- .../Contracts/ComWrappers_1.cs | 2 +- .../Data/ComWrappersVtablePtrs.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 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 96fec96a4b6f2f..0b9ce1d310cdff 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 @@ -43,7 +43,7 @@ private bool IsComWrappersCCW(TargetPointer ccw) TargetPointer comWrappersVtablePtrs = _target.ReadGlobalPointer(Constants.Globals.ComWrappersVtablePtrs); Data.ComWrappersVtablePtrs comWrappersVtableStruct = _target.ProcessedData.GetOrAdd(comWrappersVtablePtrs); - return comWrappersVtableStruct.ComWrappersInterfacePointers.Contains(new TargetPointer(CodePointerUtils.CodePointerFromAddress(qiAddress, _target))); + return comWrappersVtableStruct.ComWrappersInterfacePointers.Contains(CodePointerUtils.CodePointerFromAddress(qiAddress, _target)); } public TargetPointer GetManagedObjectWrapperFromCCW(TargetPointer ccw) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs index 8737a645fb0a4c..2fb0c578676da0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs @@ -14,9 +14,9 @@ public ComWrappersVtablePtrs(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.ComWrappersVtablePtrs); for (int i = 0; i < type.Size; i++) { - ComWrappersInterfacePointers.Add(target.ReadPointer(address + (ulong)(i * target.PointerSize))); + ComWrappersInterfacePointers.Add(target.ReadCodePointer(address + (ulong)(i * target.PointerSize))); } } - public List ComWrappersInterfacePointers { get; init; } = new List(); + public List ComWrappersInterfacePointers { get; init; } = new List(); } From 5f2a8467e16adc70ad2cd0705741b816c80eb314 Mon Sep 17 00:00:00 2001 From: Rachel Date: Wed, 18 Feb 2026 16:03:58 -0800 Subject: [PATCH 17/23] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/vm/vars.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index 14eab84eeaa2fb..02e97870b61671 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -95,7 +95,7 @@ GPTR_IMPL(RCWCleanupList,g_pRCWCleanupList); #endif // FEATURE_COMINTEROP #ifdef FEATURE_COMWRAPPERS -GARY_IMPL(TADDR, g_knownQueryInterfaceImplementations, 2); +GARY_IMPL(TADDR, g_knownQueryInterfaceImplementations, g_numKnownQueryInterfaceImplementations); #endif // FEATURE_COMWRAPPERS #ifdef FEATURE_INTEROP_DEBUGGING From 74088bd0ee6ba1125ca1f532f0f4fdcc7b202a3a Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 18 Feb 2026 16:26:51 -0800 Subject: [PATCH 18/23] code review --- docs/design/datacontracts/ComWrappers.md | 2 +- src/coreclr/vm/datadescriptor/datadescriptor.inc | 2 +- .../Data/ComWrappersVtablePtrs.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/design/datacontracts/ComWrappers.md b/docs/design/datacontracts/ComWrappers.md index bfe35e9a68421b..2a83a8044ec5b6 100644 --- a/docs/design/datacontracts/ComWrappers.md +++ b/docs/design/datacontracts/ComWrappers.md @@ -25,7 +25,7 @@ Data descriptors used: | `NativeObjectWrapperObject` | `ExternalComObject` | Address of the external COM object | | `ManagedObjectWrapperHolderObject` | `WrappedObject` | Address of the wrapped object | | `ManagedObjectWrapperLayout` | `RefCount` | Reference count of the managed object wrapper | -| `ComWrappersVtablePtrs` | `Size` | Number of entries in vtable pointers array | +| `ComWrappersVtablePtrs` | `Size` | Size of vtable pointers array | Global variables used: | Global Name | Type | Purpose | diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 02d4f22e8380fc..1e61487e26f921 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1019,7 +1019,7 @@ CDAC_TYPE_END(DynamicILBlobTable) #ifdef FEATURE_COMWRAPPERS CDAC_TYPE_BEGIN(ComWrappersVtablePtrs) -CDAC_TYPE_SIZE(g_numKnownQueryInterfaceImplementations) +CDAC_TYPE_SIZE(g_numKnownQueryInterfaceImplementations * sizeof(PCODE)) CDAC_TYPE_END(ComWrappersVtablePtrs) #endif diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs index 2fb0c578676da0..36826c9baaf2c5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ComWrappersVtablePtrs.cs @@ -12,7 +12,7 @@ internal sealed class ComWrappersVtablePtrs : IData public ComWrappersVtablePtrs(Target target, TargetPointer address) { Target.TypeInfo type = target.GetTypeInfo(DataType.ComWrappersVtablePtrs); - for (int i = 0; i < type.Size; i++) + for (int i = 0; i < type.Size / target.PointerSize; i++) { ComWrappersInterfacePointers.Add(target.ReadCodePointer(address + (ulong)(i * target.PointerSize))); } From d37b470e0497eb39c6af6ea80f52e05e79a5b0de Mon Sep 17 00:00:00 2001 From: Rachel Date: Wed, 18 Feb 2026 16:42:44 -0800 Subject: [PATCH 19/23] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/interop/comwrappers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/interop/comwrappers.cpp b/src/coreclr/interop/comwrappers.cpp index 1fdfe14492e523..22bc55d8cb5196 100644 --- a/src/coreclr/interop/comwrappers.cpp +++ b/src/coreclr/interop/comwrappers.cpp @@ -527,7 +527,7 @@ InteropLib::OBJECTHANDLE ManagedObjectWrapper::GetTarget() const using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); namespace InteropLib { namespace ABI { struct ComInterfaceDispatch; - QueryInterfaceMethod g_knownQueryInterfaceImplementations[2] = { + QueryInterfaceMethod g_knownQueryInterfaceImplementations[g_numKnownQueryInterfaceImplementations] = { &ManagedObjectWrapper_QueryInterface, &TrackerTarget_QueryInterface }; From 3a7d4816c402a31a5b850fabe432463d76b2383b Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 18 Feb 2026 17:30:49 -0800 Subject: [PATCH 20/23] fix --- src/coreclr/interop/comwrappers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/interop/comwrappers.cpp b/src/coreclr/interop/comwrappers.cpp index 22bc55d8cb5196..414fc6670547ea 100644 --- a/src/coreclr/interop/comwrappers.cpp +++ b/src/coreclr/interop/comwrappers.cpp @@ -527,7 +527,7 @@ InteropLib::OBJECTHANDLE ManagedObjectWrapper::GetTarget() const using QueryInterfaceMethod = HRESULT (STDMETHODCALLTYPE *)(InteropLib::ABI::ComInterfaceDispatch*, REFIID, void**); namespace InteropLib { namespace ABI { struct ComInterfaceDispatch; - QueryInterfaceMethod g_knownQueryInterfaceImplementations[g_numKnownQueryInterfaceImplementations] = { + QueryInterfaceMethod g_knownQueryInterfaceImplementations[] = { &ManagedObjectWrapper_QueryInterface, &TrackerTarget_QueryInterface }; From 6ccfea36abdc94a57bc0bc53ba09ec9b606af3a7 Mon Sep 17 00:00:00 2001 From: Rachel Date: Wed, 18 Feb 2026 18:36:42 -0800 Subject: [PATCH 21/23] Change loop variable type from int to size_t --- src/coreclr/debug/daccess/request.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 43e71db313b381..2d71eda3c060cc 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -4361,7 +4361,7 @@ BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr) return FALSE; } - for (int i = 0; i < g_numKnownQueryInterfaceImplementations; i++) + for (size_t i = 0; i < g_numKnownQueryInterfaceImplementations; i++) { if (PINSTRToPCODE(qiAddress) == g_knownQueryInterfaceImplementations[i]) { From 024cf5ae1ba06674dca97636e9c9796f2ad97aca Mon Sep 17 00:00:00 2001 From: Rachel Date: Wed, 18 Feb 2026 19:19:07 -0800 Subject: [PATCH 22/23] Change loop variable type from size_t to unsigned int --- src/coreclr/debug/daccess/request.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 2d71eda3c060cc..6cee27c4adf2d1 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -4361,7 +4361,7 @@ BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr) return FALSE; } - for (size_t i = 0; i < g_numKnownQueryInterfaceImplementations; i++) + for (unsigned int i = 0; i < g_numKnownQueryInterfaceImplementations; i++) { if (PINSTRToPCODE(qiAddress) == g_knownQueryInterfaceImplementations[i]) { From a2c0e6eaa6a0f68fa96c8cba53fd94d361116fa5 Mon Sep 17 00:00:00 2001 From: Rachel Date: Wed, 18 Feb 2026 19:21:18 -0800 Subject: [PATCH 23/23] Update src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../SOSDacImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 1943fddd71867c..58b62628fe68be 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -4175,7 +4175,7 @@ int ISOSDacInterface10.GetComWrappersRCWData(ClrDataAddress rcw, ClrDataAddress* throw new ArgumentException(); else if ((rcw & _rcwMask) == 0) *identity = 0; - else if (identity != null) + else { TargetPointer identityPtr = comWrappersContract.GetComWrappersIdentity(rcw.ToTargetPointer(_target) & ~_rcwMask); *identity = identityPtr.ToClrDataAddress(_target);