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