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