106f32e7eSjoerg //===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg
906f32e7eSjoerg #include "llvm/Support/CrashRecoveryContext.h"
1006f32e7eSjoerg #include "llvm/Config/llvm-config.h"
1106f32e7eSjoerg #include "llvm/Support/ErrorHandling.h"
12*da58b97aSjoerg #include "llvm/Support/ExitCodes.h"
1306f32e7eSjoerg #include "llvm/Support/ManagedStatic.h"
14*da58b97aSjoerg #include "llvm/Support/Signals.h"
1506f32e7eSjoerg #include "llvm/Support/ThreadLocal.h"
1606f32e7eSjoerg #include <mutex>
1706f32e7eSjoerg #include <setjmp.h>
18*da58b97aSjoerg
1906f32e7eSjoerg using namespace llvm;
2006f32e7eSjoerg
2106f32e7eSjoerg namespace {
2206f32e7eSjoerg
2306f32e7eSjoerg struct CrashRecoveryContextImpl;
2406f32e7eSjoerg
2506f32e7eSjoerg static ManagedStatic<
2606f32e7eSjoerg sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext;
2706f32e7eSjoerg
2806f32e7eSjoerg struct CrashRecoveryContextImpl {
2906f32e7eSjoerg // When threads are disabled, this links up all active
3006f32e7eSjoerg // CrashRecoveryContextImpls. When threads are enabled there's one thread
3106f32e7eSjoerg // per CrashRecoveryContext and CurrentContext is a thread-local, so only one
3206f32e7eSjoerg // CrashRecoveryContextImpl is active per thread and this is always null.
3306f32e7eSjoerg const CrashRecoveryContextImpl *Next;
3406f32e7eSjoerg
3506f32e7eSjoerg CrashRecoveryContext *CRC;
3606f32e7eSjoerg ::jmp_buf JumpBuffer;
3706f32e7eSjoerg volatile unsigned Failed : 1;
3806f32e7eSjoerg unsigned SwitchedThread : 1;
39*da58b97aSjoerg unsigned ValidJumpBuffer : 1;
4006f32e7eSjoerg
4106f32e7eSjoerg public:
CrashRecoveryContextImpl__anon2059d9820111::CrashRecoveryContextImpl42*da58b97aSjoerg CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept
43*da58b97aSjoerg : CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) {
4406f32e7eSjoerg Next = CurrentContext->get();
4506f32e7eSjoerg CurrentContext->set(this);
4606f32e7eSjoerg }
~CrashRecoveryContextImpl__anon2059d9820111::CrashRecoveryContextImpl4706f32e7eSjoerg ~CrashRecoveryContextImpl() {
4806f32e7eSjoerg if (!SwitchedThread)
4906f32e7eSjoerg CurrentContext->set(Next);
5006f32e7eSjoerg }
5106f32e7eSjoerg
5206f32e7eSjoerg /// Called when the separate crash-recovery thread was finished, to
5306f32e7eSjoerg /// indicate that we don't need to clear the thread-local CurrentContext.
setSwitchedThread__anon2059d9820111::CrashRecoveryContextImpl5406f32e7eSjoerg void setSwitchedThread() {
5506f32e7eSjoerg #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
5606f32e7eSjoerg SwitchedThread = true;
5706f32e7eSjoerg #endif
5806f32e7eSjoerg }
5906f32e7eSjoerg
60*da58b97aSjoerg // If the function ran by the CrashRecoveryContext crashes or fails, then
61*da58b97aSjoerg // 'RetCode' represents the returned error code, as if it was returned by a
62*da58b97aSjoerg // process. 'Context' represents the signal type on Unix; on Windows, it is
63*da58b97aSjoerg // the ExceptionContext.
HandleCrash__anon2059d9820111::CrashRecoveryContextImpl64*da58b97aSjoerg void HandleCrash(int RetCode, uintptr_t Context) {
6506f32e7eSjoerg // Eliminate the current context entry, to avoid re-entering in case the
6606f32e7eSjoerg // cleanup code crashes.
6706f32e7eSjoerg CurrentContext->set(Next);
6806f32e7eSjoerg
6906f32e7eSjoerg assert(!Failed && "Crash recovery context already failed!");
7006f32e7eSjoerg Failed = true;
7106f32e7eSjoerg
72*da58b97aSjoerg if (CRC->DumpStackAndCleanupOnFailure)
73*da58b97aSjoerg sys::CleanupOnSignal(Context);
74*da58b97aSjoerg
75*da58b97aSjoerg CRC->RetCode = RetCode;
7606f32e7eSjoerg
7706f32e7eSjoerg // Jump back to the RunSafely we were called under.
78*da58b97aSjoerg if (ValidJumpBuffer)
7906f32e7eSjoerg longjmp(JumpBuffer, 1);
80*da58b97aSjoerg
81*da58b97aSjoerg // Otherwise let the caller decide of the outcome of the crash. Currently
82*da58b97aSjoerg // this occurs when using SEH on Windows with MSVC or clang-cl.
8306f32e7eSjoerg }
8406f32e7eSjoerg };
85*da58b97aSjoerg } // namespace
8606f32e7eSjoerg
8706f32e7eSjoerg static ManagedStatic<std::mutex> gCrashRecoveryContextMutex;
8806f32e7eSjoerg static bool gCrashRecoveryEnabled = false;
8906f32e7eSjoerg
9006f32e7eSjoerg static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>
9106f32e7eSjoerg tlIsRecoveringFromCrash;
9206f32e7eSjoerg
9306f32e7eSjoerg static void installExceptionOrSignalHandlers();
9406f32e7eSjoerg static void uninstallExceptionOrSignalHandlers();
9506f32e7eSjoerg
~CrashRecoveryContextCleanup()9606f32e7eSjoerg CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
9706f32e7eSjoerg
CrashRecoveryContext()98*da58b97aSjoerg CrashRecoveryContext::CrashRecoveryContext() {
99*da58b97aSjoerg // On Windows, if abort() was previously triggered (and caught by a previous
100*da58b97aSjoerg // CrashRecoveryContext) the Windows CRT removes our installed signal handler,
101*da58b97aSjoerg // so we need to install it again.
102*da58b97aSjoerg sys::DisableSystemDialogsOnCrash();
103*da58b97aSjoerg }
104*da58b97aSjoerg
~CrashRecoveryContext()10506f32e7eSjoerg CrashRecoveryContext::~CrashRecoveryContext() {
10606f32e7eSjoerg // Reclaim registered resources.
10706f32e7eSjoerg CrashRecoveryContextCleanup *i = head;
10806f32e7eSjoerg const CrashRecoveryContext *PC = tlIsRecoveringFromCrash->get();
10906f32e7eSjoerg tlIsRecoveringFromCrash->set(this);
11006f32e7eSjoerg while (i) {
11106f32e7eSjoerg CrashRecoveryContextCleanup *tmp = i;
11206f32e7eSjoerg i = tmp->next;
11306f32e7eSjoerg tmp->cleanupFired = true;
11406f32e7eSjoerg tmp->recoverResources();
11506f32e7eSjoerg delete tmp;
11606f32e7eSjoerg }
11706f32e7eSjoerg tlIsRecoveringFromCrash->set(PC);
11806f32e7eSjoerg
11906f32e7eSjoerg CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
12006f32e7eSjoerg delete CRCI;
12106f32e7eSjoerg }
12206f32e7eSjoerg
isRecoveringFromCrash()12306f32e7eSjoerg bool CrashRecoveryContext::isRecoveringFromCrash() {
12406f32e7eSjoerg return tlIsRecoveringFromCrash->get() != nullptr;
12506f32e7eSjoerg }
12606f32e7eSjoerg
GetCurrent()12706f32e7eSjoerg CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {
12806f32e7eSjoerg if (!gCrashRecoveryEnabled)
12906f32e7eSjoerg return nullptr;
13006f32e7eSjoerg
13106f32e7eSjoerg const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
13206f32e7eSjoerg if (!CRCI)
13306f32e7eSjoerg return nullptr;
13406f32e7eSjoerg
13506f32e7eSjoerg return CRCI->CRC;
13606f32e7eSjoerg }
13706f32e7eSjoerg
Enable()13806f32e7eSjoerg void CrashRecoveryContext::Enable() {
13906f32e7eSjoerg std::lock_guard<std::mutex> L(*gCrashRecoveryContextMutex);
14006f32e7eSjoerg // FIXME: Shouldn't this be a refcount or something?
14106f32e7eSjoerg if (gCrashRecoveryEnabled)
14206f32e7eSjoerg return;
14306f32e7eSjoerg gCrashRecoveryEnabled = true;
14406f32e7eSjoerg installExceptionOrSignalHandlers();
14506f32e7eSjoerg }
14606f32e7eSjoerg
Disable()14706f32e7eSjoerg void CrashRecoveryContext::Disable() {
14806f32e7eSjoerg std::lock_guard<std::mutex> L(*gCrashRecoveryContextMutex);
14906f32e7eSjoerg if (!gCrashRecoveryEnabled)
15006f32e7eSjoerg return;
15106f32e7eSjoerg gCrashRecoveryEnabled = false;
15206f32e7eSjoerg uninstallExceptionOrSignalHandlers();
15306f32e7eSjoerg }
15406f32e7eSjoerg
registerCleanup(CrashRecoveryContextCleanup * cleanup)15506f32e7eSjoerg void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup)
15606f32e7eSjoerg {
15706f32e7eSjoerg if (!cleanup)
15806f32e7eSjoerg return;
15906f32e7eSjoerg if (head)
16006f32e7eSjoerg head->prev = cleanup;
16106f32e7eSjoerg cleanup->next = head;
16206f32e7eSjoerg head = cleanup;
16306f32e7eSjoerg }
16406f32e7eSjoerg
16506f32e7eSjoerg void
unregisterCleanup(CrashRecoveryContextCleanup * cleanup)16606f32e7eSjoerg CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {
16706f32e7eSjoerg if (!cleanup)
16806f32e7eSjoerg return;
16906f32e7eSjoerg if (cleanup == head) {
17006f32e7eSjoerg head = cleanup->next;
17106f32e7eSjoerg if (head)
17206f32e7eSjoerg head->prev = nullptr;
17306f32e7eSjoerg }
17406f32e7eSjoerg else {
17506f32e7eSjoerg cleanup->prev->next = cleanup->next;
17606f32e7eSjoerg if (cleanup->next)
17706f32e7eSjoerg cleanup->next->prev = cleanup->prev;
17806f32e7eSjoerg }
17906f32e7eSjoerg delete cleanup;
18006f32e7eSjoerg }
18106f32e7eSjoerg
18206f32e7eSjoerg #if defined(_MSC_VER)
183*da58b97aSjoerg
184*da58b97aSjoerg #include <windows.h> // for GetExceptionInformation
185*da58b97aSjoerg
18606f32e7eSjoerg // If _MSC_VER is defined, we must have SEH. Use it if it's available. It's way
18706f32e7eSjoerg // better than VEH. Vectored exception handling catches all exceptions happening
18806f32e7eSjoerg // on the thread with installed exception handlers, so it can interfere with
18906f32e7eSjoerg // internal exception handling of other libraries on that thread. SEH works
19006f32e7eSjoerg // exactly as you would expect normal exception handling to work: it only
19106f32e7eSjoerg // catches exceptions if they would bubble out from the stack frame with __try /
19206f32e7eSjoerg // __except.
19306f32e7eSjoerg
installExceptionOrSignalHandlers()19406f32e7eSjoerg static void installExceptionOrSignalHandlers() {}
uninstallExceptionOrSignalHandlers()19506f32e7eSjoerg static void uninstallExceptionOrSignalHandlers() {}
19606f32e7eSjoerg
197*da58b97aSjoerg // We need this function because the call to GetExceptionInformation() can only
198*da58b97aSjoerg // occur inside the __except evaluation block
ExceptionFilter(_EXCEPTION_POINTERS * Except)199*da58b97aSjoerg static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
200*da58b97aSjoerg // Lookup the current thread local recovery object.
201*da58b97aSjoerg const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
202*da58b97aSjoerg
203*da58b97aSjoerg if (!CRCI) {
204*da58b97aSjoerg // Something has gone horribly wrong, so let's just tell everyone
205*da58b97aSjoerg // to keep searching
206*da58b97aSjoerg CrashRecoveryContext::Disable();
207*da58b97aSjoerg return EXCEPTION_CONTINUE_SEARCH;
208*da58b97aSjoerg }
209*da58b97aSjoerg
210*da58b97aSjoerg int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
211*da58b97aSjoerg if ((RetCode & 0xF0000000) == 0xE0000000)
212*da58b97aSjoerg RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit
213*da58b97aSjoerg
214*da58b97aSjoerg // Handle the crash
215*da58b97aSjoerg const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
216*da58b97aSjoerg RetCode, reinterpret_cast<uintptr_t>(Except));
217*da58b97aSjoerg
218*da58b97aSjoerg return EXCEPTION_EXECUTE_HANDLER;
219*da58b97aSjoerg }
220*da58b97aSjoerg
221*da58b97aSjoerg #if defined(__clang__) && defined(_M_IX86)
222*da58b97aSjoerg // Work around PR44697.
223*da58b97aSjoerg __attribute__((optnone))
224*da58b97aSjoerg #endif
RunSafely(function_ref<void ()> Fn)22506f32e7eSjoerg bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
22606f32e7eSjoerg if (!gCrashRecoveryEnabled) {
22706f32e7eSjoerg Fn();
22806f32e7eSjoerg return true;
22906f32e7eSjoerg }
230*da58b97aSjoerg assert(!Impl && "Crash recovery context already initialized!");
231*da58b97aSjoerg Impl = new CrashRecoveryContextImpl(this);
23206f32e7eSjoerg __try {
23306f32e7eSjoerg Fn();
234*da58b97aSjoerg } __except (ExceptionFilter(GetExceptionInformation())) {
235*da58b97aSjoerg return false;
23606f32e7eSjoerg }
237*da58b97aSjoerg return true;
23806f32e7eSjoerg }
23906f32e7eSjoerg
24006f32e7eSjoerg #else // !_MSC_VER
24106f32e7eSjoerg
24206f32e7eSjoerg #if defined(_WIN32)
24306f32e7eSjoerg // This is a non-MSVC compiler, probably mingw gcc or clang without
24406f32e7eSjoerg // -fms-extensions. Use vectored exception handling (VEH).
24506f32e7eSjoerg //
24606f32e7eSjoerg // On Windows, we can make use of vectored exception handling to catch most
24706f32e7eSjoerg // crashing situations. Note that this does mean we will be alerted of
24806f32e7eSjoerg // exceptions *before* structured exception handling has the opportunity to
24906f32e7eSjoerg // catch it. Unfortunately, this causes problems in practice with other code
25006f32e7eSjoerg // running on threads with LLVM crash recovery contexts, so we would like to
25106f32e7eSjoerg // eventually move away from VEH.
25206f32e7eSjoerg //
25306f32e7eSjoerg // Vectored works on a per-thread basis, which is an advantage over
25406f32e7eSjoerg // SetUnhandledExceptionFilter. SetUnhandledExceptionFilter also doesn't have
25506f32e7eSjoerg // any native support for chaining exception handlers, but VEH allows more than
25606f32e7eSjoerg // one.
25706f32e7eSjoerg //
25806f32e7eSjoerg // The vectored exception handler functionality was added in Windows
25906f32e7eSjoerg // XP, so if support for older versions of Windows is required,
26006f32e7eSjoerg // it will have to be added.
26106f32e7eSjoerg
262*da58b97aSjoerg #include "llvm/Support/Windows/WindowsSupport.h"
26306f32e7eSjoerg
ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)26406f32e7eSjoerg static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
26506f32e7eSjoerg {
26606f32e7eSjoerg // DBG_PRINTEXCEPTION_WIDE_C is not properly defined on all supported
26706f32e7eSjoerg // compilers and platforms, so we define it manually.
26806f32e7eSjoerg constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;
26906f32e7eSjoerg switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
27006f32e7eSjoerg {
27106f32e7eSjoerg case DBG_PRINTEXCEPTION_C:
27206f32e7eSjoerg case DbgPrintExceptionWideC:
27306f32e7eSjoerg case 0x406D1388: // set debugger thread name
27406f32e7eSjoerg return EXCEPTION_CONTINUE_EXECUTION;
27506f32e7eSjoerg }
27606f32e7eSjoerg
27706f32e7eSjoerg // Lookup the current thread local recovery object.
27806f32e7eSjoerg const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
27906f32e7eSjoerg
28006f32e7eSjoerg if (!CRCI) {
28106f32e7eSjoerg // Something has gone horribly wrong, so let's just tell everyone
28206f32e7eSjoerg // to keep searching
28306f32e7eSjoerg CrashRecoveryContext::Disable();
28406f32e7eSjoerg return EXCEPTION_CONTINUE_SEARCH;
28506f32e7eSjoerg }
28606f32e7eSjoerg
28706f32e7eSjoerg // TODO: We can capture the stack backtrace here and store it on the
28806f32e7eSjoerg // implementation if we so choose.
28906f32e7eSjoerg
290*da58b97aSjoerg int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;
291*da58b97aSjoerg if ((RetCode & 0xF0000000) == 0xE0000000)
292*da58b97aSjoerg RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit
293*da58b97aSjoerg
29406f32e7eSjoerg // Handle the crash
295*da58b97aSjoerg const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
296*da58b97aSjoerg RetCode, reinterpret_cast<uintptr_t>(ExceptionInfo));
29706f32e7eSjoerg
29806f32e7eSjoerg // Note that we don't actually get here because HandleCrash calls
29906f32e7eSjoerg // longjmp, which means the HandleCrash function never returns.
30006f32e7eSjoerg llvm_unreachable("Handled the crash, should have longjmp'ed out of here");
30106f32e7eSjoerg }
30206f32e7eSjoerg
30306f32e7eSjoerg // Because the Enable and Disable calls are static, it means that
30406f32e7eSjoerg // there may not actually be an Impl available, or even a current
30506f32e7eSjoerg // CrashRecoveryContext at all. So we make use of a thread-local
30606f32e7eSjoerg // exception table. The handles contained in here will either be
30706f32e7eSjoerg // non-NULL, valid VEH handles, or NULL.
30806f32e7eSjoerg static sys::ThreadLocal<const void> sCurrentExceptionHandle;
30906f32e7eSjoerg
installExceptionOrSignalHandlers()31006f32e7eSjoerg static void installExceptionOrSignalHandlers() {
31106f32e7eSjoerg // We can set up vectored exception handling now. We will install our
31206f32e7eSjoerg // handler as the front of the list, though there's no assurances that
31306f32e7eSjoerg // it will remain at the front (another call could install itself before
31406f32e7eSjoerg // our handler). This 1) isn't likely, and 2) shouldn't cause problems.
31506f32e7eSjoerg PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);
31606f32e7eSjoerg sCurrentExceptionHandle.set(handle);
31706f32e7eSjoerg }
31806f32e7eSjoerg
uninstallExceptionOrSignalHandlers()31906f32e7eSjoerg static void uninstallExceptionOrSignalHandlers() {
32006f32e7eSjoerg PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get());
32106f32e7eSjoerg if (currentHandle) {
32206f32e7eSjoerg // Now we can remove the vectored exception handler from the chain
32306f32e7eSjoerg ::RemoveVectoredExceptionHandler(currentHandle);
32406f32e7eSjoerg
32506f32e7eSjoerg // Reset the handle in our thread-local set.
32606f32e7eSjoerg sCurrentExceptionHandle.set(NULL);
32706f32e7eSjoerg }
32806f32e7eSjoerg }
32906f32e7eSjoerg
33006f32e7eSjoerg #else // !_WIN32
33106f32e7eSjoerg
33206f32e7eSjoerg // Generic POSIX implementation.
33306f32e7eSjoerg //
33406f32e7eSjoerg // This implementation relies on synchronous signals being delivered to the
33506f32e7eSjoerg // current thread. We use a thread local object to keep track of the active
33606f32e7eSjoerg // crash recovery context, and install signal handlers to invoke HandleCrash on
33706f32e7eSjoerg // the active object.
33806f32e7eSjoerg //
33906f32e7eSjoerg // This implementation does not attempt to chain signal handlers in any
34006f32e7eSjoerg // reliable fashion -- if we get a signal outside of a crash recovery context we
34106f32e7eSjoerg // simply disable crash recovery and raise the signal again.
34206f32e7eSjoerg
34306f32e7eSjoerg #include <signal.h>
34406f32e7eSjoerg
34506f32e7eSjoerg static const int Signals[] =
34606f32e7eSjoerg { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };
34706f32e7eSjoerg static const unsigned NumSignals = array_lengthof(Signals);
34806f32e7eSjoerg static struct sigaction PrevActions[NumSignals];
34906f32e7eSjoerg
CrashRecoverySignalHandler(int Signal)35006f32e7eSjoerg static void CrashRecoverySignalHandler(int Signal) {
35106f32e7eSjoerg // Lookup the current thread local recovery object.
35206f32e7eSjoerg const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
35306f32e7eSjoerg
35406f32e7eSjoerg if (!CRCI) {
35506f32e7eSjoerg // We didn't find a crash recovery context -- this means either we got a
35606f32e7eSjoerg // signal on a thread we didn't expect it on, the application got a signal
35706f32e7eSjoerg // outside of a crash recovery context, or something else went horribly
35806f32e7eSjoerg // wrong.
35906f32e7eSjoerg //
36006f32e7eSjoerg // Disable crash recovery and raise the signal again. The assumption here is
36106f32e7eSjoerg // that the enclosing application will terminate soon, and we won't want to
36206f32e7eSjoerg // attempt crash recovery again.
36306f32e7eSjoerg //
36406f32e7eSjoerg // This call of Disable isn't thread safe, but it doesn't actually matter.
36506f32e7eSjoerg CrashRecoveryContext::Disable();
36606f32e7eSjoerg raise(Signal);
36706f32e7eSjoerg
36806f32e7eSjoerg // The signal will be thrown once the signal mask is restored.
36906f32e7eSjoerg return;
37006f32e7eSjoerg }
37106f32e7eSjoerg
37206f32e7eSjoerg // Unblock the signal we received.
37306f32e7eSjoerg sigset_t SigMask;
37406f32e7eSjoerg sigemptyset(&SigMask);
37506f32e7eSjoerg sigaddset(&SigMask, Signal);
37606f32e7eSjoerg sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
37706f32e7eSjoerg
378*da58b97aSjoerg // Return the same error code as if the program crashed, as mentioned in the
379*da58b97aSjoerg // section "Exit Status for Commands":
380*da58b97aSjoerg // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html
381*da58b97aSjoerg int RetCode = 128 + Signal;
382*da58b97aSjoerg
383*da58b97aSjoerg // Don't consider a broken pipe as a crash (see clang/lib/Driver/Driver.cpp)
384*da58b97aSjoerg if (Signal == SIGPIPE)
385*da58b97aSjoerg RetCode = EX_IOERR;
386*da58b97aSjoerg
38706f32e7eSjoerg if (CRCI)
388*da58b97aSjoerg const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(RetCode, Signal);
38906f32e7eSjoerg }
39006f32e7eSjoerg
installExceptionOrSignalHandlers()39106f32e7eSjoerg static void installExceptionOrSignalHandlers() {
39206f32e7eSjoerg // Setup the signal handler.
39306f32e7eSjoerg struct sigaction Handler;
39406f32e7eSjoerg Handler.sa_handler = CrashRecoverySignalHandler;
39506f32e7eSjoerg Handler.sa_flags = 0;
39606f32e7eSjoerg sigemptyset(&Handler.sa_mask);
39706f32e7eSjoerg
39806f32e7eSjoerg for (unsigned i = 0; i != NumSignals; ++i) {
39906f32e7eSjoerg sigaction(Signals[i], &Handler, &PrevActions[i]);
40006f32e7eSjoerg }
40106f32e7eSjoerg }
40206f32e7eSjoerg
uninstallExceptionOrSignalHandlers()40306f32e7eSjoerg static void uninstallExceptionOrSignalHandlers() {
40406f32e7eSjoerg // Restore the previous signal handlers.
40506f32e7eSjoerg for (unsigned i = 0; i != NumSignals; ++i)
40606f32e7eSjoerg sigaction(Signals[i], &PrevActions[i], nullptr);
40706f32e7eSjoerg }
40806f32e7eSjoerg
40906f32e7eSjoerg #endif // !_WIN32
41006f32e7eSjoerg
RunSafely(function_ref<void ()> Fn)41106f32e7eSjoerg bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
41206f32e7eSjoerg // If crash recovery is disabled, do nothing.
41306f32e7eSjoerg if (gCrashRecoveryEnabled) {
41406f32e7eSjoerg assert(!Impl && "Crash recovery context already initialized!");
41506f32e7eSjoerg CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this);
41606f32e7eSjoerg Impl = CRCI;
41706f32e7eSjoerg
418*da58b97aSjoerg CRCI->ValidJumpBuffer = true;
41906f32e7eSjoerg if (setjmp(CRCI->JumpBuffer) != 0) {
42006f32e7eSjoerg return false;
42106f32e7eSjoerg }
42206f32e7eSjoerg }
42306f32e7eSjoerg
42406f32e7eSjoerg Fn();
42506f32e7eSjoerg return true;
42606f32e7eSjoerg }
42706f32e7eSjoerg
42806f32e7eSjoerg #endif // !_MSC_VER
42906f32e7eSjoerg
430*da58b97aSjoerg LLVM_ATTRIBUTE_NORETURN
HandleExit(int RetCode)431*da58b97aSjoerg void CrashRecoveryContext::HandleExit(int RetCode) {
432*da58b97aSjoerg #if defined(_WIN32)
433*da58b97aSjoerg // SEH and VEH
434*da58b97aSjoerg ::RaiseException(0xE0000000 | RetCode, 0, 0, NULL);
435*da58b97aSjoerg #else
436*da58b97aSjoerg // On Unix we don't need to raise an exception, we go directly to
437*da58b97aSjoerg // HandleCrash(), then longjmp will unwind the stack for us.
43806f32e7eSjoerg CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;
43906f32e7eSjoerg assert(CRCI && "Crash recovery context never initialized!");
440*da58b97aSjoerg CRCI->HandleCrash(RetCode, 0 /*no sig num*/);
441*da58b97aSjoerg #endif
442*da58b97aSjoerg llvm_unreachable("Most likely setjmp wasn't called!");
443*da58b97aSjoerg }
444*da58b97aSjoerg
throwIfCrash(int RetCode)445*da58b97aSjoerg bool CrashRecoveryContext::throwIfCrash(int RetCode) {
446*da58b97aSjoerg #if defined(_WIN32)
447*da58b97aSjoerg // On Windows, the high bits are reserved for kernel return codes. Values
448*da58b97aSjoerg // starting with 0x80000000 are reserved for "warnings"; values of 0xC0000000
449*da58b97aSjoerg // and up are for "errors". In practice, both are interpreted as a
450*da58b97aSjoerg // non-continuable signal.
451*da58b97aSjoerg unsigned Code = ((unsigned)RetCode & 0xF0000000) >> 28;
452*da58b97aSjoerg if (Code != 0xC && Code != 8)
453*da58b97aSjoerg return false;
454*da58b97aSjoerg ::RaiseException(RetCode, 0, 0, NULL);
455*da58b97aSjoerg #else
456*da58b97aSjoerg // On Unix, signals are represented by return codes of 128 or higher.
457*da58b97aSjoerg // Exit code 128 is a reserved value and should not be raised as a signal.
458*da58b97aSjoerg if (RetCode <= 128)
459*da58b97aSjoerg return false;
460*da58b97aSjoerg llvm::sys::unregisterHandlers();
461*da58b97aSjoerg raise(RetCode - 128);
462*da58b97aSjoerg #endif
463*da58b97aSjoerg return true;
46406f32e7eSjoerg }
46506f32e7eSjoerg
46606f32e7eSjoerg // FIXME: Portability.
setThreadBackgroundPriority()46706f32e7eSjoerg static void setThreadBackgroundPriority() {
46806f32e7eSjoerg #ifdef __APPLE__
46906f32e7eSjoerg setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
47006f32e7eSjoerg #endif
47106f32e7eSjoerg }
47206f32e7eSjoerg
hasThreadBackgroundPriority()47306f32e7eSjoerg static bool hasThreadBackgroundPriority() {
47406f32e7eSjoerg #ifdef __APPLE__
47506f32e7eSjoerg return getpriority(PRIO_DARWIN_THREAD, 0) == 1;
47606f32e7eSjoerg #else
47706f32e7eSjoerg return false;
47806f32e7eSjoerg #endif
47906f32e7eSjoerg }
48006f32e7eSjoerg
48106f32e7eSjoerg namespace {
48206f32e7eSjoerg struct RunSafelyOnThreadInfo {
48306f32e7eSjoerg function_ref<void()> Fn;
48406f32e7eSjoerg CrashRecoveryContext *CRC;
48506f32e7eSjoerg bool UseBackgroundPriority;
48606f32e7eSjoerg bool Result;
48706f32e7eSjoerg };
488*da58b97aSjoerg } // namespace
48906f32e7eSjoerg
RunSafelyOnThread_Dispatch(void * UserData)49006f32e7eSjoerg static void RunSafelyOnThread_Dispatch(void *UserData) {
49106f32e7eSjoerg RunSafelyOnThreadInfo *Info =
49206f32e7eSjoerg reinterpret_cast<RunSafelyOnThreadInfo*>(UserData);
49306f32e7eSjoerg
49406f32e7eSjoerg if (Info->UseBackgroundPriority)
49506f32e7eSjoerg setThreadBackgroundPriority();
49606f32e7eSjoerg
49706f32e7eSjoerg Info->Result = Info->CRC->RunSafely(Info->Fn);
49806f32e7eSjoerg }
RunSafelyOnThread(function_ref<void ()> Fn,unsigned RequestedStackSize)49906f32e7eSjoerg bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn,
50006f32e7eSjoerg unsigned RequestedStackSize) {
50106f32e7eSjoerg bool UseBackgroundPriority = hasThreadBackgroundPriority();
50206f32e7eSjoerg RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };
50306f32e7eSjoerg llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info,
50406f32e7eSjoerg RequestedStackSize == 0
50506f32e7eSjoerg ? llvm::None
50606f32e7eSjoerg : llvm::Optional<unsigned>(RequestedStackSize));
50706f32e7eSjoerg if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
50806f32e7eSjoerg CRC->setSwitchedThread();
50906f32e7eSjoerg return Info.Result;
51006f32e7eSjoerg }
511