From 795b8a06dd5d57a7a6661b024c3d762426e1449c Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Fri, 20 Feb 2026 09:17:07 -0500 Subject: [PATCH 1/5] Fix null eeclass issues --- src/coreclr/debug/daccess/request.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 20bcc4e5e9e178..d433192f5f4871 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -1864,7 +1864,8 @@ ClrDataAccess::GetMethodTableData(CLRDATA_ADDRESS mt, struct DacpMethodTableData { MTData->Module = HOST_CDADDR(pMT->GetModule()); // Note: DacpMethodTableData::Class is really a pointer to the canonical method table - MTData->Class = HOST_CDADDR(pMT->GetClass()->GetMethodTable()); + PTR_EEClass pClass = pMT->GetClassWithPossibleAV(); + MTData->Class = pClass != NULL ? HOST_CDADDR(pClass->GetMethodTable()) : 0; MTData->ParentMethodTable = HOST_CDADDR(pMT->GetParentMethodTable());; MTData->wNumInterfaces = (WORD)pMT->GetNumInterfaces(); MTData->wNumMethods = pMT->GetNumMethods(); // printed as "number of vtable slots" and used to iterate over method slots @@ -2057,6 +2058,10 @@ ClrDataAccess::GetMethodTableFieldData(CLRDATA_ADDRESS mt, struct DacpMethodTabl { hr = E_INVALIDARG; } + else if (pMT->GetClassWithPossibleAV() == NULL) + { + hr = E_INVALIDARG; + } else { data->wNumInstanceFields = pMT->GetNumInstanceFields(); @@ -5653,6 +5658,10 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetThreadStaticBaseAddress(CLRDATA_ADDR { hr = E_INVALIDARG; } + else if (mTable->GetClassWithPossibleAV() == NULL) + { + hr = E_INVALIDARG; + } else { if (mTable->GetClass()->GetNumThreadStaticFields() == 0) From dff13a7c4f32a4e3c805ef816ca71031316410c4 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Fri, 20 Feb 2026 16:21:10 -0500 Subject: [PATCH 2/5] Fix 12 DAC crashes and 4 shadowed HRESULT bugs in request.cpp Crash fixes (all SIGSEGV on Linux): - GetAppDomainName(0): add null address check - TraverseModuleMap: add null callback check - TraverseVirtCallStubHeap: add null callback check - GetRegisterName: replace wcscpy_s with bounded memcpy to prevent buffer overflow - GetPendingReJITID/GetReJITInformation/GetProfilerModifiedILInformation: add DacValidateMD - GetMethodsWithProfilerModifiedIL: add module address -1 check - GetFinalizationFillPointersSvr: validate heap address against known server GC heaps - GetAssemblyLoadContext: add DacValidateMethodTable Shadowed HRESULT fixes: - GetGenerationTable, GetFinalizationFillPointers, GetGenerationTableSvr, GetFinalizationFillPointersSvr, GetObjectComWrappersData all declared a local HRESULT hr that shadowed the one from SOSDacEnter(), causing the return after SOSDacLeave() to always return S_OK regardless of errors. Contributes to: dotnet/runtime#124640 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/debug/daccess/request.cpp | 170 +++++++++++++++++--------- 1 file changed, 113 insertions(+), 57 deletions(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index d433192f5f4871..2688e07c8bb4a1 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -707,29 +707,31 @@ ClrDataAccess::GetRegisterName(int regNum, unsigned int count, _Inout_updates_z_ if (buffer) { + if (count == 0) + return S_FALSE; + WCHAR* curr = buffer; - WCHAR* end = buffer + count; - unsigned int destSize = count; - if (curr < end && callerFrame) - { - unsigned int toCopy = prefixLen < destSize ? prefixLen : destSize; - wcscpy_s(curr, toCopy, callerPrefix); - // Point to null terminator - toCopy--; + unsigned int remaining = count; + if (callerFrame && remaining > 1) + { + unsigned int srcLen = prefixLen - 1; // exclude null + unsigned int toCopy = srcLen < (remaining - 1) ? srcLen : (remaining - 1); + memcpy(curr, callerPrefix, toCopy * sizeof(WCHAR)); curr += toCopy; - destSize -= toCopy; + remaining -= toCopy; } - if (curr < end) + if (remaining > 1) { - unsigned int toCopy = regLen < destSize ? regLen : destSize; - wcscpy_s(curr, toCopy, regs[regNum]); - // Point to null terminator - toCopy--; + unsigned int srcLen = regLen - 1; // exclude null + unsigned int toCopy = srcLen < (remaining - 1) ? srcLen : (remaining - 1); + memcpy(curr, regs[regNum], toCopy * sizeof(WCHAR)); curr += toCopy; - destSize -= toCopy; } + // Always null-terminate + *curr = W('\0'); + if (count < needed) return S_FALSE; } @@ -1707,7 +1709,7 @@ ClrDataAccess::GetMethodDescFromToken(CLRDATA_ADDRESS moduleAddr, mdToken token, HRESULT ClrDataAccess::TraverseModuleMap(ModuleMapType mmt, CLRDATA_ADDRESS moduleAddr, MODULEMAPTRAVERSE pCallback, LPVOID token) { - if (moduleAddr == 0) + if (moduleAddr == 0 || pCallback == NULL) return E_INVALIDARG; SOSDacEnter(); @@ -2625,6 +2627,9 @@ ClrDataAccess::GetFailedAssemblyList(CLRDATA_ADDRESS appDomain, int count, HRESULT ClrDataAccess::GetAppDomainName(CLRDATA_ADDRESS addr, unsigned int count, _Inout_updates_z_(count) WCHAR *name, unsigned int *pNeeded) { + if (addr == 0) + return E_INVALIDARG; + SOSDacEnter(); if (addr == HOST_CDADDR(SystemDomain::System())) @@ -3620,7 +3625,7 @@ ClrDataAccess::TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind HRESULT ClrDataAccess::TraverseVirtCallStubHeap(CLRDATA_ADDRESS pAppDomain, VCSHeapType heaptype, VISITHEAP pFunc) { - if (pAppDomain == 0) + if (pAppDomain == 0 || pFunc == NULL) return E_INVALIDARG; SOSDacEnter(); @@ -4684,17 +4689,24 @@ HRESULT ClrDataAccess::GetPendingReJITID(CLRDATA_ADDRESS methodDesc, int *pRejit #ifdef FEATURE_CODE_VERSIONING PTR_MethodDesc pMD = PTR_MethodDesc(TO_TADDR(methodDesc)); - CodeVersionManager* pCodeVersionManager = pMD->GetCodeVersionManager(); - CodeVersionManager::LockHolder codeVersioningLockHolder; - ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(pMD); - if (ilVersion.IsNull()) + if (!DacValidateMD(pMD)) { hr = E_INVALIDARG; } - else if (ilVersion.GetRejitState() == RejitFlags::kStateRequested) + else { - *pRejitId = (int)ilVersion.GetVersionId(); - hr = S_OK; + CodeVersionManager* pCodeVersionManager = pMD->GetCodeVersionManager(); + CodeVersionManager::LockHolder codeVersioningLockHolder; + ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(pMD); + if (ilVersion.IsNull()) + { + hr = E_INVALIDARG; + } + else if (ilVersion.GetRejitState() == RejitFlags::kStateRequested) + { + *pRejitId = (int)ilVersion.GetVersionId(); + hr = S_OK; + } } #endif // FEATURE_CODE_VERSIONING SOSDacLeave(); @@ -4712,6 +4724,12 @@ HRESULT ClrDataAccess::GetReJITInformation(CLRDATA_ADDRESS methodDesc, int rejit SOSDacEnter(); PTR_MethodDesc pMD = PTR_MethodDesc(TO_TADDR(methodDesc)); + if (!DacValidateMD(pMD)) + { + hr = E_INVALIDARG; + } + else + { #ifdef FEATURE_CODE_VERSIONING CodeVersionManager* pCodeVersionManager = pMD->GetCodeVersionManager(); CodeVersionManager::LockHolder codeVersioningLockHolder; @@ -4750,6 +4768,7 @@ HRESULT ClrDataAccess::GetReJITInformation(CLRDATA_ADDRESS methodDesc, int rejit pReJitData->il = HOST_CDADDR(pMD->GetILHeader()); pReJitData->ilCodeVersionNodePtr = 0; #endif // FEATURE_CODE_VERSIONING + } SOSDacLeave(); @@ -4771,22 +4790,29 @@ HRESULT ClrDataAccess::GetProfilerModifiedILInformation(CLRDATA_ADDRESS methodDe pILData->il = (CLRDATA_ADDRESS)NULL; PTR_MethodDesc pMD = PTR_MethodDesc(TO_TADDR(methodDesc)); -#ifdef FEATURE_CODE_VERSIONING - CodeVersionManager* pCodeVersionManager = pMD->GetCodeVersionManager(); - CodeVersionManager::LockHolder codeVersioningLockHolder; - ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(pMD); - if (ilVersion.GetRejitState() != RejitFlags::kStateActive || !ilVersion.HasDefaultIL()) + if (!DacValidateMD(pMD)) { - pILData->type = DacpProfilerILData::ReJITModified; - pILData->rejitID = static_cast(pCodeVersionManager->GetActiveILCodeVersion(pMD).GetVersionId()); + hr = E_INVALIDARG; } + else + { +#ifdef FEATURE_CODE_VERSIONING + CodeVersionManager* pCodeVersionManager = pMD->GetCodeVersionManager(); + CodeVersionManager::LockHolder codeVersioningLockHolder; + ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(pMD); + if (ilVersion.GetRejitState() != RejitFlags::kStateActive || !ilVersion.HasDefaultIL()) + { + pILData->type = DacpProfilerILData::ReJITModified; + pILData->rejitID = static_cast(pCodeVersionManager->GetActiveILCodeVersion(pMD).GetVersionId()); + } #endif // FEATURE_CODE_VERSIONING - TADDR pDynamicIL = pMD->GetModule()->GetDynamicIL(pMD->GetMemberDef()); - if (pDynamicIL != (TADDR)NULL) - { - pILData->type = DacpProfilerILData::ILModified; - pILData->il = (CLRDATA_ADDRESS)pDynamicIL; + TADDR pDynamicIL = pMD->GetModule()->GetDynamicIL(pMD->GetMemberDef()); + if (pDynamicIL != (TADDR)NULL) + { + pILData->type = DacpProfilerILData::ILModified; + pILData->il = (CLRDATA_ADDRESS)pDynamicIL; + } } SOSDacLeave(); @@ -4807,6 +4833,12 @@ HRESULT ClrDataAccess::GetMethodsWithProfilerModifiedIL(CLRDATA_ADDRESS mod, CLR #ifdef FEATURE_CODE_VERSIONING PTR_Module pModule = PTR_Module(TO_TADDR(mod)); + if (dac_cast(pModule) == (TADDR)-1) + { + hr = E_INVALIDARG; + } + else + { CodeVersionManager* pCodeVersionManager = pModule->GetCodeVersionManager(); CodeVersionManager::LockHolder codeVersioningLockHolder; @@ -4840,6 +4872,7 @@ HRESULT ClrDataAccess::GetMethodsWithProfilerModifiedIL(CLRDATA_ADDRESS mod, CLR } } } + } #endif // FEATURE_CODE_VERSIONING SOSDacLeave(); @@ -4870,7 +4903,6 @@ HRESULT ClrDataAccess::GetGenerationTable(unsigned int cGenerations, struct Dacp SOSDacEnter(); - HRESULT hr = S_OK; unsigned int numGenerationTableEntries = (unsigned int)(g_gcDacGlobals->total_generation_count); if (pNeeded != NULL) { @@ -4916,7 +4948,6 @@ HRESULT ClrDataAccess::GetFinalizationFillPointers(unsigned int cFillPointers, C SOSDacEnter(); - HRESULT hr = S_OK; unsigned int numFillPointers = (unsigned int)(g_gcDacGlobals->total_generation_count + dac_finalize_queue::ExtraSegCount); if (pNeeded != NULL) { @@ -4957,7 +4988,6 @@ HRESULT ClrDataAccess::GetGenerationTableSvr(CLRDATA_ADDRESS heapAddr, unsigned SOSDacEnter(); - HRESULT hr = S_OK; #ifdef FEATURE_SVR_GC unsigned int numGenerationTableEntries = (unsigned int)(g_gcDacGlobals->total_generation_count); if (pNeeded != NULL) @@ -5007,7 +5037,6 @@ HRESULT ClrDataAccess::GetFinalizationFillPointersSvr(CLRDATA_ADDRESS heapAddr, SOSDacEnter(); - HRESULT hr = S_OK; #ifdef FEATURE_SVR_GC unsigned int numFillPointers = (unsigned int)(g_gcDacGlobals->total_generation_count + dac_finalize_queue::ExtraSegCount); if (pNeeded != NULL) @@ -5024,13 +5053,32 @@ HRESULT ClrDataAccess::GetFinalizationFillPointersSvr(CLRDATA_ADDRESS heapAddr, TADDR heapAddress = TO_TADDR(heapAddr); if (heapAddress != 0) { - dac_gc_heap heap = LoadGcHeapData(heapAddress); - dac_gc_heap* pHeap = &heap; - DPTR(dac_finalize_queue) fq = pHeap->finalize_queue; - DPTR(uint8_t*) pFillPointerArray= dac_cast(fq) + offsetof(dac_finalize_queue, m_FillPointers); - for (unsigned int i = 0; i < numFillPointers; ++i) + // Validate that heapAddr is a known server GC heap address + bool validHeap = false; + int heapCount = GCHeapCount(); + for (int i = 0; i < heapCount; i++) { - pFinalizationFillPointers[i] = (CLRDATA_ADDRESS) pFillPointerArray[i]; + if (heapAddress == HeapTableIndex(g_gcDacGlobals->g_heaps, i)) + { + validHeap = true; + break; + } + } + + if (!validHeap) + { + hr = E_INVALIDARG; + } + else + { + dac_gc_heap heap = LoadGcHeapData(heapAddress); + dac_gc_heap* pHeap = &heap; + DPTR(dac_finalize_queue) fq = pHeap->finalize_queue; + DPTR(uint8_t*) pFillPointerArray= dac_cast(fq) + offsetof(dac_finalize_queue, m_FillPointers); + for (unsigned int i = 0; i < numFillPointers; ++i) + { + pFinalizationFillPointers[i] = (CLRDATA_ADDRESS) pFillPointerArray[i]; + } } } else @@ -5053,20 +5101,28 @@ HRESULT ClrDataAccess::GetAssemblyLoadContext(CLRDATA_ADDRESS methodTable, CLRDA SOSDacEnter(); PTR_MethodTable pMT = PTR_MethodTable(CLRDATA_ADDRESS_TO_TADDR(methodTable)); - PTR_Module pModule = pMT->GetModule(); + BOOL bIsFree; + if (!DacValidateMethodTable(pMT, bIsFree)) + { + hr = E_INVALIDARG; + } + else + { + PTR_Module pModule = pMT->GetModule(); - PTR_PEAssembly pPEAssembly = pModule->GetPEAssembly(); - PTR_AssemblyBinder pBinder = pPEAssembly->GetAssemblyBinder(); + PTR_PEAssembly pPEAssembly = pModule->GetPEAssembly(); + PTR_AssemblyBinder pBinder = pPEAssembly->GetAssemblyBinder(); - INT_PTR AssemblyLoadContextHandle = pBinder->GetAssemblyLoadContext(); + INT_PTR AssemblyLoadContextHandle = pBinder->GetAssemblyLoadContext(); - TADDR AssemblyLoadContextAddr = 0; - if (AssemblyLoadContextHandle != 0) - { - DacReadAll(AssemblyLoadContextHandle,&AssemblyLoadContextAddr,sizeof(TADDR),true); - } + TADDR AssemblyLoadContextAddr = 0; + if (AssemblyLoadContextHandle != 0) + { + DacReadAll(AssemblyLoadContextHandle,&AssemblyLoadContextAddr,sizeof(TADDR),true); + } - *assemblyLoadContext = TO_CDADDR(AssemblyLoadContextAddr); + *assemblyLoadContext = TO_CDADDR(AssemblyLoadContextAddr); + } SOSDacLeave(); return hr; @@ -5157,7 +5213,7 @@ HRESULT ClrDataAccess::GetObjectComWrappersData(CLRDATA_ADDRESS objAddr, CLRDATA SOSDacEnter(); // Default to having found no information. - HRESULT hr = S_FALSE; + hr = S_FALSE; if (pNeeded != NULL) { From 52544a8edb523c91b1b634374143db29aacedce1 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Fri, 20 Feb 2026 16:36:24 -0500 Subject: [PATCH 3/5] Forward-proof RequestGlobal against future MAX_GLOBAL_GC_MECHANISMS_COUNT growth Over-allocate the buffer passed to GetGCGlobalMechanisms to 256 entries so that a newer runtime writing more than 6 entries won't overflow the caller's stack. Only copy back DAC_MAX_GLOBAL_GC_MECHANISMS_COUNT elements into the struct. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/debug/daccess/request.cpp | 20 ++++++++++++-------- src/coreclr/inc/dacprivate.h | 12 +++++++++++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 2688e07c8bb4a1..11fcc36c1b9775 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -120,7 +120,7 @@ BOOL DacValidateEEClass(PTR_EEClass pEEClass) // PREfix. retval = FALSE; } - else if (pEEClass != pMethodTable->GetClass()) + else if (pEEClass != pMethodTable->GetClassWithPossibleAV()) { retval = FALSE; } @@ -698,7 +698,7 @@ ClrDataAccess::GetRegisterName(int regNum, unsigned int count, _Inout_updates_z_ return E_UNEXPECTED; const WCHAR callerPrefix[] = W("caller."); - // Include null terminator in prefixLen/regLen because wcscpy_s will fail otherwise + // Include null terminator in prefixLen/regLen for the 'needed' count unsigned int prefixLen = (unsigned int)ARRAY_SIZE(callerPrefix); unsigned int regLen = (unsigned int)u16_strlen(regs[regNum]) + 1; unsigned int needed = (callerFrame ? prefixLen - 1 : 0) + regLen; @@ -2066,11 +2066,12 @@ ClrDataAccess::GetMethodTableFieldData(CLRDATA_ADDRESS mt, struct DacpMethodTabl } else { - data->wNumInstanceFields = pMT->GetNumInstanceFields(); - data->wNumStaticFields = pMT->GetNumStaticFields(); - data->wNumThreadStaticFields = pMT->GetNumThreadStaticFields(); + PTR_EEClass pClass = pMT->GetClassWithPossibleAV(); + data->wNumInstanceFields = pClass->GetNumInstanceFields(); + data->wNumStaticFields = pClass->GetNumStaticFields(); + data->wNumThreadStaticFields = pClass->GetNumThreadStaticFields(); - data->FirstField = PTR_TO_TADDR(pMT->GetClass()->GetFieldDescList()); + data->FirstField = PTR_TO_TADDR(pClass->GetFieldDescList()); data->wContextStaticsSize = 0; data->wContextStaticOffset = 0; @@ -5074,7 +5075,7 @@ HRESULT ClrDataAccess::GetFinalizationFillPointersSvr(CLRDATA_ADDRESS heapAddr, dac_gc_heap heap = LoadGcHeapData(heapAddress); dac_gc_heap* pHeap = &heap; DPTR(dac_finalize_queue) fq = pHeap->finalize_queue; - DPTR(uint8_t*) pFillPointerArray= dac_cast(fq) + offsetof(dac_finalize_queue, m_FillPointers); + DPTR(uint8_t*) pFillPointerArray = dac_cast(fq) + offsetof(dac_finalize_queue, m_FillPointers); for (unsigned int i = 0; i < numFillPointers; ++i) { pFinalizationFillPointers[i] = (CLRDATA_ADDRESS) pFillPointerArray[i]; @@ -5099,6 +5100,8 @@ HRESULT ClrDataAccess::GetAssemblyLoadContext(CLRDATA_ADDRESS methodTable, CLRDA if (methodTable == 0 || assemblyLoadContext == NULL) return E_INVALIDARG; + *assemblyLoadContext = 0; + SOSDacEnter(); PTR_MethodTable pMT = PTR_MethodTable(CLRDATA_ADDRESS_TO_TADDR(methodTable)); BOOL bIsFree; @@ -5720,7 +5723,8 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetThreadStaticBaseAddress(CLRDATA_ADDR } else { - if (mTable->GetClass()->GetNumThreadStaticFields() == 0) + PTR_EEClass pClass = mTable->GetClassWithPossibleAV(); + if (pClass->GetNumThreadStaticFields() == 0) { if (GCStaticsAddress != NULL) { diff --git a/src/coreclr/inc/dacprivate.h b/src/coreclr/inc/dacprivate.h index 95209e0d03ead9..8734f49cfe05f9 100644 --- a/src/coreclr/inc/dacprivate.h +++ b/src/coreclr/inc/dacprivate.h @@ -857,7 +857,17 @@ struct MSLAYOUT DacpGCInterestingInfoData ISOSDacInterface3 *psos3 = NULL; if (SUCCEEDED(hr = sos->QueryInterface(__uuidof(ISOSDacInterface3), (void**) &psos3))) { - hr = psos3->GetGCGlobalMechanisms(globalMechanisms); + // GetGCGlobalMechanisms writes MAX_GLOBAL_GC_MECHANISMS_COUNT entries (currently 6) + // into the provided buffer with no count parameter. Over-allocate so that a newer + // runtime writing more entries won't overflow our buffer. We only read back + // DAC_MAX_GLOBAL_GC_MECHANISMS_COUNT elements into globalMechanisms. + size_t buffer[256] = {}; + hr = psos3->GetGCGlobalMechanisms(buffer); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < DAC_MAX_GLOBAL_GC_MECHANISMS_COUNT; i++) + globalMechanisms[i] = buffer[i]; + } psos3->Release(); } return hr; From aacec8ed7fd0b33ca717538e86e2138e295fe974 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Sat, 21 Feb 2026 13:37:08 -0500 Subject: [PATCH 4/5] Code review feedback --- src/coreclr/debug/daccess/request.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 11fcc36c1b9775..769a690298ec11 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -1866,8 +1866,7 @@ ClrDataAccess::GetMethodTableData(CLRDATA_ADDRESS mt, struct DacpMethodTableData { MTData->Module = HOST_CDADDR(pMT->GetModule()); // Note: DacpMethodTableData::Class is really a pointer to the canonical method table - PTR_EEClass pClass = pMT->GetClassWithPossibleAV(); - MTData->Class = pClass != NULL ? HOST_CDADDR(pClass->GetMethodTable()) : 0; + MTData->Class = HOST_CDADDR(pMT->GetClass()->GetMethodTable()); MTData->ParentMethodTable = HOST_CDADDR(pMT->GetParentMethodTable());; MTData->wNumInterfaces = (WORD)pMT->GetNumInterfaces(); MTData->wNumMethods = pMT->GetNumMethods(); // printed as "number of vtable slots" and used to iterate over method slots @@ -2060,7 +2059,7 @@ ClrDataAccess::GetMethodTableFieldData(CLRDATA_ADDRESS mt, struct DacpMethodTabl { hr = E_INVALIDARG; } - else if (pMT->GetClassWithPossibleAV() == NULL) + else if (pMT->GetClass() == NULL) { hr = E_INVALIDARG; } @@ -5717,7 +5716,7 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetThreadStaticBaseAddress(CLRDATA_ADDR { hr = E_INVALIDARG; } - else if (mTable->GetClassWithPossibleAV() == NULL) + else if (mTable->GetClass() == NULL) { hr = E_INVALIDARG; } From d915be5db2c464256b02b46d9b04469c248a05cb Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Sat, 21 Feb 2026 14:16:14 -0500 Subject: [PATCH 5/5] Update src/coreclr/debug/daccess/request.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/debug/daccess/request.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 769a690298ec11..fa0c77250f0795 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -5716,10 +5716,6 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetThreadStaticBaseAddress(CLRDATA_ADDR { hr = E_INVALIDARG; } - else if (mTable->GetClass() == NULL) - { - hr = E_INVALIDARG; - } else { PTR_EEClass pClass = mTable->GetClassWithPossibleAV();