Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 52 additions & 12 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,31 @@ void AsyncHelpers_ResumeInterpreterContinuation(QCall::ObjectHandleOnStack cont,
END_QCALL;
}

static void DECLSPEC_NORETURN HandleInterpreterStackOverflow(InterpreterFrame* pInterpreterFrame)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_COOPERATIVE;
}
CONTRACTL_END

CONTEXT ctx;
memset(&ctx, 0, sizeof(CONTEXT));
pInterpreterFrame->SetIsFaulting(true);
pInterpreterFrame->SetContextToInterpMethodContextFrame(&ctx);

EXCEPTION_RECORD exceptionRecord;
memset(&exceptionRecord, 0, sizeof(EXCEPTION_RECORD));
exceptionRecord.ExceptionCode = STATUS_STACK_OVERFLOW;
exceptionRecord.ExceptionAddress = (PVOID)GetIP(&ctx);

EXCEPTION_POINTERS exceptionInfo = { &exceptionRecord, &ctx };
EEPolicy::HandleFatalStackOverflow(&exceptionInfo);
}


void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFrame *pFrame, InterpThreadContext *pThreadContext, ExceptionClauseArgs *pExceptionClauseArgs)
{
CONTRACTL
Expand All @@ -860,31 +885,38 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
InterpMethod *pMethod = pFrame->startIp->Method;
_ASSERTE(pMethod->CheckIntegrity());

pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize;
stack = pFrame->pStack;

if (pExceptionClauseArgs == NULL)
{
// Start executing at the beginning of the method
ip = pFrame->startIp->GetByteCodes();
}
else
{
// Start executing at the beginning of the exception clause
ip = pExceptionClauseArgs->ip;
}

if (pFrame->pStack + pMethod->allocaSize > pThreadContext->pStackEnd)
{
pFrame->ip = ip;
HandleInterpreterStackOverflow(pInterpreterFrame);
UNREACHABLE();
}

pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize;
stack = pFrame->pStack;

if ((pExceptionClauseArgs != NULL) && pExceptionClauseArgs->isFilter)
{
// * Filter funclets are executed in the current frame, because they are executed
// in the first pass of EH when the frames between the current frame and the
// parent frame are still alive. All accesses to the locals and arguments
// in this case use the pExceptionClauseArgs->pFrame->pStack as a frame pointer.
// * Catch and finally funclets are running in the parent frame directly

if (pExceptionClauseArgs->isFilter)
{
// Since filters run in their own frame, we need to clear the global variables
// so that GC doesn't pick garbage in variables that were not yet written to.
memset(pFrame->pStack, 0, pMethod->allocaSize);
}

// Start executing at the beginning of the exception clause
ip = pExceptionClauseArgs->ip;
// Since filters run in their own frame, we need to clear the global variables
// so that GC doesn't pick garbage in variables that were not yet written to.
memset(pFrame->pStack, 0, pMethod->allocaSize);
}

int32_t returnOffset, callArgsOffset, methodSlot;
Expand Down Expand Up @@ -2908,6 +2940,13 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
_ASSERTE(pMethod->CheckIntegrity());
stack = pFrame->pStack;
ip = pFrame->startIp->GetByteCodes();

if (stack + pMethod->allocaSize > pThreadContext->pStackEnd)
{
pFrame->ip = ip;
HandleInterpreterStackOverflow(pInterpreterFrame);
UNREACHABLE();
}
pThreadContext->pStackPointer = stack + pMethod->allocaSize;
break;
}
Expand Down Expand Up @@ -4091,6 +4130,7 @@ do \
stack = pFrame->pStack;
pMethod = pFrame->startIp->Method;
_ASSERTE(pMethod->CheckIntegrity());

pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize;

pInterpreterFrame->SetIsFaulting(false);
Expand Down
24 changes: 24 additions & 0 deletions src/coreclr/vm/stackwalk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,11 +716,35 @@ UINT_PTR Thread::VirtualUnwindToFirstManagedCallFrame(T_CONTEXT* pContext)
CONTRACTL_END;

PCODE uControlPc = GetIP(pContext);
Thread *pThread = GetThread();

#ifdef FEATURE_INTERPRETER
Frame *pFrame = pThread->GetFrame();
while (pFrame != FRAME_TOP && (pFrame->GetFrameIdentifier() != FrameIdentifier::InterpreterFrame))
{
pFrame = pFrame->PtrNextFrame();
}
InterpreterFrame *pInterpreterFrame = (pFrame != FRAME_TOP) ? (InterpreterFrame *)pFrame : NULL;
#endif // FEATURE_INTERPRETER

// unwind out of this function and out of our caller to
// get our caller's PSP, or our caller's caller's SP.
while (!ExecutionManager::IsManagedCode(uControlPc))
{
#ifdef FEATURE_INTERPRETER
// Check if we are past the topmost interpreter frame
if ((pInterpreterFrame != NULL) && (GetSP(pContext) > (TADDR)pFrame))
{
InterpMethodContextFrame *pInterpMethodContextFrame = pInterpreterFrame->GetTopInterpMethodContextFrame();
if (pInterpMethodContextFrame != NULL)
{
pInterpreterFrame->SetContextToInterpMethodContextFrame(pContext);
uControlPc = GetIP(pContext);
break;
}
}
#endif // FEATURE_INTERPRETER

if (IsIPInWriteBarrierCodeCopy(uControlPc))
{
// Pretend we were executing the barrier function at its original location so that the unwinder can unwind the frame
Expand Down
Loading