10#include "llvm/Config/llvm-config.h"
23struct CrashRecoveryContextImpl;
26struct CrashRecoveryContextImpl {
31 const CrashRecoveryContextImpl *Next;
33 CrashRecoveryContext *CRC;
35 volatile unsigned Failed : 1;
36 unsigned SwitchedThread : 1;
37 unsigned ValidJumpBuffer : 1;
40 CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept
41 : CRC(CRC),
Failed(
false), SwitchedThread(
false), ValidJumpBuffer(
false) {
42 Next = CurrentContext;
43 CurrentContext =
this;
45 ~CrashRecoveryContextImpl() {
47 CurrentContext = Next;
52 void setSwitchedThread() {
53#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
54 SwitchedThread =
true;
62 void HandleCrash(
int RetCode, uintptr_t
Context) {
65 CurrentContext = Next;
67 assert(!Failed &&
"Crash recovery context already failed!");
70 if (CRC->DumpStackAndCleanupOnFailure)
73 CRC->RetCode = RetCode;
77 longjmp(JumpBuffer, 1);
84std::mutex &getCrashRecoveryContextMutex() {
85 static std::mutex CrashRecoveryContextMutex;
86 return CrashRecoveryContextMutex;
89static bool gCrashRecoveryEnabled =
false;
112 IsRecoveringFromCrash =
this;
120 IsRecoveringFromCrash = PC;
122 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
127 return IsRecoveringFromCrash !=
nullptr;
131 if (!gCrashRecoveryEnabled)
134 const CrashRecoveryContextImpl *CRCI = CurrentContext;
142 std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
144 if (gCrashRecoveryEnabled)
146 gCrashRecoveryEnabled =
true;
151 std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
152 if (!gCrashRecoveryEnabled)
154 gCrashRecoveryEnabled =
false;
175 head->prev =
nullptr;
203static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
205 const CrashRecoveryContextImpl *CRCI = CurrentContext;
211 return EXCEPTION_CONTINUE_SEARCH;
214 int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
215 if ((RetCode & 0xF0000000) == 0xE0000000)
216 RetCode &= ~0xF0000000;
219 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(
220 RetCode,
reinterpret_cast<uintptr_t
>(Except));
222 return EXCEPTION_EXECUTE_HANDLER;
225#if defined(__clang__) && defined(_M_IX86)
227__attribute__((optnone))
230 if (!gCrashRecoveryEnabled) {
234 assert(!Impl &&
"Crash recovery context already initialized!");
235 Impl =
new CrashRecoveryContextImpl(
this);
238 } __except (ExceptionFilter(GetExceptionInformation())) {
268static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
272 constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;
273 switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
275 case DBG_PRINTEXCEPTION_C:
276 case DbgPrintExceptionWideC:
278 return EXCEPTION_CONTINUE_EXECUTION;
282 const CrashRecoveryContextImpl *CRCI = CurrentContext;
288 return EXCEPTION_CONTINUE_SEARCH;
294 int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;
295 if ((RetCode & 0xF0000000) == 0xE0000000)
296 RetCode &= ~0xF0000000;
299 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(
300 RetCode,
reinterpret_cast<uintptr_t
>(ExceptionInfo));
320 PVOID
handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);
321 sCurrentExceptionHandle =
handle;
325 PVOID currentHandle =
const_cast<PVOID
>(sCurrentExceptionHandle);
328 ::RemoveVectoredExceptionHandler(currentHandle);
331 sCurrentExceptionHandle = NULL;
351 { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };
357 const CrashRecoveryContextImpl *CRCI = CurrentContext;
379 sigemptyset(&SigMask);
380 sigaddset(&SigMask, Signal);
381 sigprocmask(SIG_UNBLOCK, &SigMask,
nullptr);
386 int RetCode = 128 + Signal;
389 if (Signal == SIGPIPE)
393 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(RetCode, Signal);
399 struct sigaction Handler;
401 Handler.sa_flags = 0;
402 sigemptyset(&Handler.sa_mask);
405 if (NeedsPOSIXUtilitySignalHandling) {
407 struct sigaction act;
408 if (sigaction(
Signals[i], NULL, &act) == 0 && act.sa_handler != SIG_IGN)
426 if (gCrashRecoveryEnabled) {
427 assert(!Impl &&
"Crash recovery context already initialized!");
428 CrashRecoveryContextImpl *CRCI =
new CrashRecoveryContextImpl(
this);
431 CRCI->ValidJumpBuffer =
true;
432 if (setjmp(CRCI->JumpBuffer) != 0) {
449 ::RaiseException(0xE0000000 |
RetCode, 0, 0, NULL);
453 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;
454 assert(CRCI &&
"Crash recovery context never initialized!");
455 CRCI->HandleCrash(
RetCode, 0 );
467 if (Code != 0xC && Code != 8)
482 ::RaiseException(
RetCode, 0, 0, NULL);
493 setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
499 return getpriority(PRIO_DARWIN_THREAD, 0) == 1;
506struct RunSafelyOnThreadInfo {
507 function_ref<void()> Fn;
508 CrashRecoveryContext *CRC;
509 bool UseBackgroundPriority;
515 RunSafelyOnThreadInfo *Info =
516 reinterpret_cast<RunSafelyOnThreadInfo*
>(UserData);
518 if (Info->UseBackgroundPriority)
521 Info->Result = Info->CRC->RunSafely(Info->Fn);
524 unsigned RequestedStackSize) {
526 RunSafelyOnThreadInfo Info = { Fn,
this, UseBackgroundPriority,
false };
529 : std::optional<unsigned>(RequestedStackSize),
533 if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
534 CRC->setSwitchedThread();
539 unsigned RequestedStackSize) {
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static void cleanup(BlockFrequencyInfoImplBase &BFI)
Clear all memory not needed downstream.
#define LLVM_THREAD_LOCAL
\macro LLVM_THREAD_LOCAL A thread-local storage specifier which can be used with globals,...
static void installExceptionOrSignalHandlers(bool NeedsPOSIXUtilitySignalHandling)
static bool hasThreadBackgroundPriority()
static const unsigned NumSignals
static const int Signals[]
static void CrashRecoverySignalHandler(int Signal)
static void RunSafelyOnThread_Dispatch(void *UserData)
static void setThreadBackgroundPriority()
static void uninstallExceptionOrSignalHandlers()
static struct sigaction PrevActions[NumSignals]
This file contains definitions of exit codes for exit() function.
Abstract base class of cleanup handlers.
virtual ~CrashRecoveryContextCleanup()
virtual void recoverResources()=0
Crash recovery helper object.
static LLVM_ABI void Enable(bool NeedsPOSIXUtilitySignalHandling=false)
Enable crash recovery.
static LLVM_ABI bool isCrash(int RetCode)
Return true if RetCode indicates that a signal or an exception occurred.
static LLVM_ABI CrashRecoveryContext * GetCurrent()
Return the active context, if the code is currently executing in a thread which is in a protected con...
LLVM_ABI void HandleExit(int RetCode)
Explicitly trigger a crash recovery in the current process, and return failure from RunSafely().
LLVM_ABI ~CrashRecoveryContext()
LLVM_ABI bool RunSafelyOnNewStack(function_ref< void()>, unsigned RequestedStackSize=0)
LLVM_ABI void unregisterCleanup(CrashRecoveryContextCleanup *cleanup)
LLVM_ABI bool RunSafely(function_ref< void()> Fn)
Execute the provided callback function (with the given arguments) in a protected context.
static LLVM_ABI void Disable()
Disable crash recovery.
int RetCode
In case of a crash, this is the crash identifier.
static LLVM_ABI bool isRecoveringFromCrash()
Return true if the current thread is recovering from a crash.
static LLVM_ABI bool throwIfCrash(int RetCode)
Throw again a signal or an exception, after it was catched once by a CrashRecoveryContext.
LLVM_ABI void registerCleanup(CrashRecoveryContextCleanup *cleanup)
Register cleanup handler, which is used when the recovery context is finished.
LLVM_ABI CrashRecoveryContext()
LLVM_ABI bool RunSafelyOnThread(function_ref< void()>, unsigned RequestedStackSize=0)
Execute the provide callback function (with the given arguments) in a protected context which is run ...
An efficient, type-erasing, non-owning reference to a callable.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
IRHandle handle(const Type *Ty)
LLVM_ABI void DisableSystemDialogsOnCrash()
Disable all system dialog boxes that appear when the process crashes.
LLVM_ABI void unregisterHandlers()
LLVM_ABI void CleanupOnSignal(uintptr_t Context)
This function does the following:
This is an optimization pass for GlobalISel generic memory operations.
testing::Matcher< const detail::ErrorHolder & > Failed()