From dd568c147fff8764c9e1d764584e619c1a2fe41c Mon Sep 17 00:00:00 2001 From: Tom McDonald Date: Tue, 14 Apr 2026 15:37:15 -0400 Subject: [PATCH 1/2] Fix x86 async frame generic type resolution in DBI CordbAsyncFrame::LoadGenericArgs was using SafeReadStruct to read the generic arg token from the continuation object. CORDB_ADDRESS is ULONG64 (always 8 bytes), but on x86 targets the field is a 4-byte pointer. Reading 8 bytes pulled in adjacent memory, producing garbage pointer values that caused EnumerateTypeParameters to return E_INVALIDARG. Changed to SafeReadStruct which matches the target pointer size (4 bytes on x86, 8 bytes on x64), consistent with how CordbJITILFrame::LoadGenericArgs reads tokens via GetRegisterOrStackValue. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/debug/di/rsthread.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index f32c499371a44f..2a5bca1ea960a5 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -11525,8 +11525,14 @@ void CordbAsyncFrame::LoadGenericArgs() { if (m_asyncVars[i].ilVarNum == genericArgIndex) { - - HRESULT hr = GetProcess()->SafeReadStruct(m_continuationAddress + m_asyncVars[i].offset, &genericTypeParam); + // Read a target-pointer-sized value. CORDB_ADDRESS is always 8 bytes (ULONG64), + // but on x86 targets the generic arg field is only a 4-byte pointer. Using + // SIZE_T (which matches the target pointer size) avoids reading adjacent memory. + // This mirrors how CordbJITILFrame::LoadGenericArgs reads the token via + // GetRegisterOrStackValue (which returns SIZE_T). + SIZE_T rawToken = 0; + HRESULT hr = GetProcess()->SafeReadStruct(m_continuationAddress + m_asyncVars[i].offset, &rawToken); + genericTypeParam = (CORDB_ADDRESS)rawToken; IfFailThrow(hr); break; } From dec1d91102ce650542ce5ef8cb2a28d0c3774a3e Mon Sep 17 00:00:00 2001 From: Tom McDonald Date: Wed, 15 Apr 2026 11:47:07 -0400 Subject: [PATCH 2/2] Update src/coreclr/debug/di/rsthread.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/debug/di/rsthread.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index 2a5bca1ea960a5..15285136229e05 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -11527,9 +11527,9 @@ void CordbAsyncFrame::LoadGenericArgs() { // Read a target-pointer-sized value. CORDB_ADDRESS is always 8 bytes (ULONG64), // but on x86 targets the generic arg field is only a 4-byte pointer. Using - // SIZE_T (which matches the target pointer size) avoids reading adjacent memory. - // This mirrors how CordbJITILFrame::LoadGenericArgs reads the token via - // GetRegisterOrStackValue (which returns SIZE_T). + // SIZE_T (which is pointer-sized for the DBI build, matching the target here) + // avoids reading adjacent memory. This mirrors how CordbJITILFrame::Init() + // reads the raw token via GetRegisterOrStackValue (which returns SIZE_T). SIZE_T rawToken = 0; HRESULT hr = GetProcess()->SafeReadStruct(m_continuationAddress + m_asyncVars[i].offset, &rawToken); genericTypeParam = (CORDB_ADDRESS)rawToken;