CrashRecoveryContext.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. //===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/Support/CrashRecoveryContext.h"
  9. #include "llvm/Config/llvm-config.h"
  10. #include "llvm/Support/ErrorHandling.h"
  11. #include "llvm/Support/ExitCodes.h"
  12. #include "llvm/Support/Signals.h"
  13. #include "llvm/Support/thread.h"
  14. #include <cassert>
  15. #include <mutex>
  16. #include <setjmp.h>
  17. using namespace llvm;
  18. namespace {
  19. struct CrashRecoveryContextImpl;
  20. static LLVM_THREAD_LOCAL const CrashRecoveryContextImpl *CurrentContext;
  21. struct CrashRecoveryContextImpl {
  22. // When threads are disabled, this links up all active
  23. // CrashRecoveryContextImpls. When threads are enabled there's one thread
  24. // per CrashRecoveryContext and CurrentContext is a thread-local, so only one
  25. // CrashRecoveryContextImpl is active per thread and this is always null.
  26. const CrashRecoveryContextImpl *Next;
  27. CrashRecoveryContext *CRC;
  28. ::jmp_buf JumpBuffer;
  29. volatile unsigned Failed : 1;
  30. unsigned SwitchedThread : 1;
  31. unsigned ValidJumpBuffer : 1;
  32. public:
  33. CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept
  34. : CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) {
  35. Next = CurrentContext;
  36. CurrentContext = this;
  37. }
  38. ~CrashRecoveryContextImpl() {
  39. if (!SwitchedThread)
  40. CurrentContext = Next;
  41. }
  42. /// Called when the separate crash-recovery thread was finished, to
  43. /// indicate that we don't need to clear the thread-local CurrentContext.
  44. void setSwitchedThread() {
  45. #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
  46. SwitchedThread = true;
  47. #endif
  48. }
  49. // If the function ran by the CrashRecoveryContext crashes or fails, then
  50. // 'RetCode' represents the returned error code, as if it was returned by a
  51. // process. 'Context' represents the signal type on Unix; on Windows, it is
  52. // the ExceptionContext.
  53. void HandleCrash(int RetCode, uintptr_t Context) {
  54. // Eliminate the current context entry, to avoid re-entering in case the
  55. // cleanup code crashes.
  56. CurrentContext = Next;
  57. assert(!Failed && "Crash recovery context already failed!");
  58. Failed = true;
  59. if (CRC->DumpStackAndCleanupOnFailure)
  60. sys::CleanupOnSignal(Context);
  61. CRC->RetCode = RetCode;
  62. // Jump back to the RunSafely we were called under.
  63. if (ValidJumpBuffer)
  64. longjmp(JumpBuffer, 1);
  65. // Otherwise let the caller decide of the outcome of the crash. Currently
  66. // this occurs when using SEH on Windows with MSVC or clang-cl.
  67. }
  68. };
  69. std::mutex &getCrashRecoveryContextMutex() {
  70. static std::mutex CrashRecoveryContextMutex;
  71. return CrashRecoveryContextMutex;
  72. }
  73. static bool gCrashRecoveryEnabled = false;
  74. static LLVM_THREAD_LOCAL const CrashRecoveryContext *IsRecoveringFromCrash;
  75. } // namespace
  76. static void installExceptionOrSignalHandlers();
  77. static void uninstallExceptionOrSignalHandlers();
  78. CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() = default;
  79. CrashRecoveryContext::CrashRecoveryContext() {
  80. // On Windows, if abort() was previously triggered (and caught by a previous
  81. // CrashRecoveryContext) the Windows CRT removes our installed signal handler,
  82. // so we need to install it again.
  83. sys::DisableSystemDialogsOnCrash();
  84. }
  85. CrashRecoveryContext::~CrashRecoveryContext() {
  86. // Reclaim registered resources.
  87. CrashRecoveryContextCleanup *i = head;
  88. const CrashRecoveryContext *PC = IsRecoveringFromCrash;
  89. IsRecoveringFromCrash = this;
  90. while (i) {
  91. CrashRecoveryContextCleanup *tmp = i;
  92. i = tmp->next;
  93. tmp->cleanupFired = true;
  94. tmp->recoverResources();
  95. delete tmp;
  96. }
  97. IsRecoveringFromCrash = PC;
  98. CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
  99. delete CRCI;
  100. }
  101. bool CrashRecoveryContext::isRecoveringFromCrash() {
  102. return IsRecoveringFromCrash != nullptr;
  103. }
  104. CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {
  105. if (!gCrashRecoveryEnabled)
  106. return nullptr;
  107. const CrashRecoveryContextImpl *CRCI = CurrentContext;
  108. if (!CRCI)
  109. return nullptr;
  110. return CRCI->CRC;
  111. }
  112. void CrashRecoveryContext::Enable() {
  113. std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
  114. // FIXME: Shouldn't this be a refcount or something?
  115. if (gCrashRecoveryEnabled)
  116. return;
  117. gCrashRecoveryEnabled = true;
  118. installExceptionOrSignalHandlers();
  119. }
  120. void CrashRecoveryContext::Disable() {
  121. std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
  122. if (!gCrashRecoveryEnabled)
  123. return;
  124. gCrashRecoveryEnabled = false;
  125. uninstallExceptionOrSignalHandlers();
  126. }
  127. void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup)
  128. {
  129. if (!cleanup)
  130. return;
  131. if (head)
  132. head->prev = cleanup;
  133. cleanup->next = head;
  134. head = cleanup;
  135. }
  136. void
  137. CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {
  138. if (!cleanup)
  139. return;
  140. if (cleanup == head) {
  141. head = cleanup->next;
  142. if (head)
  143. head->prev = nullptr;
  144. }
  145. else {
  146. cleanup->prev->next = cleanup->next;
  147. if (cleanup->next)
  148. cleanup->next->prev = cleanup->prev;
  149. }
  150. delete cleanup;
  151. }
  152. #if defined(_MSC_VER)
  153. #include <windows.h> // for GetExceptionInformation
  154. // If _MSC_VER is defined, we must have SEH. Use it if it's available. It's way
  155. // better than VEH. Vectored exception handling catches all exceptions happening
  156. // on the thread with installed exception handlers, so it can interfere with
  157. // internal exception handling of other libraries on that thread. SEH works
  158. // exactly as you would expect normal exception handling to work: it only
  159. // catches exceptions if they would bubble out from the stack frame with __try /
  160. // __except.
  161. static void installExceptionOrSignalHandlers() {}
  162. static void uninstallExceptionOrSignalHandlers() {}
  163. // We need this function because the call to GetExceptionInformation() can only
  164. // occur inside the __except evaluation block
  165. static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
  166. // Lookup the current thread local recovery object.
  167. const CrashRecoveryContextImpl *CRCI = CurrentContext;
  168. if (!CRCI) {
  169. // Something has gone horribly wrong, so let's just tell everyone
  170. // to keep searching
  171. CrashRecoveryContext::Disable();
  172. return EXCEPTION_CONTINUE_SEARCH;
  173. }
  174. int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
  175. if ((RetCode & 0xF0000000) == 0xE0000000)
  176. RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit
  177. // Handle the crash
  178. const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
  179. RetCode, reinterpret_cast<uintptr_t>(Except));
  180. return EXCEPTION_EXECUTE_HANDLER;
  181. }
  182. #if defined(__clang__) && defined(_M_IX86)
  183. // Work around PR44697.
  184. __attribute__((optnone))
  185. #endif
  186. bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
  187. if (!gCrashRecoveryEnabled) {
  188. Fn();
  189. return true;
  190. }
  191. assert(!Impl && "Crash recovery context already initialized!");
  192. Impl = new CrashRecoveryContextImpl(this);
  193. __try {
  194. Fn();
  195. } __except (ExceptionFilter(GetExceptionInformation())) {
  196. return false;
  197. }
  198. return true;
  199. }
  200. #else // !_MSC_VER
  201. #if defined(_WIN32)
  202. // This is a non-MSVC compiler, probably mingw gcc or clang without
  203. // -fms-extensions. Use vectored exception handling (VEH).
  204. //
  205. // On Windows, we can make use of vectored exception handling to catch most
  206. // crashing situations. Note that this does mean we will be alerted of
  207. // exceptions *before* structured exception handling has the opportunity to
  208. // catch it. Unfortunately, this causes problems in practice with other code
  209. // running on threads with LLVM crash recovery contexts, so we would like to
  210. // eventually move away from VEH.
  211. //
  212. // Vectored works on a per-thread basis, which is an advantage over
  213. // SetUnhandledExceptionFilter. SetUnhandledExceptionFilter also doesn't have
  214. // any native support for chaining exception handlers, but VEH allows more than
  215. // one.
  216. //
  217. // The vectored exception handler functionality was added in Windows
  218. // XP, so if support for older versions of Windows is required,
  219. // it will have to be added.
  220. #include "llvm/Support/Windows/WindowsSupport.h"
  221. static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
  222. {
  223. // DBG_PRINTEXCEPTION_WIDE_C is not properly defined on all supported
  224. // compilers and platforms, so we define it manually.
  225. constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;
  226. switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
  227. {
  228. case DBG_PRINTEXCEPTION_C:
  229. case DbgPrintExceptionWideC:
  230. case 0x406D1388: // set debugger thread name
  231. return EXCEPTION_CONTINUE_EXECUTION;
  232. }
  233. // Lookup the current thread local recovery object.
  234. const CrashRecoveryContextImpl *CRCI = CurrentContext;
  235. if (!CRCI) {
  236. // Something has gone horribly wrong, so let's just tell everyone
  237. // to keep searching
  238. CrashRecoveryContext::Disable();
  239. return EXCEPTION_CONTINUE_SEARCH;
  240. }
  241. // TODO: We can capture the stack backtrace here and store it on the
  242. // implementation if we so choose.
  243. int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;
  244. if ((RetCode & 0xF0000000) == 0xE0000000)
  245. RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit
  246. // Handle the crash
  247. const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
  248. RetCode, reinterpret_cast<uintptr_t>(ExceptionInfo));
  249. // Note that we don't actually get here because HandleCrash calls
  250. // longjmp, which means the HandleCrash function never returns.
  251. llvm_unreachable("Handled the crash, should have longjmp'ed out of here");
  252. }
  253. // Because the Enable and Disable calls are static, it means that
  254. // there may not actually be an Impl available, or even a current
  255. // CrashRecoveryContext at all. So we make use of a thread-local
  256. // exception table. The handles contained in here will either be
  257. // non-NULL, valid VEH handles, or NULL.
  258. static LLVM_THREAD_LOCAL const void* sCurrentExceptionHandle;
  259. static void installExceptionOrSignalHandlers() {
  260. // We can set up vectored exception handling now. We will install our
  261. // handler as the front of the list, though there's no assurances that
  262. // it will remain at the front (another call could install itself before
  263. // our handler). This 1) isn't likely, and 2) shouldn't cause problems.
  264. PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);
  265. sCurrentExceptionHandle = handle;
  266. }
  267. static void uninstallExceptionOrSignalHandlers() {
  268. PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle);
  269. if (currentHandle) {
  270. // Now we can remove the vectored exception handler from the chain
  271. ::RemoveVectoredExceptionHandler(currentHandle);
  272. // Reset the handle in our thread-local set.
  273. sCurrentExceptionHandle = NULL;
  274. }
  275. }
  276. #else // !_WIN32
  277. // Generic POSIX implementation.
  278. //
  279. // This implementation relies on synchronous signals being delivered to the
  280. // current thread. We use a thread local object to keep track of the active
  281. // crash recovery context, and install signal handlers to invoke HandleCrash on
  282. // the active object.
  283. //
  284. // This implementation does not attempt to chain signal handlers in any
  285. // reliable fashion -- if we get a signal outside of a crash recovery context we
  286. // simply disable crash recovery and raise the signal again.
  287. #include <signal.h>
  288. static const int Signals[] =
  289. { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };
  290. static const unsigned NumSignals = std::size(Signals);
  291. static struct sigaction PrevActions[NumSignals];
  292. static void CrashRecoverySignalHandler(int Signal) {
  293. // Lookup the current thread local recovery object.
  294. const CrashRecoveryContextImpl *CRCI = CurrentContext;
  295. if (!CRCI) {
  296. // We didn't find a crash recovery context -- this means either we got a
  297. // signal on a thread we didn't expect it on, the application got a signal
  298. // outside of a crash recovery context, or something else went horribly
  299. // wrong.
  300. //
  301. // Disable crash recovery and raise the signal again. The assumption here is
  302. // that the enclosing application will terminate soon, and we won't want to
  303. // attempt crash recovery again.
  304. //
  305. // This call of Disable isn't thread safe, but it doesn't actually matter.
  306. CrashRecoveryContext::Disable();
  307. raise(Signal);
  308. // The signal will be thrown once the signal mask is restored.
  309. return;
  310. }
  311. // Unblock the signal we received.
  312. sigset_t SigMask;
  313. sigemptyset(&SigMask);
  314. sigaddset(&SigMask, Signal);
  315. sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
  316. // Return the same error code as if the program crashed, as mentioned in the
  317. // section "Exit Status for Commands":
  318. // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html
  319. int RetCode = 128 + Signal;
  320. // Don't consider a broken pipe as a crash (see clang/lib/Driver/Driver.cpp)
  321. if (Signal == SIGPIPE)
  322. RetCode = EX_IOERR;
  323. if (CRCI)
  324. const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(RetCode, Signal);
  325. }
  326. static void installExceptionOrSignalHandlers() {
  327. // Setup the signal handler.
  328. struct sigaction Handler;
  329. Handler.sa_handler = CrashRecoverySignalHandler;
  330. Handler.sa_flags = 0;
  331. sigemptyset(&Handler.sa_mask);
  332. for (unsigned i = 0; i != NumSignals; ++i) {
  333. sigaction(Signals[i], &Handler, &PrevActions[i]);
  334. }
  335. }
  336. static void uninstallExceptionOrSignalHandlers() {
  337. // Restore the previous signal handlers.
  338. for (unsigned i = 0; i != NumSignals; ++i)
  339. sigaction(Signals[i], &PrevActions[i], nullptr);
  340. }
  341. #endif // !_WIN32
  342. bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
  343. // If crash recovery is disabled, do nothing.
  344. if (gCrashRecoveryEnabled) {
  345. assert(!Impl && "Crash recovery context already initialized!");
  346. CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this);
  347. Impl = CRCI;
  348. CRCI->ValidJumpBuffer = true;
  349. if (setjmp(CRCI->JumpBuffer) != 0) {
  350. return false;
  351. }
  352. }
  353. Fn();
  354. return true;
  355. }
  356. #endif // !_MSC_VER
  357. [[noreturn]] void CrashRecoveryContext::HandleExit(int RetCode) {
  358. #if defined(_WIN32)
  359. // SEH and VEH
  360. ::RaiseException(0xE0000000 | RetCode, 0, 0, NULL);
  361. #else
  362. // On Unix we don't need to raise an exception, we go directly to
  363. // HandleCrash(), then longjmp will unwind the stack for us.
  364. CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;
  365. assert(CRCI && "Crash recovery context never initialized!");
  366. CRCI->HandleCrash(RetCode, 0 /*no sig num*/);
  367. #endif
  368. llvm_unreachable("Most likely setjmp wasn't called!");
  369. }
  370. bool CrashRecoveryContext::isCrash(int RetCode) {
  371. #if defined(_WIN32)
  372. // On Windows, the high bits are reserved for kernel return codes. Values
  373. // starting with 0x80000000 are reserved for "warnings"; values of 0xC0000000
  374. // and up are for "errors". In practice, both are interpreted as a
  375. // non-continuable signal.
  376. unsigned Code = ((unsigned)RetCode & 0xF0000000) >> 28;
  377. if (Code != 0xC && Code != 8)
  378. return false;
  379. #else
  380. // On Unix, signals are represented by return codes of 128 or higher.
  381. // Exit code 128 is a reserved value and should not be raised as a signal.
  382. if (RetCode <= 128)
  383. return false;
  384. #endif
  385. return true;
  386. }
  387. bool CrashRecoveryContext::throwIfCrash(int RetCode) {
  388. if (!isCrash(RetCode))
  389. return false;
  390. #if defined(_WIN32)
  391. ::RaiseException(RetCode, 0, 0, NULL);
  392. #else
  393. llvm::sys::unregisterHandlers();
  394. raise(RetCode - 128);
  395. #endif
  396. return true;
  397. }
  398. // FIXME: Portability.
  399. static void setThreadBackgroundPriority() {
  400. #ifdef __APPLE__
  401. setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
  402. #endif
  403. }
  404. static bool hasThreadBackgroundPriority() {
  405. #ifdef __APPLE__
  406. return getpriority(PRIO_DARWIN_THREAD, 0) == 1;
  407. #else
  408. return false;
  409. #endif
  410. }
  411. namespace {
  412. struct RunSafelyOnThreadInfo {
  413. function_ref<void()> Fn;
  414. CrashRecoveryContext *CRC;
  415. bool UseBackgroundPriority;
  416. bool Result;
  417. };
  418. } // namespace
  419. static void RunSafelyOnThread_Dispatch(void *UserData) {
  420. RunSafelyOnThreadInfo *Info =
  421. reinterpret_cast<RunSafelyOnThreadInfo*>(UserData);
  422. if (Info->UseBackgroundPriority)
  423. setThreadBackgroundPriority();
  424. Info->Result = Info->CRC->RunSafely(Info->Fn);
  425. }
  426. bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn,
  427. unsigned RequestedStackSize) {
  428. bool UseBackgroundPriority = hasThreadBackgroundPriority();
  429. RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };
  430. llvm::thread Thread(RequestedStackSize == 0
  431. ? std::nullopt
  432. : std::optional<unsigned>(RequestedStackSize),
  433. RunSafelyOnThread_Dispatch, &Info);
  434. Thread.join();
  435. if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
  436. CRC->setSwitchedThread();
  437. return Info.Result;
  438. }