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 15dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "llvm/ADT/STLExtras.h" 16dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 17a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarnamespace llvm { 18a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarclass StringRef; 19a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 20a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekclass CrashRecoveryContextCleanup; 21dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 22a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// \brief Crash recovery helper object. 23a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 24a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// This class implements support for running operations in a safe context so 25a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// that crashes (memory errors, stack overflow, assertion violations) can be 26a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// detected and control restored to the crashing thread. Crash detection is 27a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// purely "best effort", the exact set of failures which can be recovered from 28a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// is platform dependent. 29a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 30a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// Clients make use of this code by first calling 31a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// CrashRecoveryContext::Enable(), and then executing unsafe operations via a 32a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// CrashRecoveryContext object. For example: 33a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 34a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// void actual_work(void *); 35a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 36a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// void foo() { 37a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// CrashRecoveryContext CRC; 38a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 39a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// if (!CRC.RunSafely(actual_work, 0)) { 40a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// ... a crash was detected, report error to user ... 41a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// } 42a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 43a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// ... no crash was detected ... 44a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// } 45a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// 46a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// Crash recovery contexts may not be nested. 47a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarclass CrashRecoveryContext { 48a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar void *Impl; 49a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek CrashRecoveryContextCleanup *head; 50a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 51a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarpublic: 52dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines CrashRecoveryContext() : Impl(nullptr), head(nullptr) {} 53a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar ~CrashRecoveryContext(); 54dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 55a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek void registerCleanup(CrashRecoveryContextCleanup *cleanup); 56a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek void unregisterCleanup(CrashRecoveryContextCleanup *cleanup); 57a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 58c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar /// \brief Enable crash recovery. 59a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar static void Enable(); 60a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 61c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar /// \brief Disable crash recovery. 62a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar static void Disable(); 63a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 64a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar /// \brief Return the active context, if the code is currently executing in a 65a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar /// thread which is in a protected context. 66a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar static CrashRecoveryContext *GetCurrent(); 67a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar 68b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek /// \brief Return true if the current thread is recovering from a 69b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek /// crash. 70b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek static bool isRecoveringFromCrash(); 71b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek 72a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// \brief Execute the provide callback function (with the given arguments) in 73a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// a protected context. 74a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// 75a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// \return True if the function completed successfully, and false if the 76a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// function crashed (or HandleCrash was called explicitly). Clients should 77a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// make as little assumptions as possible about the program state when 78a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// RunSafely has returned false. Clients can use getBacktrace() to retrieve 79a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// the backtrace of the crash on failures. 80dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines bool RunSafely(function_ref<void()> Fn); 81dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines bool RunSafely(void (*Fn)(void*), void *UserData) { 82dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines return RunSafely([&]() { Fn(UserData); }); 8336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 84a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 85f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// \brief Execute the provide callback function (with the given arguments) in 86f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// a protected context which is run in another thread (optionally with a 87f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// requested stack size). 88f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// 89f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar /// See RunSafely() and llvm_execute_on_thread(). 90cd81d94322a39503e4a3e87b6ee03d4fcb3465fbStephen Hines /// 91cd81d94322a39503e4a3e87b6ee03d4fcb3465fbStephen Hines /// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be 92cd81d94322a39503e4a3e87b6ee03d4fcb3465fbStephen Hines /// propagated to the new thread as well. 93dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines bool RunSafelyOnThread(function_ref<void()>, unsigned RequestedStackSize = 0); 94f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar bool RunSafelyOnThread(void (*Fn)(void*), void *UserData, 95dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines unsigned RequestedStackSize = 0) { 96dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize); 9736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 98f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar 99a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// \brief Explicitly trigger a crash recovery in the current process, and 100a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// return failure from RunSafely(). This function does not return. 101a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar void HandleCrash(); 102a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 103a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// \brief Return a string containing the backtrace where the crash was 104a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// detected; or empty if the backtrace wasn't recovered. 105a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// 106a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// This function is only valid when a crash has been detected (i.e., 107a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar /// RunSafely() has returned false. 108a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar const std::string &getBacktrace() const; 109a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar}; 110a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 111a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekclass CrashRecoveryContextCleanup { 112afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekprotected: 113afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContext *context; 114afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanup(CrashRecoveryContext *context) 1153311d951e22b133207ed6f8e384d80f0970a7fb3Ted Kremenek : context(context), cleanupFired(false) {} 116a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekpublic: 1171a06d5721acb9a2b69217fc8872ed5b14a482104Ted Kremenek bool cleanupFired; 1181a06d5721acb9a2b69217fc8872ed5b14a482104Ted Kremenek 119a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek virtual ~CrashRecoveryContextCleanup(); 120a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek virtual void recoverResources() = 0; 121afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 122afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContext *getContext() const { 123afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek return context; 124afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek } 125afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 126a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekprivate: 127a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek friend class CrashRecoveryContext; 128a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek CrashRecoveryContextCleanup *prev, *next; 129a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek}; 130a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 131afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenektemplate<typename DERIVED, typename T> 132afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup { 133afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekprotected: 134a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek T *resource; 135afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T* resource) 136afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : CrashRecoveryContextCleanup(context), resource(resource) {} 137a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekpublic: 138afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek static DERIVED *create(T *x) { 139afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek if (x) { 140afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent()) 141afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek return new DERIVED(context, x); 142afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek } 143afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek return 0; 144a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek } 145a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek}; 1460597234028d14e454673bec8d8196285a9712364Ted Kremenek 1470597234028d14e454673bec8d8196285a9712364Ted Kremenektemplate <typename T> 148afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextDestructorCleanup : public 149afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> { 1500597234028d14e454673bec8d8196285a9712364Ted Kremenekpublic: 151afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context, 152afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek T *resource) 153afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : CrashRecoveryContextCleanupBase< 154afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {} 155afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 1560597234028d14e454673bec8d8196285a9712364Ted Kremenek virtual void recoverResources() { 157afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek this->resource->~T(); 1580597234028d14e454673bec8d8196285a9712364Ted Kremenek } 1590597234028d14e454673bec8d8196285a9712364Ted Kremenek}; 1600597234028d14e454673bec8d8196285a9712364Ted Kremenek 161a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenektemplate <typename T> 162afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextDeleteCleanup : public 163afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> { 164afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekpublic: 165afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource) 166afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : CrashRecoveryContextCleanupBase< 167afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {} 168afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 169afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek virtual void recoverResources() { 170afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek delete this->resource; 171afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek } 172a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek}; 173a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 174afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenektemplate <typename T> 175afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextReleaseRefCleanup : public 176afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> 177afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek{ 178afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekpublic: 179afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context, 180afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek T *resource) 181afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, 182afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek T>(context, resource) {} 183a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 184afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek virtual void recoverResources() { 185afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek this->resource->Release(); 186afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek } 187afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek}; 188afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 189afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenektemplate <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> > 190a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekclass CrashRecoveryContextCleanupRegistrar { 191a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek CrashRecoveryContextCleanup *cleanup; 192a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekpublic: 193afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek CrashRecoveryContextCleanupRegistrar(T *x) 194afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek : cleanup(Cleanup::create(x)) { 195afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek if (cleanup) 196afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek cleanup->getContext()->registerCleanup(cleanup); 197a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek } 198afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek 199a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek ~CrashRecoveryContextCleanupRegistrar() { 2002169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek unregister(); 2012169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek } 2022169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek 2032169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek void unregister() { 204afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek if (cleanup && !cleanup->cleanupFired) 2052169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek cleanup->getContext()->unregisterCleanup(cleanup); 2062169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek cleanup = 0; 207a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek } 208a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek}; 209a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar} 210a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 211a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#endif 212