10#include "llvm/Config/llvm-config.h"
23struct CrashRecoveryContextImpl;
26struct CrashRecoveryContextImpl {
31 const CrashRecoveryContextImpl *Next;
35 volatile unsigned Failed : 1;
36 unsigned SwitchedThread : 1;
37 unsigned ValidJumpBuffer : 1;
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!");
77 longjmp(JumpBuffer, 1);
84std::mutex &getCrashRecoveryContextMutex() {
85 static std::mutex CrashRecoveryContextMutex;
86 return CrashRecoveryContextMutex;
89static bool gCrashRecoveryEnabled =
false;
111 IsRecoveringFromCrash =
this;
119 IsRecoveringFromCrash = PC;
121 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
126 return IsRecoveringFromCrash !=
nullptr;
130 if (!gCrashRecoveryEnabled)
133 const CrashRecoveryContextImpl *CRCI = CurrentContext;
141 std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
143 if (gCrashRecoveryEnabled)
145 gCrashRecoveryEnabled =
true;
150 std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
151 if (!gCrashRecoveryEnabled)
153 gCrashRecoveryEnabled =
false;
174 head->prev =
nullptr;
201static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
203 const CrashRecoveryContextImpl *CRCI = CurrentContext;
209 return EXCEPTION_CONTINUE_SEARCH;
212 int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
213 if ((RetCode & 0xF0000000) == 0xE0000000)
214 RetCode &= ~0xF0000000;
217 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(
218 RetCode,
reinterpret_cast<uintptr_t
>(Except));
220 return EXCEPTION_EXECUTE_HANDLER;
223#if defined(__clang__) && defined(_M_IX86)
225__attribute__((optnone))
228 if (!gCrashRecoveryEnabled) {
232 assert(!Impl &&
"Crash recovery context already initialized!");
233 Impl =
new CrashRecoveryContextImpl(
this);
236 } __except (ExceptionFilter(GetExceptionInformation())) {
266static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
270 constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;
271 switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
273 case DBG_PRINTEXCEPTION_C:
274 case DbgPrintExceptionWideC:
276 return EXCEPTION_CONTINUE_EXECUTION;
280 const CrashRecoveryContextImpl *CRCI = CurrentContext;
286 return EXCEPTION_CONTINUE_SEARCH;
292 int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;
293 if ((RetCode & 0xF0000000) == 0xE0000000)
294 RetCode &= ~0xF0000000;
297 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(
298 RetCode,
reinterpret_cast<uintptr_t
>(ExceptionInfo));
317 PVOID
handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);
318 sCurrentExceptionHandle =
handle;
322 PVOID currentHandle =
const_cast<PVOID
>(sCurrentExceptionHandle);
325 ::RemoveVectoredExceptionHandler(currentHandle);
328 sCurrentExceptionHandle = NULL;
348 { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };
354 const CrashRecoveryContextImpl *CRCI = CurrentContext;
376 sigemptyset(&SigMask);
377 sigaddset(&SigMask, Signal);
378 sigprocmask(SIG_UNBLOCK, &SigMask,
nullptr);
383 int RetCode = 128 + Signal;
386 if (Signal == SIGPIPE)
390 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(RetCode, Signal);
395 struct sigaction Handler;
397 Handler.sa_flags = 0;
398 sigemptyset(&Handler.sa_mask);
415 if (gCrashRecoveryEnabled) {
416 assert(!Impl &&
"Crash recovery context already initialized!");
417 CrashRecoveryContextImpl *CRCI =
new CrashRecoveryContextImpl(
this);
420 CRCI->ValidJumpBuffer =
true;
421 if (setjmp(CRCI->JumpBuffer) != 0) {
438 ::RaiseException(0xE0000000 |
RetCode, 0, 0, NULL);
442 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;
443 assert(CRCI &&
"Crash recovery context never initialized!");
444 CRCI->HandleCrash(
RetCode, 0 );
456 if (Code != 0xC && Code != 8)
471 ::RaiseException(
RetCode, 0, 0, NULL);
482 setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
488 return getpriority(PRIO_DARWIN_THREAD, 0) == 1;
495struct RunSafelyOnThreadInfo {
498 bool UseBackgroundPriority;
504 RunSafelyOnThreadInfo *
Info =
505 reinterpret_cast<RunSafelyOnThreadInfo*
>(UserData);
507 if (
Info->UseBackgroundPriority)
513 unsigned RequestedStackSize) {
515 RunSafelyOnThreadInfo
Info = { Fn,
this, UseBackgroundPriority,
false };
518 : std::optional<unsigned>(RequestedStackSize),
522 if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
523 CRC->setSwitchedThread();
528 unsigned RequestedStackSize) {
529#ifdef LLVM_HAS_SPLIT_STACKS
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static void cleanup(BlockFrequencyInfoImplBase &BFI)
Clear all memory not needed downstream.
Analysis containing CSE Info
#define LLVM_THREAD_LOCAL
\macro LLVM_THREAD_LOCAL A thread-local storage specifier which can be used with globals,...
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]
static void installExceptionOrSignalHandlers()
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 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()
static LLVM_ABI void Enable()
Enable crash recovery.
LLVM_ABI bool RunSafelyOnNewStack(function_ref< void()>, unsigned RequestedStackSize=0)
bool DumpStackAndCleanupOnFailure
Selects whether handling of failures should be done in the same way as for regular crashes.
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.
LLVM_ABI void runOnNewStack(unsigned StackSize, function_ref< void()> Fn)
Runs Fn on a new stack of at least the given size.
testing::Matcher< const detail::ErrorHolder & > Failed()