[Support] When using SEH, create a impl instance for CrashRecoveryContext. NFCI.

Previously, the SEH codepath in CrashRecoveryContext didn't create a CrashRecoveryContextImpl. The other codepaths (VEH and Unix) were creating it.

When running with -fintegrated-cc1, this is needed to handle exit() as a jump to CrashRecoveryContext's exception filter, through a call to RaiseException. In that situation, we need a user-defined exception code, which is later interpreted as an exit() by the exception filter. This in turn needs to set RetCode accordingly, *inside* the exception filter, and *before* calling HandleCrash().

Differential Revision: https://reviews.llvm.org/D74078
This commit is contained in:
Alexandre Ganea 2020-02-06 19:23:27 -05:00
parent ad0e03fd4c
commit 2a3fa0fc5c
1 changed files with 35 additions and 25 deletions

View File

@ -15,7 +15,7 @@
#include <mutex>
#include <setjmp.h>
#ifdef _WIN32
#include <excpt.h> // for GetExceptionInformation
#include <windows.h> // for GetExceptionInformation
#endif
#if LLVM_ON_UNIX
#include <sysexits.h> // EX_IOERR
@ -41,11 +41,11 @@ struct CrashRecoveryContextImpl {
::jmp_buf JumpBuffer;
volatile unsigned Failed : 1;
unsigned SwitchedThread : 1;
unsigned ValidJumpBuffer : 1;
public:
CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC),
Failed(false),
SwitchedThread(false) {
CrashRecoveryContextImpl(CrashRecoveryContext *CRC)
: CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) {
Next = CurrentContext->get();
CurrentContext->set(this);
}
@ -80,10 +80,13 @@ public:
CRC->RetCode = RetCode;
// Jump back to the RunSafely we were called under.
longjmp(JumpBuffer, 1);
if (ValidJumpBuffer)
longjmp(JumpBuffer, 1);
// Otherwise let the caller decide of the outcome of the crash. Currently
// this occurs when using SEH on Windows with MSVC or clang-cl.
}
};
}
static ManagedStatic<std::mutex> gCrashRecoveryContextMutex;
@ -188,37 +191,43 @@ static void uninstallExceptionOrSignalHandlers() {}
// We need this function because the call to GetExceptionInformation() can only
// occur inside the __except evaluation block
static int ExceptionFilter(bool DumpStackAndCleanup,
_EXCEPTION_POINTERS *Except) {
if (DumpStackAndCleanup)
sys::CleanupOnSignal((uintptr_t)Except);
static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
// Lookup the current thread local recovery object.
const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
if (!CRCI) {
// Something has gone horribly wrong, so let's just tell everyone
// to keep searching
CrashRecoveryContext::Disable();
return EXCEPTION_CONTINUE_SEARCH;
}
int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
// Handle the crash
const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
RetCode, reinterpret_cast<uintptr_t>(Except));
return EXCEPTION_EXECUTE_HANDLER;
}
#if defined(__clang__) && defined(_M_IX86)
// Work around PR44697.
__attribute__((optnone))
static bool InvokeFunctionCall(function_ref<void()> Fn,
bool DumpStackAndCleanup, int &RetCode) {
#else
static bool InvokeFunctionCall(function_ref<void()> Fn,
bool DumpStackAndCleanup, int &RetCode) {
#endif
__try {
Fn();
} __except (ExceptionFilter(DumpStackAndCleanup, GetExceptionInformation())) {
RetCode = GetExceptionCode();
return false;
}
return true;
}
bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
if (!gCrashRecoveryEnabled) {
Fn();
return true;
}
return InvokeFunctionCall(Fn, DumpStackAndCleanupOnFailure, RetCode);
assert(!Impl && "Crash recovery context already initialized!");
Impl = new CrashRecoveryContextImpl(this);
__try {
Fn();
} __except (ExceptionFilter(GetExceptionInformation())) {
return false;
}
return true;
}
#else // !_MSC_VER
@ -395,6 +404,7 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this);
Impl = CRCI;
CRCI->ValidJumpBuffer = true;
if (setjmp(CRCI->JumpBuffer) != 0) {
return false;
}