10#include "llvm/Config/llvm-config.h"
19#include <sys/resource.h>
26struct CrashRecoveryContextImpl;
29struct CrashRecoveryContextImpl {
34 const CrashRecoveryContextImpl *Next;
36 CrashRecoveryContext *CRC;
38 volatile unsigned Failed : 1;
39 unsigned SwitchedThread : 1;
40 unsigned ValidJumpBuffer : 1;
43 CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept
44 : CRC(CRC),
Failed(
false), SwitchedThread(
false), ValidJumpBuffer(
false) {
45 Next = CurrentContext;
46 CurrentContext =
this;
48 ~CrashRecoveryContextImpl() {
50 CurrentContext = Next;
55 void setSwitchedThread() {
56#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
57 SwitchedThread =
true;
65 void HandleCrash(
int RetCode, uintptr_t
Context) {
68 CurrentContext = Next;
70 assert(!Failed &&
"Crash recovery context already failed!");
73 if (CRC->DumpStackAndCleanupOnFailure)
76 CRC->RetCode = RetCode;
80 longjmp(JumpBuffer, 1);
87std::mutex &getCrashRecoveryContextMutex() {
88 static std::mutex CrashRecoveryContextMutex;
89 return CrashRecoveryContextMutex;
92static bool gCrashRecoveryEnabled =
false;
115 IsRecoveringFromCrash =
this;
123 IsRecoveringFromCrash = PC;
125 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
130 return IsRecoveringFromCrash !=
nullptr;
134 if (!gCrashRecoveryEnabled)
137 const CrashRecoveryContextImpl *CRCI = CurrentContext;
145 std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
147 if (gCrashRecoveryEnabled)
149 gCrashRecoveryEnabled =
true;
154 std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
155 if (!gCrashRecoveryEnabled)
157 gCrashRecoveryEnabled =
false;
178 head->prev =
nullptr;
206static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
208 const CrashRecoveryContextImpl *CRCI = CurrentContext;
214 return EXCEPTION_CONTINUE_SEARCH;
217 int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
218 if ((RetCode & 0xF0000000) == 0xE0000000)
219 RetCode &= ~0xF0000000;
222 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(
223 RetCode,
reinterpret_cast<uintptr_t
>(Except));
225 return EXCEPTION_EXECUTE_HANDLER;
228#if defined(__clang__) && defined(_M_IX86)
230__attribute__((optnone))
233 if (!gCrashRecoveryEnabled) {
237 assert(!Impl &&
"Crash recovery context already initialized!");
238 Impl =
new CrashRecoveryContextImpl(
this);
241 } __except (ExceptionFilter(GetExceptionInformation())) {
271static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
275 constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;
276 switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
278 case DBG_PRINTEXCEPTION_C:
279 case DbgPrintExceptionWideC:
281 return EXCEPTION_CONTINUE_EXECUTION;
285 const CrashRecoveryContextImpl *CRCI = CurrentContext;
291 return EXCEPTION_CONTINUE_SEARCH;
297 int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;
298 if ((RetCode & 0xF0000000) == 0xE0000000)
299 RetCode &= ~0xF0000000;
302 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(
303 RetCode,
reinterpret_cast<uintptr_t
>(ExceptionInfo));
323 PVOID
handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);
324 sCurrentExceptionHandle =
handle;
328 PVOID currentHandle =
const_cast<PVOID
>(sCurrentExceptionHandle);
331 ::RemoveVectoredExceptionHandler(currentHandle);
334 sCurrentExceptionHandle = NULL;
354 { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };
360 const CrashRecoveryContextImpl *CRCI = CurrentContext;
382 sigemptyset(&SigMask);
383 sigaddset(&SigMask, Signal);
384 sigprocmask(SIG_UNBLOCK, &SigMask,
nullptr);
389 int RetCode = 128 + Signal;
392 if (Signal == SIGPIPE)
396 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(RetCode, Signal);
402 struct sigaction Handler;
404 Handler.sa_flags = 0;
405 sigemptyset(&Handler.sa_mask);
408 if (NeedsPOSIXUtilitySignalHandling) {
410 struct sigaction act;
411 if (sigaction(
Signals[i], NULL, &act) == 0 && act.sa_handler != SIG_IGN)
429 if (gCrashRecoveryEnabled) {
430 assert(!Impl &&
"Crash recovery context already initialized!");
431 CrashRecoveryContextImpl *CRCI =
new CrashRecoveryContextImpl(
this);
434 CRCI->ValidJumpBuffer =
true;
435 if (setjmp(CRCI->JumpBuffer) != 0) {
452 ::RaiseException(0xE0000000 |
RetCode, 0, 0, NULL);
456 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;
457 assert(CRCI &&
"Crash recovery context never initialized!");
458 CRCI->HandleCrash(
RetCode, 0 );
470 if (Code != 0xC && Code != 8)
485 ::RaiseException(
RetCode, 0, 0, NULL);
496 setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
502 return getpriority(PRIO_DARWIN_THREAD, 0) == 1;
509struct RunSafelyOnThreadInfo {
510 function_ref<void()> Fn;
511 CrashRecoveryContext *CRC;
512 bool UseBackgroundPriority;
518 RunSafelyOnThreadInfo *Info =
519 reinterpret_cast<RunSafelyOnThreadInfo*
>(UserData);
521 if (Info->UseBackgroundPriority)
524 Info->Result = Info->CRC->RunSafely(Info->Fn);
527 unsigned RequestedStackSize) {
529 RunSafelyOnThreadInfo Info = { Fn,
this, UseBackgroundPriority,
false };
532 : std::optional<unsigned>(RequestedStackSize),
536 if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
537 CRC->setSwitchedThread();
542 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()