Summary
RuntimeTypeSystem_1.GetConstructedType fails to find pointer TypeDescs (e.g., int*) when the TypeDesc lives in a different module than the element type's loader module. This causes ClrDataFrame to return DEFAULT flags for pointer variables instead of IS_POINTER.
Root Cause
GetConstructedType searches only the loader module's AvailableTypeParams hash table:
- For
int*, GetLoaderModule(int) returns CoreLib
- The search iterates CoreLib's
AvailableTypeParams via GetAvailableTypeParams(CoreLib)
- If the
int* TypeDesc was allocated in the debuggee's module (not CoreLib), it won't be found
The native runtime uses ComputeLoaderModule(TypeKey) -> LookupInLoaderModule -> EETypeHashTable::GetValue(TypeKey*) which performs a hash-based lookup in the computed loader module. The native DAC can find the TypeDesc because it traverses the actual runtime type system data structures.
Affected Code
- cDAC:
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs GetConstructedType method (line ~851)
- Consumer:
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs CreateValueFromDebugInfo (line ~500)
- Native reference:
src/coreclr/vm/clsload.cpp ClassLoader::LoadConstructedTypeThrowing / LookupInLoaderModule
The TODO is in ClrDataFrame.cs:
// TODO: Implement cross-module TypeDesc search in GetConstructedType
// so that pointer types (ELEMENT_TYPE_PTR) can be resolved even when
// their TypeDesc lives in a different module than the element type.
valueFlags = (uint)ClrDataValueFlag.DEFAULT;
Possible Approaches
- Implement
ComputeLoaderModule logic in the cDAC to match the native runtime's module computation, ensuring the correct module is searched
- Search multiple modules if the loader module search fails (fallback to searching all loaded modules'
AvailableTypeParams)
- Use hash-based lookup instead of linear scan in
GetAvailableTypeParams if the EETypeHashTable structure supports key-based queries from the cDAC
Impact
Pointer variable arguments (int*, char*, etc.) in stack frames will have DEFAULT (0x0) flags instead of IS_POINTER (0x00040000). This affects diagnostic tools that inspect variable types via IXCLRDataValue::GetFlags. Function pointers (delegate*) are not affected because the cDAC maps FNPTR to IntPtr (matching native DAC behavior).
/cc @max-charlamb
Summary
RuntimeTypeSystem_1.GetConstructedTypefails to find pointer TypeDescs (e.g.,int*) when the TypeDesc lives in a different module than the element type's loader module. This causesClrDataFrameto returnDEFAULTflags for pointer variables instead ofIS_POINTER.Root Cause
GetConstructedTypesearches only the loader module'sAvailableTypeParamshash table:int*,GetLoaderModule(int)returns CoreLibAvailableTypeParamsviaGetAvailableTypeParams(CoreLib)int*TypeDesc was allocated in the debuggee's module (not CoreLib), it won't be foundThe native runtime uses
ComputeLoaderModule(TypeKey)->LookupInLoaderModule->EETypeHashTable::GetValue(TypeKey*)which performs a hash-based lookup in the computed loader module. The native DAC can find the TypeDesc because it traverses the actual runtime type system data structures.Affected Code
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.csGetConstructedTypemethod (line ~851)src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.csCreateValueFromDebugInfo(line ~500)src/coreclr/vm/clsload.cppClassLoader::LoadConstructedTypeThrowing/LookupInLoaderModuleThe TODO is in ClrDataFrame.cs:
Possible Approaches
ComputeLoaderModulelogic in the cDAC to match the native runtime's module computation, ensuring the correct module is searchedAvailableTypeParams)GetAvailableTypeParamsif theEETypeHashTablestructure supports key-based queries from the cDACImpact
Pointer variable arguments (
int*,char*, etc.) in stack frames will haveDEFAULT(0x0) flags instead ofIS_POINTER(0x00040000). This affects diagnostic tools that inspect variable types viaIXCLRDataValue::GetFlags. Function pointers (delegate*) are not affected because the cDAC maps FNPTR to IntPtr (matching native DAC behavior)./cc @max-charlamb