LLVM API Documentation
00001 //===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 00010 #include "llvm/Support/CrashRecoveryContext.h" 00011 #include "llvm/ADT/SmallString.h" 00012 #include "llvm/Config/config.h" 00013 #include "llvm/Support/ErrorHandling.h" 00014 #include "llvm/Support/ManagedStatic.h" 00015 #include "llvm/Support/Mutex.h" 00016 #include "llvm/Support/ThreadLocal.h" 00017 #include <cstdio> 00018 #include <setjmp.h> 00019 using namespace llvm; 00020 00021 namespace { 00022 00023 struct CrashRecoveryContextImpl; 00024 00025 static ManagedStatic< 00026 sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext; 00027 00028 struct CrashRecoveryContextImpl { 00029 CrashRecoveryContext *CRC; 00030 std::string Backtrace; 00031 ::jmp_buf JumpBuffer; 00032 volatile unsigned Failed : 1; 00033 unsigned SwitchedThread : 1; 00034 00035 public: 00036 CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC), 00037 Failed(false), 00038 SwitchedThread(false) { 00039 CurrentContext->set(this); 00040 } 00041 ~CrashRecoveryContextImpl() { 00042 if (!SwitchedThread) 00043 CurrentContext->erase(); 00044 } 00045 00046 /// \brief Called when the separate crash-recovery thread was finished, to 00047 /// indicate that we don't need to clear the thread-local CurrentContext. 00048 void setSwitchedThread() { SwitchedThread = true; } 00049 00050 void HandleCrash() { 00051 // Eliminate the current context entry, to avoid re-entering in case the 00052 // cleanup code crashes. 00053 CurrentContext->erase(); 00054 00055 assert(!Failed && "Crash recovery context already failed!"); 00056 Failed = true; 00057 00058 // FIXME: Stash the backtrace. 00059 00060 // Jump back to the RunSafely we were called under. 00061 longjmp(JumpBuffer, 1); 00062 } 00063 }; 00064 00065 } 00066 00067 static ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex; 00068 static bool gCrashRecoveryEnabled = false; 00069 00070 static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextCleanup> > 00071 tlIsRecoveringFromCrash; 00072 00073 CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} 00074 00075 CrashRecoveryContext::~CrashRecoveryContext() { 00076 // Reclaim registered resources. 00077 CrashRecoveryContextCleanup *i = head; 00078 tlIsRecoveringFromCrash->set(head); 00079 while (i) { 00080 CrashRecoveryContextCleanup *tmp = i; 00081 i = tmp->next; 00082 tmp->cleanupFired = true; 00083 tmp->recoverResources(); 00084 delete tmp; 00085 } 00086 tlIsRecoveringFromCrash->erase(); 00087 00088 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; 00089 delete CRCI; 00090 } 00091 00092 bool CrashRecoveryContext::isRecoveringFromCrash() { 00093 return tlIsRecoveringFromCrash->get() != nullptr; 00094 } 00095 00096 CrashRecoveryContext *CrashRecoveryContext::GetCurrent() { 00097 if (!gCrashRecoveryEnabled) 00098 return nullptr; 00099 00100 const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 00101 if (!CRCI) 00102 return nullptr; 00103 00104 return CRCI->CRC; 00105 } 00106 00107 void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup) 00108 { 00109 if (!cleanup) 00110 return; 00111 if (head) 00112 head->prev = cleanup; 00113 cleanup->next = head; 00114 head = cleanup; 00115 } 00116 00117 void 00118 CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { 00119 if (!cleanup) 00120 return; 00121 if (cleanup == head) { 00122 head = cleanup->next; 00123 if (head) 00124 head->prev = nullptr; 00125 } 00126 else { 00127 cleanup->prev->next = cleanup->next; 00128 if (cleanup->next) 00129 cleanup->next->prev = cleanup->prev; 00130 } 00131 delete cleanup; 00132 } 00133 00134 #ifdef LLVM_ON_WIN32 00135 00136 #include "Windows/WindowsSupport.h" 00137 00138 // On Windows, we can make use of vectored exception handling to 00139 // catch most crashing situations. Note that this does mean 00140 // we will be alerted of exceptions *before* structured exception 00141 // handling has the opportunity to catch it. But that isn't likely 00142 // to cause problems because nowhere in the project is SEH being 00143 // used. 00144 // 00145 // Vectored exception handling is built on top of SEH, and so it 00146 // works on a per-thread basis. 00147 // 00148 // The vectored exception handler functionality was added in Windows 00149 // XP, so if support for older versions of Windows is required, 00150 // it will have to be added. 00151 // 00152 // If we want to support as far back as Win2k, we could use the 00153 // SetUnhandledExceptionFilter API, but there's a risk of that 00154 // being entirely overwritten (it's not a chain). 00155 00156 static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) 00157 { 00158 // Lookup the current thread local recovery object. 00159 const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 00160 00161 if (!CRCI) { 00162 // Something has gone horribly wrong, so let's just tell everyone 00163 // to keep searching 00164 CrashRecoveryContext::Disable(); 00165 return EXCEPTION_CONTINUE_SEARCH; 00166 } 00167 00168 // TODO: We can capture the stack backtrace here and store it on the 00169 // implementation if we so choose. 00170 00171 // Handle the crash 00172 const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); 00173 00174 // Note that we don't actually get here because HandleCrash calls 00175 // longjmp, which means the HandleCrash function never returns. 00176 llvm_unreachable("Handled the crash, should have longjmp'ed out of here"); 00177 } 00178 00179 // Because the Enable and Disable calls are static, it means that 00180 // there may not actually be an Impl available, or even a current 00181 // CrashRecoveryContext at all. So we make use of a thread-local 00182 // exception table. The handles contained in here will either be 00183 // non-NULL, valid VEH handles, or NULL. 00184 static sys::ThreadLocal<const void> sCurrentExceptionHandle; 00185 00186 void CrashRecoveryContext::Enable() { 00187 sys::ScopedLock L(*gCrashRecoveryContextMutex); 00188 00189 if (gCrashRecoveryEnabled) 00190 return; 00191 00192 gCrashRecoveryEnabled = true; 00193 00194 // We can set up vectored exception handling now. We will install our 00195 // handler as the front of the list, though there's no assurances that 00196 // it will remain at the front (another call could install itself before 00197 // our handler). This 1) isn't likely, and 2) shouldn't cause problems. 00198 PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler); 00199 sCurrentExceptionHandle.set(handle); 00200 } 00201 00202 void CrashRecoveryContext::Disable() { 00203 sys::ScopedLock L(*gCrashRecoveryContextMutex); 00204 00205 if (!gCrashRecoveryEnabled) 00206 return; 00207 00208 gCrashRecoveryEnabled = false; 00209 00210 PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get()); 00211 if (currentHandle) { 00212 // Now we can remove the vectored exception handler from the chain 00213 ::RemoveVectoredExceptionHandler(currentHandle); 00214 00215 // Reset the handle in our thread-local set. 00216 sCurrentExceptionHandle.set(NULL); 00217 } 00218 } 00219 00220 #else 00221 00222 // Generic POSIX implementation. 00223 // 00224 // This implementation relies on synchronous signals being delivered to the 00225 // current thread. We use a thread local object to keep track of the active 00226 // crash recovery context, and install signal handlers to invoke HandleCrash on 00227 // the active object. 00228 // 00229 // This implementation does not to attempt to chain signal handlers in any 00230 // reliable fashion -- if we get a signal outside of a crash recovery context we 00231 // simply disable crash recovery and raise the signal again. 00232 00233 #include <signal.h> 00234 00235 static const int Signals[] = 00236 { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP }; 00237 static const unsigned NumSignals = sizeof(Signals) / sizeof(Signals[0]); 00238 static struct sigaction PrevActions[NumSignals]; 00239 00240 static void CrashRecoverySignalHandler(int Signal) { 00241 // Lookup the current thread local recovery object. 00242 const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 00243 00244 if (!CRCI) { 00245 // We didn't find a crash recovery context -- this means either we got a 00246 // signal on a thread we didn't expect it on, the application got a signal 00247 // outside of a crash recovery context, or something else went horribly 00248 // wrong. 00249 // 00250 // Disable crash recovery and raise the signal again. The assumption here is 00251 // that the enclosing application will terminate soon, and we won't want to 00252 // attempt crash recovery again. 00253 // 00254 // This call of Disable isn't thread safe, but it doesn't actually matter. 00255 CrashRecoveryContext::Disable(); 00256 raise(Signal); 00257 00258 // The signal will be thrown once the signal mask is restored. 00259 return; 00260 } 00261 00262 // Unblock the signal we received. 00263 sigset_t SigMask; 00264 sigemptyset(&SigMask); 00265 sigaddset(&SigMask, Signal); 00266 sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); 00267 00268 if (CRCI) 00269 const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); 00270 } 00271 00272 void CrashRecoveryContext::Enable() { 00273 sys::ScopedLock L(*gCrashRecoveryContextMutex); 00274 00275 if (gCrashRecoveryEnabled) 00276 return; 00277 00278 gCrashRecoveryEnabled = true; 00279 00280 // Setup the signal handler. 00281 struct sigaction Handler; 00282 Handler.sa_handler = CrashRecoverySignalHandler; 00283 Handler.sa_flags = 0; 00284 sigemptyset(&Handler.sa_mask); 00285 00286 for (unsigned i = 0; i != NumSignals; ++i) { 00287 sigaction(Signals[i], &Handler, &PrevActions[i]); 00288 } 00289 } 00290 00291 void CrashRecoveryContext::Disable() { 00292 sys::ScopedLock L(*gCrashRecoveryContextMutex); 00293 00294 if (!gCrashRecoveryEnabled) 00295 return; 00296 00297 gCrashRecoveryEnabled = false; 00298 00299 // Restore the previous signal handlers. 00300 for (unsigned i = 0; i != NumSignals; ++i) 00301 sigaction(Signals[i], &PrevActions[i], nullptr); 00302 } 00303 00304 #endif 00305 00306 bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { 00307 // If crash recovery is disabled, do nothing. 00308 if (gCrashRecoveryEnabled) { 00309 assert(!Impl && "Crash recovery context already initialized!"); 00310 CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this); 00311 Impl = CRCI; 00312 00313 if (setjmp(CRCI->JumpBuffer) != 0) { 00314 return false; 00315 } 00316 } 00317 00318 Fn(); 00319 return true; 00320 } 00321 00322 void CrashRecoveryContext::HandleCrash() { 00323 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; 00324 assert(CRCI && "Crash recovery context never initialized!"); 00325 CRCI->HandleCrash(); 00326 } 00327 00328 const std::string &CrashRecoveryContext::getBacktrace() const { 00329 CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *) Impl; 00330 assert(CRC && "Crash recovery context never initialized!"); 00331 assert(CRC->Failed && "No crash was detected!"); 00332 return CRC->Backtrace; 00333 } 00334 00335 // FIXME: Portability. 00336 static void setThreadBackgroundPriority() { 00337 #ifdef __APPLE__ 00338 setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); 00339 #endif 00340 } 00341 00342 static bool hasThreadBackgroundPriority() { 00343 #ifdef __APPLE__ 00344 return getpriority(PRIO_DARWIN_THREAD, 0) == 1; 00345 #else 00346 return false; 00347 #endif 00348 } 00349 00350 namespace { 00351 struct RunSafelyOnThreadInfo { 00352 function_ref<void()> Fn; 00353 CrashRecoveryContext *CRC; 00354 bool UseBackgroundPriority; 00355 bool Result; 00356 }; 00357 } 00358 00359 static void RunSafelyOnThread_Dispatch(void *UserData) { 00360 RunSafelyOnThreadInfo *Info = 00361 reinterpret_cast<RunSafelyOnThreadInfo*>(UserData); 00362 00363 if (Info->UseBackgroundPriority) 00364 setThreadBackgroundPriority(); 00365 00366 Info->Result = Info->CRC->RunSafely(Info->Fn); 00367 } 00368 bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn, 00369 unsigned RequestedStackSize) { 00370 bool UseBackgroundPriority = hasThreadBackgroundPriority(); 00371 RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false }; 00372 llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize); 00373 if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl) 00374 CRC->setSwitchedThread(); 00375 return Info.Result; 00376 }