Skip to content

Commit

Permalink
port fix for InlinedCallFrame corruption to 3.1
Browse files Browse the repository at this point in the history
  • Loading branch information
davmason committed Aug 28, 2020
1 parent f897710 commit f9916f2
Showing 1 changed file with 34 additions and 16 deletions.
50 changes: 34 additions & 16 deletions src/vm/i386/excepx86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1868,21 +1868,6 @@ NOINLINE LPVOID COMPlusEndCatchWorker(Thread * pThread)
// Sync managed exception state, for the managed thread, based upon any active exception tracker
pThread->SyncManagedExceptionState(fIsDebuggerHelperThread);

if (InlinedCallFrame::FrameHasActiveCall(pThread->m_pFrame))
{
// When unwinding an exception in ReadyToRun, the JIT_PInvokeEnd helper which unlinks the ICF from
// the thread will be skipped. This is because unlike jitted code, each pinvoke is wrapped by calls
// to the JIT_PInvokeBegin and JIT_PInvokeEnd helpers, which push and pop the ICF on the thread. The
// ICF is not linked at the method prolog and unlined at the epilog when running R2R code. Since the
// JIT_PInvokeEnd helper will be skipped, we need to unlink the ICF here. If the executing method
// has another pinovoke, it will re-link the ICF again when the JIT_PInvokeBegin helper is called

if (ExecutionManager::IsReadyToRunCode(((InlinedCallFrame*)pThread->m_pFrame)->m_pCallerReturnAddress))
{
pThread->m_pFrame->Pop(pThread);
}
}

LOG((LF_EH, LL_INFO1000, "COMPlusPEndCatch: esp=%p\n", esp));

return esp;
Expand Down Expand Up @@ -3138,6 +3123,39 @@ void ResumeAtJitEH(CrawlFrame* pCf,
*pHandlerEnd = EHClausePtr->HandlerEndPC;
}

MethodDesc* pMethodDesc = pCf->GetCodeInfo()->GetMethodDesc();
TADDR startAddress = pCf->GetCodeInfo()->GetStartAddress();
if (InlinedCallFrame::FrameHasActiveCall(pThread->m_pFrame))
{
// When unwinding an exception in ReadyToRun, the JIT_PInvokeEnd helper which unlinks the ICF from
// the thread will be skipped. This is because unlike jitted code, each pinvoke is wrapped by calls
// to the JIT_PInvokeBegin and JIT_PInvokeEnd helpers, which push and pop the ICF on the thread. The
// ICF is not linked at the method prolog and unlinked at the epilog when running R2R code. Since the
// JIT_PInvokeEnd helper will be skipped, we need to unlink the ICF here. If the executing method
// has another pinvoke, it will re-link the ICF again when the JIT_PInvokeBegin helper is called.

// Check that the InlinedCallFrame is in the method with the exception handler. There can be other
// InlinedCallFrame somewhere up the call chain that is not related to the current exception
// handling.

#ifdef DEBUG
TADDR handlerFrameSP = pCf->GetRegisterSet()->SP;
#endif // DEBUG
// Find the ESP of the caller of the method with the exception handler.
bool unwindSuccess = pCf->GetCodeManager()->UnwindStackFrame(pCf->GetRegisterSet(),
pCf->GetCodeInfo(),
pCf->GetCodeManagerFlags(),
pCf->GetCodeManState(),
NULL /* StackwalkCacheUnwindInfo* */);
_ASSERTE(unwindSuccess);

if (((TADDR)pThread->m_pFrame < pCf->GetRegisterSet()->SP) && ExecutionManager::IsReadyToRunCode(((InlinedCallFrame*)pThread->m_pFrame)->m_pCallerReturnAddress))
{
_ASSERTE((TADDR)pThread->m_pFrame >= handlerFrameSP);
pThread->m_pFrame->Pop(pThread);
}
}

// save esp so that endcatch can restore it (it always restores, so want correct value)
ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
pExInfo->m_dEsp = (LPVOID)context.GetSP();
Expand Down Expand Up @@ -3251,7 +3269,7 @@ void ResumeAtJitEH(CrawlFrame* pCf,
// that the handle for the current ExInfo has been freed has been delivered
pExInfo->m_EHClauseInfo.SetManagedCodeEntered(TRUE);

ETW::ExceptionLog::ExceptionCatchBegin(pCf->GetCodeInfo()->GetMethodDesc(), (PVOID)pCf->GetCodeInfo()->GetStartAddress());
ETW::ExceptionLog::ExceptionCatchBegin(pMethodDesc, (PVOID)startAddress);

ResumeAtJitEHHelper(&context);
UNREACHABLE_MSG("Should never return from ResumeAtJitEHHelper!");
Expand Down

0 comments on commit f9916f2

Please sign in to comment.