diff options
author | Alexandre Ganea <alexandre.ganea@ubisoft.com> | 2020-01-11 15:27:07 -0500 |
---|---|---|
committer | Alexandre Ganea <alexandre.ganea@ubisoft.com> | 2020-01-11 15:27:07 -0500 |
commit | a1f16998f371870ca4da8b3c00a093c607a36ddd (patch) | |
tree | 16c485a7efd204626905f09dfbc073c02740cf12 /llvm/lib/Support/CrashRecoveryContext.cpp | |
parent | 179abb091d8a1d67115d21b54001d10250756042 (diff) | |
download | bcm5719-llvm-a1f16998f371870ca4da8b3c00a093c607a36ddd.tar.gz bcm5719-llvm-a1f16998f371870ca4da8b3c00a093c607a36ddd.zip |
[Support] Optionally call signal handlers when a function wrapped by the the CrashRecoveryContext fails
This patch allows for handling a failure inside a CrashRecoveryContext in the same way as the global exception/signal handler. A failure will have the same side-effect, such as cleanup of temporarty file, printing callstack, calling relevant signal handlers, and finally returning an exception code. This is an optional feature, disabled by default.
This is a support patch for D69825.
Differential Revision: https://reviews.llvm.org/D70568
Diffstat (limited to 'llvm/lib/Support/CrashRecoveryContext.cpp')
-rw-r--r-- | llvm/lib/Support/CrashRecoveryContext.cpp | 65 |
1 files changed, 52 insertions, 13 deletions
diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp index a9e0fcc73b9..548cce058c5 100644 --- a/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/llvm/lib/Support/CrashRecoveryContext.cpp @@ -10,9 +10,17 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Signals.h" #include "llvm/Support/ThreadLocal.h" #include <mutex> #include <setjmp.h> +#ifdef _WIN32 +#include <excpt.h> // for GetExceptionInformation +#endif +#if LLVM_ON_UNIX +#include <sysexits.h> // EX_IOERR +#endif + using namespace llvm; namespace { @@ -54,7 +62,11 @@ public: #endif } - void HandleCrash() { + // If the function ran by the CrashRecoveryContext crashes or fails, then + // 'RetCode' represents the returned error code, as if it was returned by a + // process. 'Context' represents the signal type on Unix; on Windows, it is + // the ExceptionContext. + void HandleCrash(int RetCode, uintptr_t Context) { // Eliminate the current context entry, to avoid re-entering in case the // cleanup code crashes. CurrentContext->set(Next); @@ -62,7 +74,10 @@ public: assert(!Failed && "Crash recovery context already failed!"); Failed = true; - // FIXME: Stash the backtrace. + if (CRC->DumpStackAndCleanupOnFailure) + sys::CleanupOnSignal(Context); + + CRC->RetCode = RetCode; // Jump back to the RunSafely we were called under. longjmp(JumpBuffer, 1); @@ -171,19 +186,32 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { static void installExceptionOrSignalHandlers() {} static void uninstallExceptionOrSignalHandlers() {} -bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { - if (!gCrashRecoveryEnabled) { +// 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); + return EXCEPTION_EXECUTE_HANDLER; +} + +static bool InvokeFunctionCall(function_ref<void()> Fn, + bool DumpStackAndCleanup, int &RetCode) { + __try { Fn(); - return true; + } __except (ExceptionFilter(DumpStackAndCleanup, GetExceptionInformation())) { + RetCode = GetExceptionCode(); + return false; } + return true; +} - bool Result = true; - __try { +bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { + if (!gCrashRecoveryEnabled) { Fn(); - } __except (1) { // Catch any exception. - Result = false; + return true; } - return Result; + return InvokeFunctionCall(Fn, DumpStackAndCleanupOnFailure, RetCode); } #else // !_MSC_VER @@ -237,7 +265,8 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) // implementation if we so choose. // Handle the crash - const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); + const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash( + (int)ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo); // Note that we don't actually get here because HandleCrash calls // longjmp, which means the HandleCrash function never returns. @@ -319,8 +348,16 @@ static void CrashRecoverySignalHandler(int Signal) { sigaddset(&SigMask, Signal); sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); + // As per convention, -2 indicates a crash or timeout as opposed to failure to + // execute (see llvm/include/llvm/Support/Program.h) + int RetCode = -2; + + // Don't consider a broken pipe as a crash (see clang/lib/Driver/Driver.cpp) + if (Signal == SIGPIPE) + RetCode = EX_IOERR; + if (CRCI) - const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); + const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(RetCode, Signal); } static void installExceptionOrSignalHandlers() { @@ -364,7 +401,9 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { void CrashRecoveryContext::HandleCrash() { CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; assert(CRCI && "Crash recovery context never initialized!"); - CRCI->HandleCrash(); + // As per convention, -2 indicates a crash or timeout as opposed to failure to + // execute (see llvm/include/llvm/Support/Program.h) + CRCI->HandleCrash(-2, 0); } // FIXME: Portability. |