CrashRecoveryContext.h revision 2169ad8c60c9d4fcc3665836be6c5f9302b1c4ec
1a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===// 2a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// 3a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// The LLVM Compiler Infrastructure 4a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// 5a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// This file is distributed under the University of Illinois Open Source 6a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// License. See LICENSE.TXT for details. 7a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// 8a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//===----------------------------------------------------------------------===// 9a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 10a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H 11a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H 12a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 13a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#include <string> 14a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 15a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarnamespace llvm { 16a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarclass StringRef; 17a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 18a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekclass CrashRecoveryContextCleanup; 19a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 20a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// \brief Crash recovery helper object. 21a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 22a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// This class implements support for running operations in a safe context so 23a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// that crashes (memory errors, stack overflow, assertion violations) can be 24a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// detected and control restored to the crashing thread. Crash detection is 25a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// purely "best effort", the exact set of failures which can be recovered from 26a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// is platform dependent. 27a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 28a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// Clients make use of this code by first calling 29a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// CrashRecoveryContext::Enable(), and then executing unsafe operations via a 30a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// CrashRecoveryContext object. For example: 31a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 32a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// void actual_work(void *); 33a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 34a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// void foo() { 35a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// CrashRecoveryContext CRC; 36a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 37a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// if (!CRC.RunSafely(actual_work, 0)) { 38a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// ... a crash was detected, report error to user ... 39a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// } 40a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 41a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// ... no crash was detected ... 42a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// } 43a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 44a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// Crash recovery contexts may not be nested. 45a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarclass CrashRecoveryContext { 46a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar void *Impl; 47a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek CrashRecoveryContextCleanup *head; 48a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 49a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarpublic: 50a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek CrashRecoveryContext() : Impl(0), head(0) {} 51a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar ~CrashRecoveryContext(); 52a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 53a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek void registerCleanup(CrashRecoveryContextCleanup *cleanup); 54a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek void unregisterCleanup(CrashRecoveryContextCleanup *cleanup); 55a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 56c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar /// \brief Enable crash recovery. 57a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar static void Enable(); 58a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 59c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar /// \brief Disable crash recovery. 60a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar static void Disable(); 61a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 62a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar /// \brief Return the active context, if the code is currently executing in a 63a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar /// thread which is in a protected context. 64a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar static CrashRecoveryContext *GetCurrent(); 65a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar 66b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek /// \brief Return true if the current thread is recovering from a 67b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek /// crash. 68b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek static bool isRecoveringFromCrash(); 69b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek 70a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// \brief Execute the provide callback function (with the given arguments) in 71a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// a protected context. 72a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// 73a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// \return True if the function completed successfully, and false if the 74a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// function crashed (or HandleCrash was called explicitly). Clients should 75a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// make as little assumptions as possible about the program state when 76a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// RunSafely has returned false. Clients can use getBacktrace() to retrieve 77a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// the backtrace of the crash on failures. 78a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar bool RunSafely(void (*Fn)(void*), void *UserData); 79a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 80f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// \brief Execute the provide callback function (with the given arguments) in 81f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// a protected context which is run in another thread (optionally with a 82f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// requested stack size). 83f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// 84f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// See RunSafely() and llvm_execute_on_thread(). 85f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar bool RunSafelyOnThread(void (*Fn)(void*), void *UserData, 86f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar unsigned RequestedStackSize = 0); 87f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar 88a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// \brief Explicitly trigger a crash recovery in the current process, and 89a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// return failure from RunSafely(). This function does not return. 90a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar void HandleCrash(); 91a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 92a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// \brief Return a string containing the backtrace where the crash was 93a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// detected; or empty if the backtrace wasn't recovered. 94a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// 95a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// This function is only valid when a crash has been detected (i.e., 96a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// RunSafely() has returned false. 97a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar const std::string &getBacktrace() const; 98a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar}; 99a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 100a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekclass CrashRecoveryContextCleanup { 101afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekprotected: 102afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContext *context; 103afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanup(CrashRecoveryContext *context) 1043311d951e22b133207ed6f8e384d80f0970a7fb3Ted Kremenek : context(context), cleanupFired(false) {} 105a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekpublic: 1061a06d5721acb9a2b69217fc8872ed5b14a482104Ted Kremenek bool cleanupFired; 1071a06d5721acb9a2b69217fc8872ed5b14a482104Ted Kremenek 108a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek virtual ~CrashRecoveryContextCleanup(); 109a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek virtual void recoverResources() = 0; 110afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 111afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContext *getContext() const { 112afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek return context; 113afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek } 114afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 115a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekprivate: 116a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek friend class CrashRecoveryContext; 117a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek CrashRecoveryContextCleanup *prev, *next; 118a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek}; 119a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 120afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenektemplate<typename DERIVED, typename T> 121afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup { 122afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekprotected: 123a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek T *resource; 124afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T* resource) 125afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : CrashRecoveryContextCleanup(context), resource(resource) {} 126a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekpublic: 127afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek static DERIVED *create(T *x) { 128afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek if (x) { 129afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent()) 130afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek return new DERIVED(context, x); 131afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek } 132afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek return 0; 133a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek } 134a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek}; 1350597234028d14e454673bec8d8196285a9712364Ted Kremenek 1360597234028d14e454673bec8d8196285a9712364Ted Kremenektemplate <typename T> 137afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextDestructorCleanup : public 138afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> { 1390597234028d14e454673bec8d8196285a9712364Ted Kremenekpublic: 140afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context, 141afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek T *resource) 142afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : CrashRecoveryContextCleanupBase< 143afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {} 144afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 1450597234028d14e454673bec8d8196285a9712364Ted Kremenek virtual void recoverResources() { 146afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek this->resource->~T(); 1470597234028d14e454673bec8d8196285a9712364Ted Kremenek } 1480597234028d14e454673bec8d8196285a9712364Ted Kremenek}; 1490597234028d14e454673bec8d8196285a9712364Ted Kremenek 150a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenektemplate <typename T> 151afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextDeleteCleanup : public 152afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> { 153afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekpublic: 154afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource) 155afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : CrashRecoveryContextCleanupBase< 156afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {} 157afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 158afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek virtual void recoverResources() { 159afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek delete this->resource; 160afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek } 161a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek}; 162a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 163afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenektemplate <typename T> 164afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextReleaseRefCleanup : public 165afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> 166afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek{ 167afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekpublic: 168afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context, 169afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek T *resource) 170afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, 171afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek T>(context, resource) {} 172a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 173afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek virtual void recoverResources() { 174afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek this->resource->Release(); 175afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek } 176afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek}; 177afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 178afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenektemplate <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> > 179a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekclass CrashRecoveryContextCleanupRegistrar { 180a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek CrashRecoveryContextCleanup *cleanup; 181a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekpublic: 182afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupRegistrar(T *x) 183afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : cleanup(Cleanup::create(x)) { 184afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek if (cleanup) 185afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek cleanup->getContext()->registerCleanup(cleanup); 186a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek } 187afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 188a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek ~CrashRecoveryContextCleanupRegistrar() { 1892169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek unregister(); 1902169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek } 1912169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek 1922169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek void unregister() { 193afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek if (cleanup && !cleanup->cleanupFired) 1942169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek cleanup->getContext()->unregisterCleanup(cleanup); 1952169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek cleanup = 0; 196a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek } 197a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek}; 198a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar} 199a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 200a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#endif 201