LLVM: lib/Support/CrashRecoveryContext.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
10#include "llvm/Config/llvm-config.h"
15#include
16#include
17#include <setjmp.h>
18
19using namespace llvm;
20
21namespace {
22
23struct CrashRecoveryContextImpl;
24static LLVM_THREAD_LOCAL const CrashRecoveryContextImpl *CurrentContext;
25
26struct CrashRecoveryContextImpl {
27
28
29
30
31 const CrashRecoveryContextImpl *Next;
32
33 CrashRecoveryContext *CRC;
34 ::jmp_buf JumpBuffer;
35 volatile unsigned Failed : 1;
36 unsigned SwitchedThread : 1;
37 unsigned ValidJumpBuffer : 1;
38
39public:
40 CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept
41 : CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) {
42 Next = CurrentContext;
43 CurrentContext = this;
44 }
45 ~CrashRecoveryContextImpl() {
46 if (!SwitchedThread)
47 CurrentContext = Next;
48 }
49
50
51
52 void setSwitchedThread() {
53#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
54 SwitchedThread = true;
55#endif
56 }
57
58
59
60
61
62 void HandleCrash(int RetCode, uintptr_t Context) {
63
64
65 CurrentContext = Next;
66
67 assert(!Failed && "Crash recovery context already failed!");
68 Failed = true;
69
70 if (CRC->DumpStackAndCleanupOnFailure)
72
73 CRC->RetCode = RetCode;
74
75
76 if (ValidJumpBuffer)
77 longjmp(JumpBuffer, 1);
78
79
80
81 }
82};
83
84std::mutex &getCrashRecoveryContextMutex() {
85 static std::mutex CrashRecoveryContextMutex;
86 return CrashRecoveryContextMutex;
87}
88
89static bool gCrashRecoveryEnabled = false;
90
92
93}
94
97
99
106
108
111 IsRecoveringFromCrash = this;
112 while (i) {
114 i = tmp->next;
117 delete tmp;
118 }
119 IsRecoveringFromCrash = PC;
120
121 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
122 delete CRCI;
123}
124
126 return IsRecoveringFromCrash != nullptr;
127}
128
130 if (!gCrashRecoveryEnabled)
131 return nullptr;
132
133 const CrashRecoveryContextImpl *CRCI = CurrentContext;
134 if (!CRCI)
135 return nullptr;
136
137 return CRCI->CRC;
138}
139
141 std::lock_guardstd::mutex L(getCrashRecoveryContextMutex());
142
143 if (gCrashRecoveryEnabled)
144 return;
145 gCrashRecoveryEnabled = true;
147}
148
150 std::lock_guardstd::mutex L(getCrashRecoveryContextMutex());
151 if (!gCrashRecoveryEnabled)
152 return;
153 gCrashRecoveryEnabled = false;
155}
156
158{
160 return;
161 if (head)
165}
166
167void
170 return;
173 if (head)
174 head->prev = nullptr;
175 }
176 else {
180 }
182}
183
184#if defined(_MSC_VER)
185
186#include <windows.h>
187
188
189
190
191
192
193
194
195
198
199
200
201static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
202
203 const CrashRecoveryContextImpl *CRCI = CurrentContext;
204
205 if (!CRCI) {
206
207
209 return EXCEPTION_CONTINUE_SEARCH;
210 }
211
212 int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
213 if ((RetCode & 0xF0000000) == 0xE0000000)
214 RetCode &= ~0xF0000000;
215
216
217 const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
218 RetCode, reinterpret_cast<uintptr_t>(Except));
219
220 return EXCEPTION_EXECUTE_HANDLER;
221}
222
223#if defined(__clang__) && defined(_M_IX86)
224
225__attribute__((optnone))
226#endif
228 if (!gCrashRecoveryEnabled) {
229 Fn();
230 return true;
231 }
232 assert(!Impl && "Crash recovery context already initialized!");
233 Impl = new CrashRecoveryContextImpl(this);
234 __try {
235 Fn();
236 } __except (ExceptionFilter(GetExceptionInformation())) {
237 return false;
238 }
239 return true;
240}
241
242#else
243
244#if defined(_WIN32)
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
265
266static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
267{
268
269
270 constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;
271 switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
272 {
273 case DBG_PRINTEXCEPTION_C:
274 case DbgPrintExceptionWideC:
275 case 0x406D1388:
276 return EXCEPTION_CONTINUE_EXECUTION;
277 }
278
279
280 const CrashRecoveryContextImpl *CRCI = CurrentContext;
281
282 if (!CRCI) {
283
284
286 return EXCEPTION_CONTINUE_SEARCH;
287 }
288
289
290
291
292 int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;
293 if ((RetCode & 0xF0000000) == 0xE0000000)
294 RetCode &= ~0xF0000000;
295
296
297 const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
298 RetCode, reinterpret_cast<uintptr_t>(ExceptionInfo));
299
300
301
302 llvm_unreachable("Handled the crash, should have longjmp'ed out of here");
303}
304
305
306
307
308
309
311
313
314
315
316
317 PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);
318 sCurrentExceptionHandle = handle;
319}
320
322 PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle);
323 if (currentHandle) {
324
325 ::RemoveVectoredExceptionHandler(currentHandle);
326
327
328 sCurrentExceptionHandle = NULL;
329 }
330}
331
332#else
333
334
335
336
337
338
339
340
341
342
343
344
345#include <signal.h>
346
348 { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };
351
353
354 const CrashRecoveryContextImpl *CRCI = CurrentContext;
355
356 if (!CRCI) {
357
358
359
360
361
362
363
364
365
366
368 raise(Signal);
369
370
371 return;
372 }
373
374
375 sigset_t SigMask;
376 sigemptyset(&SigMask);
377 sigaddset(&SigMask, Signal);
378 sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
379
380
381
382
383 int RetCode = 128 + Signal;
384
385
386 if (Signal == SIGPIPE)
387 RetCode = EX_IOERR;
388
389 if (CRCI)
390 const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(RetCode, Signal);
391}
392
394
395 struct sigaction Handler;
397 Handler.sa_flags = 0;
398 sigemptyset(&Handler.sa_mask);
399
400 for (unsigned i = 0; i != NumSignals; ++i) {
402 }
403}
404
406
407 for (unsigned i = 0; i != NumSignals; ++i)
409}
410
411#endif
412
414
415 if (gCrashRecoveryEnabled) {
416 assert(!Impl && "Crash recovery context already initialized!");
417 CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this);
418 Impl = CRCI;
419
420 CRCI->ValidJumpBuffer = true;
421 if (setjmp(CRCI->JumpBuffer) != 0) {
422 return false;
423 }
424 }
425
426 Fn();
427 return true;
428}
429
430#endif
431
433#if defined(_WIN32)
434
435
436
437
438 ::RaiseException(0xE0000000 | RetCode, 0, 0, NULL);
439#else
440
441
442 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;
443 assert(CRCI && "Crash recovery context never initialized!");
444 CRCI->HandleCrash(RetCode, 0 );
445#endif
447}
448
450#if defined(_WIN32)
451
452
453
454
456 if (Code != 0xC && Code != 8)
457 return false;
458#else
459
460
462 return false;
463#endif
464 return true;
465}
466
469 return false;
470#if defined(_WIN32)
471 ::RaiseException(RetCode, 0, 0, NULL);
472#else
475#endif
476 return true;
477}
478
479
481#ifdef __APPLE__
482 setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
483#endif
484}
485
487#ifdef __APPLE__
488 return getpriority(PRIO_DARWIN_THREAD, 0) == 1;
489#else
490 return false;
491#endif
492}
493
494namespace {
495struct RunSafelyOnThreadInfo {
496 function_ref<void()> Fn;
497 CrashRecoveryContext *CRC;
498 bool UseBackgroundPriority;
500};
501}
502
504 RunSafelyOnThreadInfo *Info =
505 reinterpret_cast<RunSafelyOnThreadInfo*>(UserData);
506
507 if (Info->UseBackgroundPriority)
509
510 Info->Result = Info->CRC->RunSafely(Info->Fn);
511}
513 unsigned RequestedStackSize) {
515 RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };
517 ? std::nullopt
518 : std::optional(RequestedStackSize),
520 Thread.join();
521
522 if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
523 CRC->setSwitchedThread();
524 return Info.Result;
525}
526
528 unsigned RequestedStackSize) {
529#ifdef LLVM_HAS_SPLIT_STACKS
532#else
534#endif
535}
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()
Definition CrashRecoveryContext.cpp:486
static const unsigned NumSignals
Definition CrashRecoveryContext.cpp:349
static const int Signals[]
Definition CrashRecoveryContext.cpp:347
static void CrashRecoverySignalHandler(int Signal)
Definition CrashRecoveryContext.cpp:352
static void RunSafelyOnThread_Dispatch(void *UserData)
Definition CrashRecoveryContext.cpp:503
static void setThreadBackgroundPriority()
Definition CrashRecoveryContext.cpp:480
static void uninstallExceptionOrSignalHandlers()
Definition CrashRecoveryContext.cpp:405
static struct sigaction PrevActions[NumSignals]
Definition CrashRecoveryContext.cpp:350
static void installExceptionOrSignalHandlers()
Definition CrashRecoveryContext.cpp:393
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.
Definition CrashRecoveryContext.cpp:449
static LLVM_ABI CrashRecoveryContext * GetCurrent()
Return the active context, if the code is currently executing in a thread which is in a protected con...
Definition CrashRecoveryContext.cpp:129
LLVM_ABI void HandleExit(int RetCode)
Explicitly trigger a crash recovery in the current process, and return failure from RunSafely().
Definition CrashRecoveryContext.cpp:432
LLVM_ABI ~CrashRecoveryContext()
Definition CrashRecoveryContext.cpp:107
static LLVM_ABI void Enable()
Enable crash recovery.
Definition CrashRecoveryContext.cpp:140
LLVM_ABI bool RunSafelyOnNewStack(function_ref< void()>, unsigned RequestedStackSize=0)
Definition CrashRecoveryContext.cpp:527
LLVM_ABI void unregisterCleanup(CrashRecoveryContextCleanup *cleanup)
Definition CrashRecoveryContext.cpp:168
LLVM_ABI bool RunSafely(function_ref< void()> Fn)
Execute the provided callback function (with the given arguments) in a protected context.
Definition CrashRecoveryContext.cpp:413
static LLVM_ABI void Disable()
Disable crash recovery.
Definition CrashRecoveryContext.cpp:149
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.
Definition CrashRecoveryContext.cpp:125
static LLVM_ABI bool throwIfCrash(int RetCode)
Throw again a signal or an exception, after it was catched once by a CrashRecoveryContext.
Definition CrashRecoveryContext.cpp:467
LLVM_ABI void registerCleanup(CrashRecoveryContextCleanup *cleanup)
Register cleanup handler, which is used when the recovery context is finished.
Definition CrashRecoveryContext.cpp:157
LLVM_ABI CrashRecoveryContext()
Definition CrashRecoveryContext.cpp:100
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 ...
Definition CrashRecoveryContext.cpp:512
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()