Skip to content

Commit 40365cd

Browse files
kotlarmilosCopilotjanvorli
authored
[interp] Fix doubled interpreter frames in DAC/DBI stack walks (#126953)
## Description When DAC/DBI seeds StackFrameIterator from a CONTEXT pointing into interpreted code, m_crawl.pFrame is initialized to the thread's top explicit Frame, which is the InterpreterFrame that owns the executing InterpMethodContextFrame chain. ResetRegDisp reads the owning InterpreterFrame* from the CONTEXT's first-arg register and advances m_crawl.pFrame past it before ProcessCurrentFrame runs. ## Tests Fixes the following interpreter debugger test failures: - `StackWalking.NestedException` - `StackWalking.ChildParentTest` --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jan Vorlicek <janvorli@microsoft.com>
1 parent 920b310 commit 40365cd

1 file changed

Lines changed: 19 additions & 1 deletion

File tree

src/coreclr/vm/stackwalk.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ PTR_VOID ConvertStackMarkToPointerOnOSStack(PTR_Thread pThread, PTR_VOID stackMa
7070
}
7171
pCurrent = pCurrent->pParent;
7272
} while (pCurrent != NULL);
73-
73+
7474
}
7575

7676
pFrame = pFrame->PtrNextFrame();
@@ -1087,6 +1087,9 @@ BOOL StackFrameIterator::Init(Thread * pThread,
10871087

10881088
// process the REGDISPLAY and stop at the first frame
10891089
ProcessIp(GetControlPC(m_crawl.pRD));
1090+
#ifdef FEATURE_INTERPRETER
1091+
_ASSERTE(!m_crawl.codeInfo.IsInterpretedCode());
1092+
#endif // FEATURE_INTERPRETER
10901093
if (m_crawl.isFrameless && !!(m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE))
10911094
{
10921095
m_crawl.hasFaulted = true;
@@ -1160,6 +1163,21 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp,
11601163
PCODE curPc = GetControlPC(pRegDisp);
11611164
ProcessIp(curPc);
11621165

1166+
#ifdef FEATURE_INTERPRETER
1167+
if (m_crawl.codeInfo.IsInterpretedCode())
1168+
{
1169+
// The CONTEXT carries the owning InterpreterFrame in the first-arg register
1170+
// (set by InterpreterFrame::SetContextToInterpMethodContextFrame). Advance
1171+
// m_crawl.pFrame past it so the iterator does not re-enter the same
1172+
// InterpMethodContextFrame chain via the explicit frame link.
1173+
PTR_InterpreterFrame pOwningInterpFrame =
1174+
dac_cast<PTR_InterpreterFrame>((TADDR)GetFirstArgReg(m_crawl.pRD->pCurrentContext));
1175+
_ASSERTE(pOwningInterpFrame != NULL);
1176+
_ASSERTE(pOwningInterpFrame->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame);
1177+
m_crawl.pFrame = pOwningInterpFrame->PtrNextFrame();
1178+
}
1179+
else
1180+
#endif // FEATURE_INTERPRETER
11631181
// loop the frame chain to find the closet explicit frame which is lower than the specified REGDISPLAY
11641182
// (stack grows up towards lower address)
11651183
if (m_crawl.pFrame != FRAME_TOP)

0 commit comments

Comments
 (0)