aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support/CrashRecoveryContext.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
commit706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch)
tree4adf86a776049cbf7f69a1929c4babcbbef925eb /llvm/lib/Support/CrashRecoveryContext.cpp
parent7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff)
Notes
Diffstat (limited to 'llvm/lib/Support/CrashRecoveryContext.cpp')
-rw-r--r--llvm/lib/Support/CrashRecoveryContext.cpp73
1 files changed, 58 insertions, 15 deletions
diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp
index 9d13fce9cc52..b9031f52375c 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,9 @@ 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,
+ reinterpret_cast<uintptr_t>(ExceptionInfo));
// Note that we don't actually get here because HandleCrash calls
// longjmp, which means the HandleCrash function never returns.
@@ -280,7 +310,7 @@ static void uninstallExceptionOrSignalHandlers() {
// crash recovery context, and install signal handlers to invoke HandleCrash on
// the active object.
//
-// This implementation does not to attempt to chain signal handlers in any
+// This implementation does not attempt to chain signal handlers in any
// reliable fashion -- if we get a signal outside of a crash recovery context we
// simply disable crash recovery and raise the signal again.
@@ -319,8 +349,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 +402,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.
@@ -404,7 +444,10 @@ bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn,
unsigned RequestedStackSize) {
bool UseBackgroundPriority = hasThreadBackgroundPriority();
RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };
- llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize);
+ llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info,
+ RequestedStackSize == 0
+ ? llvm::None
+ : llvm::Optional<unsigned>(RequestedStackSize));
if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
CRC->setSwitchedThread();
return Info.Result;