diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index bd31eee7c233bf..0eb96e0af27b9b 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -5657,7 +5657,7 @@ BOOL DacDbiInterfaceImpl::IsThreadAtGCSafePlace(VMPTR_Thread vmThread) ULONG32 flags = (QUICKUNWIND | HANDLESKIPPEDFRAMES | DISABLE_MISSING_FRAME_DETECTION); StackFrameIterator iter; - iter.Init(pThread, pThread->GetFrame(), &rd, flags); + iter.Init(pThread, NULL, &rd, flags); CrawlFrame * pCF = &(iter.m_crawl); if (pCF->IsFrameless() && pCF->IsActiveFunc()) diff --git a/src/coreclr/vm/stackwalk.cpp b/src/coreclr/vm/stackwalk.cpp index 00f2123f005fe0..f8e344552c303e 100644 --- a/src/coreclr/vm/stackwalk.cpp +++ b/src/coreclr/vm/stackwalk.cpp @@ -1088,7 +1088,25 @@ BOOL StackFrameIterator::Init(Thread * pThread, // process the REGDISPLAY and stop at the first frame ProcessIp(GetControlPC(m_crawl.pRD)); #ifdef FEATURE_INTERPRETER - _ASSERTE(!m_crawl.codeInfo.IsInterpretedCode()); + if (m_crawl.codeInfo.IsInterpretedCode()) + { + // CONTEXT is in interpreted code where the first-arg register holds the owning InterpreterFrame. + // Skip past it so we don't re-enter its frame chain. + PTR_InterpreterFrame pOwning = + dac_cast((TADDR)GetFirstArgReg(m_crawl.pRD->pCurrentContext)); + _ASSERTE(pOwning != NULL); + _ASSERTE(pOwning->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame); + + if (pFrame == NULL) + { + m_crawl.pFrame = pOwning->PtrNextFrame(); + } + else + { + // Explicit pFrame must already be past the owner (callee Frames have lower addresses than their callers). + _ASSERTE(dac_cast(m_crawl.pFrame) > dac_cast(pOwning)); + } + } #endif // FEATURE_INTERPRETER if (m_crawl.isFrameless && !!(m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE)) { @@ -1166,10 +1184,8 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp, #ifdef FEATURE_INTERPRETER if (m_crawl.codeInfo.IsInterpretedCode()) { - // The CONTEXT carries the owning InterpreterFrame in the first-arg register - // (set by InterpreterFrame::SetContextToInterpMethodContextFrame). Advance - // m_crawl.pFrame past it so the iterator does not re-enter the same - // InterpMethodContextFrame chain via the explicit frame link. + // CONTEXT is in interpreted code where the first-arg register holds the owning InterpreterFrame. + // Skip past it so we don't re-enter its frame chain. PTR_InterpreterFrame pOwningInterpFrame = dac_cast((TADDR)GetFirstArgReg(m_crawl.pRD->pCurrentContext)); _ASSERTE(pOwningInterpFrame != NULL);