1 //===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Support/CrashRecoveryContext.h" 11 #include "llvm/ADT/STLExtras.h" 12 #include "llvm/Config/config.h" 13 #include "llvm/Support/ErrorHandling.h" 14 #include "llvm/Support/ManagedStatic.h" 15 #include "llvm/Support/Mutex.h" 16 #include "llvm/Support/ThreadLocal.h" 17 #include "llvm/Support/Threading.h" 18 #include <cassert> 19 #include <csetjmp> 20 21 using namespace llvm; 22 23 namespace { 24 25 struct CrashRecoveryContextImpl; 26 27 ManagedStatic< 28 sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext; 29 30 struct CrashRecoveryContextImpl { 31 // When threads are disabled, this links up all active 32 // CrashRecoveryContextImpls. When threads are enabled there's one thread 33 // per CrashRecoveryContext and CurrentContext is a thread-local, so only one 34 // CrashRecoveryContextImpl is active per thread and this is always null. 35 const CrashRecoveryContextImpl *Next; 36 37 CrashRecoveryContext *CRC; 38 ::jmp_buf JumpBuffer; 39 volatile unsigned Failed : 1; 40 unsigned SwitchedThread : 1; 41 42 public: 43 CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC), 44 Failed(false), 45 SwitchedThread(false) { 46 Next = CurrentContext->get(); 47 CurrentContext->set(this); 48 } 49 50 ~CrashRecoveryContextImpl() { 51 if (!SwitchedThread) 52 CurrentContext->set(Next); 53 } 54 55 /// \brief Called when the separate crash-recovery thread was finished, to 56 /// indicate that we don't need to clear the thread-local CurrentContext. 57 void setSwitchedThread() { 58 #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0 59 SwitchedThread = true; 60 #endif 61 } 62 63 void HandleCrash() { 64 // Eliminate the current context entry, to avoid re-entering in case the 65 // cleanup code crashes. 66 CurrentContext->set(Next); 67 68 assert(!Failed && "Crash recovery context already failed!"); 69 Failed = true; 70 71 // FIXME: Stash the backtrace. 72 73 // Jump back to the RunSafely we were called under. 74 longjmp(JumpBuffer, 1); 75 } 76 }; 77 78 ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex; 79 bool gCrashRecoveryEnabled = false; 80 81 ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>> 82 tlIsRecoveringFromCrash; 83 84 } // end anonymous namespace 85 86 CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} 87 88 CrashRecoveryContext::~CrashRecoveryContext() { 89 // Reclaim registered resources. 90 CrashRecoveryContextCleanup *i = head; 91 const CrashRecoveryContext *PC = tlIsRecoveringFromCrash->get(); 92 tlIsRecoveringFromCrash->set(this); 93 while (i) { 94 CrashRecoveryContextCleanup *tmp = i; 95 i = tmp->next; 96 tmp->cleanupFired = true; 97 tmp->recoverResources(); 98 delete tmp; 99 } 100 tlIsRecoveringFromCrash->set(PC); 101 102 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; 103 delete CRCI; 104 } 105 106 bool CrashRecoveryContext::isRecoveringFromCrash() { 107 return tlIsRecoveringFromCrash->get() != nullptr; 108 } 109 110 CrashRecoveryContext *CrashRecoveryContext::GetCurrent() { 111 if (!gCrashRecoveryEnabled) 112 return nullptr; 113 114 const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 115 if (!CRCI) 116 return nullptr; 117 118 return CRCI->CRC; 119 } 120 121 void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup) 122 { 123 if (!cleanup) 124 return; 125 if (head) 126 head->prev = cleanup; 127 cleanup->next = head; 128 head = cleanup; 129 } 130 131 void 132 CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { 133 if (!cleanup) 134 return; 135 if (cleanup == head) { 136 head = cleanup->next; 137 if (head) 138 head->prev = nullptr; 139 } 140 else { 141 cleanup->prev->next = cleanup->next; 142 if (cleanup->next) 143 cleanup->next->prev = cleanup->prev; 144 } 145 delete cleanup; 146 } 147 148 #ifdef LLVM_ON_WIN32 149 150 #include "Windows/WindowsSupport.h" 151 152 // On Windows, we can make use of vectored exception handling to 153 // catch most crashing situations. Note that this does mean 154 // we will be alerted of exceptions *before* structured exception 155 // handling has the opportunity to catch it. But that isn't likely 156 // to cause problems because nowhere in the project is SEH being 157 // used. 158 // 159 // Vectored exception handling is built on top of SEH, and so it 160 // works on a per-thread basis. 161 // 162 // The vectored exception handler functionality was added in Windows 163 // XP, so if support for older versions of Windows is required, 164 // it will have to be added. 165 // 166 // If we want to support as far back as Win2k, we could use the 167 // SetUnhandledExceptionFilter API, but there's a risk of that 168 // being entirely overwritten (it's not a chain). 169 170 namespace { 171 172 LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) 173 { 174 // Lookup the current thread local recovery object. 175 const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 176 177 if (!CRCI) { 178 // Something has gone horribly wrong, so let's just tell everyone 179 // to keep searching 180 CrashRecoveryContext::Disable(); 181 return EXCEPTION_CONTINUE_SEARCH; 182 } 183 184 // TODO: We can capture the stack backtrace here and store it on the 185 // implementation if we so choose. 186 187 // Handle the crash 188 const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); 189 190 // Note that we don't actually get here because HandleCrash calls 191 // longjmp, which means the HandleCrash function never returns. 192 llvm_unreachable("Handled the crash, should have longjmp'ed out of here"); 193 } 194 195 // Because the Enable and Disable calls are static, it means that 196 // there may not actually be an Impl available, or even a current 197 // CrashRecoveryContext at all. So we make use of a thread-local 198 // exception table. The handles contained in here will either be 199 // non-NULL, valid VEH handles, or NULL. 200 sys::ThreadLocal<const void> sCurrentExceptionHandle; 201 202 } // end anonymous namespace 203 204 void CrashRecoveryContext::Enable() { 205 sys::ScopedLock L(*gCrashRecoveryContextMutex); 206 207 if (gCrashRecoveryEnabled) 208 return; 209 210 gCrashRecoveryEnabled = true; 211 212 // We can set up vectored exception handling now. We will install our 213 // handler as the front of the list, though there's no assurances that 214 // it will remain at the front (another call could install itself before 215 // our handler). This 1) isn't likely, and 2) shouldn't cause problems. 216 PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler); 217 sCurrentExceptionHandle.set(handle); 218 } 219 220 void CrashRecoveryContext::Disable() { 221 sys::ScopedLock L(*gCrashRecoveryContextMutex); 222 223 if (!gCrashRecoveryEnabled) 224 return; 225 226 gCrashRecoveryEnabled = false; 227 228 PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get()); 229 if (currentHandle) { 230 // Now we can remove the vectored exception handler from the chain 231 ::RemoveVectoredExceptionHandler(currentHandle); 232 233 // Reset the handle in our thread-local set. 234 sCurrentExceptionHandle.set(NULL); 235 } 236 } 237 238 #else 239 240 // Generic POSIX implementation. 241 // 242 // This implementation relies on synchronous signals being delivered to the 243 // current thread. We use a thread local object to keep track of the active 244 // crash recovery context, and install signal handlers to invoke HandleCrash on 245 // the active object. 246 // 247 // This implementation does not to attempt to chain signal handlers in any 248 // reliable fashion -- if we get a signal outside of a crash recovery context we 249 // simply disable crash recovery and raise the signal again. 250 251 #include <csignal> 252 253 namespace { 254 255 const int Signals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP }; 256 const unsigned NumSignals = array_lengthof(Signals); 257 struct sigaction PrevActions[NumSignals]; 258 259 void CrashRecoverySignalHandler(int Signal) { 260 // Lookup the current thread local recovery object. 261 const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 262 263 if (!CRCI) { 264 // We didn't find a crash recovery context -- this means either we got a 265 // signal on a thread we didn't expect it on, the application got a signal 266 // outside of a crash recovery context, or something else went horribly 267 // wrong. 268 // 269 // Disable crash recovery and raise the signal again. The assumption here is 270 // that the enclosing application will terminate soon, and we won't want to 271 // attempt crash recovery again. 272 // 273 // This call of Disable isn't thread safe, but it doesn't actually matter. 274 CrashRecoveryContext::Disable(); 275 raise(Signal); 276 277 // The signal will be thrown once the signal mask is restored. 278 return; 279 } 280 281 // Unblock the signal we received. 282 sigset_t SigMask; 283 sigemptyset(&SigMask); 284 sigaddset(&SigMask, Signal); 285 sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); 286 287 if (CRCI) 288 const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); 289 } 290 291 } // end anonymous namespace 292 293 void CrashRecoveryContext::Enable() { 294 sys::ScopedLock L(*gCrashRecoveryContextMutex); 295 296 if (gCrashRecoveryEnabled) 297 return; 298 299 gCrashRecoveryEnabled = true; 300 301 // Setup the signal handler. 302 struct sigaction Handler; 303 Handler.sa_handler = CrashRecoverySignalHandler; 304 Handler.sa_flags = 0; 305 sigemptyset(&Handler.sa_mask); 306 307 for (unsigned i = 0; i != NumSignals; ++i) { 308 sigaction(Signals[i], &Handler, &PrevActions[i]); 309 } 310 } 311 312 void CrashRecoveryContext::Disable() { 313 sys::ScopedLock L(*gCrashRecoveryContextMutex); 314 315 if (!gCrashRecoveryEnabled) 316 return; 317 318 gCrashRecoveryEnabled = false; 319 320 // Restore the previous signal handlers. 321 for (unsigned i = 0; i != NumSignals; ++i) 322 sigaction(Signals[i], &PrevActions[i], nullptr); 323 } 324 325 #endif 326 327 bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { 328 // If crash recovery is disabled, do nothing. 329 if (gCrashRecoveryEnabled) { 330 assert(!Impl && "Crash recovery context already initialized!"); 331 CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this); 332 Impl = CRCI; 333 334 if (setjmp(CRCI->JumpBuffer) != 0) { 335 return false; 336 } 337 } 338 339 Fn(); 340 return true; 341 } 342 343 void CrashRecoveryContext::HandleCrash() { 344 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; 345 assert(CRCI && "Crash recovery context never initialized!"); 346 CRCI->HandleCrash(); 347 } 348 349 namespace { 350 351 // FIXME: Portability. 352 void setThreadBackgroundPriority() { 353 #ifdef __APPLE__ 354 setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); 355 #endif 356 } 357 358 bool hasThreadBackgroundPriority() { 359 #ifdef __APPLE__ 360 return getpriority(PRIO_DARWIN_THREAD, 0) == 1; 361 #else 362 return false; 363 #endif 364 } 365 366 struct RunSafelyOnThreadInfo { 367 function_ref<void()> Fn; 368 CrashRecoveryContext *CRC; 369 bool UseBackgroundPriority; 370 bool Result; 371 }; 372 373 void RunSafelyOnThread_Dispatch(void *UserData) { 374 RunSafelyOnThreadInfo *Info = 375 reinterpret_cast<RunSafelyOnThreadInfo*>(UserData); 376 377 if (Info->UseBackgroundPriority) 378 setThreadBackgroundPriority(); 379 380 Info->Result = Info->CRC->RunSafely(Info->Fn); 381 } 382 383 } // end anonymous namespace 384 385 bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn, 386 unsigned RequestedStackSize) { 387 bool UseBackgroundPriority = hasThreadBackgroundPriority(); 388 RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false }; 389 llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize); 390 if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl) 391 CRC->setSwitchedThread(); 392 return Info.Result; 393 } 394