Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 5.6k
GCRoot: Report GCFrame and in-flight exception objects#129145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
1faf644d6871bb309ca5fb558f00f2284035d7d6fc04011ec360eeaed0dfd024c234eb51db504c28765d23a1008a8999b4ff6667b190cfef0d273a4b9db5672d39b2787a13570e0fa71d4bc353281d9483aed379f586157File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -76,7 +76,7 @@ struct StackRef | ||
| CLRDATA_ADDRESS Object; // The object pointer value | ||
| unsigned int Flags; // SOSRefFlags (interior, pinned) | ||
| CLRDATA_ADDRESS Source; // IP or Frame that owns this ref | ||
| int SourceType; // SOS_StackSourceIPor SOS_StackSourceFrame | ||
| int SourceType; // SOS_StackSourceIP, SOS_StackSourceFrame, or SOS_StackSourceOther | ||
| int Register; // Processor-encoding reg number, -1 for stack slots | ||
| // (cDAC populates from GcInfo; runtime populates | ||
| // by inverting GetRegisterSlot on supported arches) | ||
| @@ -721,7 +721,7 @@ static HRESULT CollectRuntimeStackRefs(Thread* pThread, PCONTEXT regs, SArray<St | ||
| collectCtx.refs = outRefs; | ||
| collectCtx.overflow = false; | ||
| collectCtx.currentFrameSource = 0; | ||
| collectCtx.currentFrameSourceType = 0; | ||
| collectCtx.currentFrameSourceType = SOS_StackSourceIP; | ||
| collectCtx.currentRegDisplay = nullptr; | ||
| GCCONTEXT gcctx = {}; | ||
| @@ -780,7 +780,7 @@ static HRESULT CollectRuntimeStackRefs(Thread* pThread, PCONTEXT regs, SArray<St | ||
| // safepoint (matches DAC SOS_StackSourceIP convention). | ||
| collectCtx->currentFrameSource = | ||
| (CLRDATA_ADDRESS)PCODEToPINSTR(GetControlPC(pCF->GetRegisterSet())); | ||
| collectCtx->currentFrameSourceType = 0; // SOS_StackSourceIP | ||
| collectCtx->currentFrameSourceType = SOS_StackSourceIP; | ||
| collectCtx->currentRegDisplay = pCF->GetRegisterSet(); | ||
| ICodeManager* pCM = pCF->GetCodeManager(); | ||
| @@ -801,7 +801,7 @@ static HRESULT CollectRuntimeStackRefs(Thread* pThread, PCONTEXT regs, SArray<St | ||
| // emit register-resident refs, so leave currentRegDisplay null. | ||
| Frame* pFrame = pCF->GetFrame(); | ||
| collectCtx->currentFrameSource = (CLRDATA_ADDRESS)dac_cast<TADDR>(pFrame); | ||
| collectCtx->currentFrameSourceType = 1; // SOS_StackSourceFrame | ||
| collectCtx->currentFrameSourceType = SOS_StackSourceFrame; | ||
| pFrame->GcScanRoots(gcctx->f, gcctx->sc); | ||
| } | ||
| @@ -812,10 +812,36 @@ static HRESULT CollectRuntimeStackRefs(Thread* pThread, PCONTEXT regs, SArray<St | ||
| pThread->StackWalkFrames(dacLikeCallback, &diagCtx, flagsStackWalk); | ||
| // NOTE: ScanStackRoots also scans the separate GCFrame linked list | ||
| // (Thread::GetGCFrame), but the DAC's GetStackReferences / DacStackReferenceWalker | ||
| // does NOT include those. We intentionally omit GCFrame scanning here so our | ||
| // runtime-side collection matches what the cDAC is expected to produce. | ||
| // ScanStackRoots also scans two root sets that are not part of the frame walk: the | ||
| // GCFrame (GCPROTECT) chain and the in-flight ExInfo chain. GetStackReferences reports | ||
| // both, so mirror them here to keep the runtime-side collection in parity. See | ||
| // ScanStackRoots in gcenv.ee.cpp. | ||
| GCFrame* pGCFrame = pThread->GetGCFrame(); | ||
| while (pGCFrame != nullptr) | ||
| { | ||
| // A GCFrame node is a separate chain from the explicit Frame chain, so it is not a | ||
| // capital-F Frame. Report it with the Other source type and the GCFrame node address as | ||
| // the Source, matching cDAC (GcScanContext stamps Source = GCFrame node, SourceType = Other). | ||
| collectCtx.currentFrameSource = (CLRDATA_ADDRESS)dac_cast<TADDR>(pGCFrame); | ||
| collectCtx.currentFrameSourceType = SOS_StackSourceOther; | ||
| collectCtx.currentRegDisplay = nullptr; | ||
| pGCFrame->GcScanRoots(gcctx.f, gcctx.sc); | ||
| pGCFrame = pGCFrame->PtrNextFrame(); | ||
leculver marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| PTR_ExInfo pExInfo = pThread->GetExceptionState()->GetCurrentExceptionTracker(); | ||
| while (pExInfo != NULL) | ||
| { | ||
| // The ExInfo is not a Frame either; GetStackReferences surfaces the in-flight exception | ||
| // object with the Other source type and the ExInfo node address as the Source, the same | ||
| // way it reports a GCFrame root. Mirror that here so the runtime-side collection matches cDAC. | ||
| collectCtx.currentFrameSource = (CLRDATA_ADDRESS)dac_cast<TADDR>(pExInfo); | ||
| collectCtx.currentFrameSourceType = SOS_StackSourceOther; | ||
| collectCtx.currentRegDisplay = nullptr; | ||
| PTR_PTR_Object pRef = dac_cast<PTR_PTR_Object>(&pExInfo->m_exception); | ||
| gcctx.f(pRef, gcctx.sc, 0); | ||
| pExInfo = pExInfo->GetPreviousExceptionTracker(); | ||
| } | ||
| return collectCtx.overflow ? S_FALSE : S_OK; | ||
| } | ||
| @@ -867,7 +893,7 @@ static void ReportMismatch(const char* message, Thread* pThread, PCONTEXT regs) | ||
| struct FrameRefGroup | ||
| { | ||
| CLRDATA_ADDRESS Source; | ||
| int SourceType; // 0 = IP, 1 = Frame | ||
| int SourceType; // 0 = IP, 1 = Frame, 2 = Other | ||
| int StartIdx; // Index into the original ref array | ||
| int Count; // Number of refs in this group | ||
| }; | ||
| @@ -1624,7 +1650,15 @@ static void ResolveMethodName(CLRDATA_ADDRESS source, int sourceType, char* buf, | ||
| if (bufLen <= 0) | ||
| return; | ||
| if (sourceType != 0) // SOS_StackSourceFrame | ||
| if (sourceType == SOS_StackSourceOther) | ||
| { | ||
| // A root reported outside the frame walk (GCFrame/GCPROTECT or ExInfo chain). Source is a | ||
| // node address, not a capital-F Frame, so do not dereference it as a Frame*. | ||
| snprintf(buf, bufLen, "<other 0x%llx>", (unsigned long long)source); | ||
| return; | ||
| } | ||
| if (sourceType == SOS_StackSourceFrame) | ||
| { | ||
| Frame* pFrame = reinterpret_cast<Frame*>(source); | ||
| LPCSTR typeName = Frame::GetFrameTypeName(pFrame->GetFrameIdentifier()); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1185,28 +1185,29 @@ GCFrame::~GCFrame() | ||
| NOTHROW; | ||
| GC_NOTRIGGER; | ||
| MODE_ANY; | ||
| PRECONDITION(m_pCurThread != NULL); | ||
| } | ||
| CONTRACTL_END; | ||
| // m_pNext is NULL when the frame was already popped from the stack. | ||
| if (m_Next != NULL) | ||
| // Normally the destructor performs the pop for a GCPROTECT_BEGIN/END scope, so the frame is | ||
| // still linked when we get here. If it was already popped explicitly - by PopExplicitFrames | ||
| // during EH unwind, or by the interpreter's GCReporting::Unregister - then m_pCurThread is | ||
| // NULL and there is nothing left to do. | ||
| if (m_pCurThread != NULL) | ||
| { | ||
| // This is a GCFrame that was not popped. This is a problem. | ||
| // We should have popped it before we destruct | ||
| // Do a manual switch to the GC cooperative mode instead of using the GCX_COOP_THREAD_EXISTS | ||
| // macro so that this function isn't slowed down by having to deal with FS:0 chain on x86 Windows. | ||
| BOOL wasCoop = m_pCurThread->PreemptiveGCDisabled(); | ||
| Thread *pThread = m_pCurThread; | ||
| BOOL wasCoop = pThread->PreemptiveGCDisabled(); | ||
| if (!wasCoop) | ||
| { | ||
| m_pCurThread->DisablePreemptiveGC(); | ||
| pThread->DisablePreemptiveGC(); | ||
| } | ||
| Pop(); | ||
| if (!wasCoop) | ||
| { | ||
| m_pCurThread->EnablePreemptiveGC(); | ||
| pThread->EnablePreemptiveGC(); | ||
| } | ||
| } | ||
| } | ||
| @@ -1233,7 +1234,7 @@ void GCFrame::Push(Thread* pThread) | ||
| // in which the compiler will lay them out in the stack frame. | ||
| // So minipal_getpagesize() is a guess of the maximum stack frame size of any method | ||
| // with multiple GCFrames in coreclr.dll | ||
| _ASSERTE(((m_Next == GCFRAME_TOP) || | ||
| _ASSERTE(((m_Next == NULL) || | ||
| (PBYTE(m_Next->GetOSStackLocation()) + (2 * minipal_getpagesize())) > PBYTE(this->GetOSStackLocation())) && | ||
| "Pushing a GCFrame out of order ?"); | ||
| @@ -1258,13 +1259,15 @@ void GCFrame::Pop() | ||
| _ASSERTE(m_pCurThread->GetGCFrame() == this && "Popping a GCFrame out of order ?"); | ||
| m_pCurThread->SetGCFrame(m_Next); | ||
| m_Next = NULL; | ||
| #ifdef _DEBUG | ||
| m_pCurThread->EnableStressHeap(); | ||
| for(UINT i = 0; i < m_numObjRefs; i++) | ||
| Thread::ObjectRefNew(&m_pObjRefs[i]); // Unprotect them | ||
| #endif | ||
| // The frame is no longer linked on the thread's GCFrame chain. | ||
| m_pCurThread = NULL; | ||
leculver marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| void GCFrame::Remove() | ||
| @@ -1280,7 +1283,7 @@ void GCFrame::Remove() | ||
| GCFrame *pPrevFrame = NULL; | ||
| GCFrame *pFrame = m_pCurThread->GetGCFrame(); | ||
| while (pFrame != GCFRAME_TOP) | ||
| while (pFrame != NULL) | ||
| { | ||
| if (pFrame == this) | ||
| { | ||
| @@ -1293,8 +1296,6 @@ void GCFrame::Remove() | ||
| m_pCurThread->SetGCFrame(m_Next); | ||
| } | ||
| m_Next = NULL; | ||
| #ifdef _DEBUG | ||
| m_pCurThread->EnableStressHeap(); | ||
| for(UINT i = 0; i < m_numObjRefs; i++) | ||
| @@ -1308,6 +1309,9 @@ void GCFrame::Remove() | ||
| } | ||
| _ASSERTE_MSG(pFrame != NULL, "GCFrame not found in the current thread's stack"); | ||
| // The frame is no longer linked on the thread's GCFrame chain. | ||
| m_pCurThread = NULL; | ||
leculver marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| #endif // !DACCESS_COMPILE | ||
| @@ -1393,7 +1397,7 @@ BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef) | ||
| GetThread()->StackWalkFrames(IsProtectedByGCFrameStackWalkFramesCallback, &d); | ||
| GCFrame* pGCFrame = GetThread()->GetGCFrame(); | ||
| while (pGCFrame != GCFRAME_TOP) | ||
| while (pGCFrame != NULL) | ||
| { | ||
| if (pGCFrame->Protects(ppObjectRef)) { | ||
| d.count++; | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.