CrashRecoveryContext.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
  14. #define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
  15. #include "llvm/ADT/STLFunctionalExtras.h"
  16. namespace llvm {
  17. class CrashRecoveryContextCleanup;
  18. /// Crash recovery helper object.
  19. ///
  20. /// This class implements support for running operations in a safe context so
  21. /// that crashes (memory errors, stack overflow, assertion violations) can be
  22. /// detected and control restored to the crashing thread. Crash detection is
  23. /// purely "best effort", the exact set of failures which can be recovered from
  24. /// is platform dependent.
  25. ///
  26. /// Clients make use of this code by first calling
  27. /// CrashRecoveryContext::Enable(), and then executing unsafe operations via a
  28. /// CrashRecoveryContext object. For example:
  29. ///
  30. /// \code
  31. /// void actual_work(void *);
  32. ///
  33. /// void foo() {
  34. /// CrashRecoveryContext CRC;
  35. ///
  36. /// if (!CRC.RunSafely(actual_work, 0)) {
  37. /// ... a crash was detected, report error to user ...
  38. /// }
  39. ///
  40. /// ... no crash was detected ...
  41. /// }
  42. /// \endcode
  43. ///
  44. /// To assist recovery the class allows specifying set of actions that will be
  45. /// executed in any case, whether crash occurs or not. These actions may be used
  46. /// to reclaim resources in the case of crash.
  47. class CrashRecoveryContext {
  48. void *Impl = nullptr;
  49. CrashRecoveryContextCleanup *head = nullptr;
  50. public:
  51. CrashRecoveryContext();
  52. ~CrashRecoveryContext();
  53. /// Register cleanup handler, which is used when the recovery context is
  54. /// finished.
  55. /// The recovery context owns the handler.
  56. void registerCleanup(CrashRecoveryContextCleanup *cleanup);
  57. void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
  58. /// Enable crash recovery.
  59. static void Enable();
  60. /// Disable crash recovery.
  61. static void Disable();
  62. /// Return the active context, if the code is currently executing in a
  63. /// thread which is in a protected context.
  64. static CrashRecoveryContext *GetCurrent();
  65. /// Return true if the current thread is recovering from a crash.
  66. static bool isRecoveringFromCrash();
  67. /// Execute the provided callback function (with the given arguments) in
  68. /// a protected context.
  69. ///
  70. /// \return True if the function completed successfully, and false if the
  71. /// function crashed (or HandleCrash was called explicitly). Clients should
  72. /// make as little assumptions as possible about the program state when
  73. /// RunSafely has returned false.
  74. bool RunSafely(function_ref<void()> Fn);
  75. bool RunSafely(void (*Fn)(void*), void *UserData) {
  76. return RunSafely([&]() { Fn(UserData); });
  77. }
  78. /// Execute the provide callback function (with the given arguments) in
  79. /// a protected context which is run in another thread (optionally with a
  80. /// requested stack size).
  81. ///
  82. /// See RunSafely().
  83. ///
  84. /// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be
  85. /// propagated to the new thread as well.
  86. bool RunSafelyOnThread(function_ref<void()>, unsigned RequestedStackSize = 0);
  87. bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
  88. unsigned RequestedStackSize = 0) {
  89. return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize);
  90. }
  91. /// Explicitly trigger a crash recovery in the current process, and
  92. /// return failure from RunSafely(). This function does not return.
  93. [[noreturn]] void HandleExit(int RetCode);
  94. /// Return true if RetCode indicates that a signal or an exception occurred.
  95. static bool isCrash(int RetCode);
  96. /// Throw again a signal or an exception, after it was catched once by a
  97. /// CrashRecoveryContext.
  98. static bool throwIfCrash(int RetCode);
  99. /// In case of a crash, this is the crash identifier.
  100. int RetCode = 0;
  101. /// Selects whether handling of failures should be done in the same way as
  102. /// for regular crashes. When this is active, a crash would print the
  103. /// callstack, clean-up any temporary files and create a coredump/minidump.
  104. bool DumpStackAndCleanupOnFailure = false;
  105. };
  106. /// Abstract base class of cleanup handlers.
  107. ///
  108. /// Derived classes override method recoverResources, which makes actual work on
  109. /// resource recovery.
  110. ///
  111. /// Cleanup handlers are stored in a double list, which is owned and managed by
  112. /// a crash recovery context.
  113. class CrashRecoveryContextCleanup {
  114. protected:
  115. CrashRecoveryContext *context = nullptr;
  116. CrashRecoveryContextCleanup(CrashRecoveryContext *context)
  117. : context(context) {}
  118. public:
  119. bool cleanupFired = false;
  120. virtual ~CrashRecoveryContextCleanup();
  121. virtual void recoverResources() = 0;
  122. CrashRecoveryContext *getContext() const {
  123. return context;
  124. }
  125. private:
  126. friend class CrashRecoveryContext;
  127. CrashRecoveryContextCleanup *prev = nullptr, *next = nullptr;
  128. };
  129. /// Base class of cleanup handler that controls recovery of resources of the
  130. /// given type.
  131. ///
  132. /// \tparam Derived Class that uses this class as a base.
  133. /// \tparam T Type of controlled resource.
  134. ///
  135. /// This class serves as a base for its template parameter as implied by
  136. /// Curiously Recurring Template Pattern.
  137. ///
  138. /// This class factors out creation of a cleanup handler. The latter requires
  139. /// knowledge of the current recovery context, which is provided by this class.
  140. template<typename Derived, typename T>
  141. class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup {
  142. protected:
  143. T *resource;
  144. CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T *resource)
  145. : CrashRecoveryContextCleanup(context), resource(resource) {}
  146. public:
  147. /// Creates cleanup handler.
  148. /// \param x Pointer to the resource recovered by this handler.
  149. /// \return New handler or null if the method was called outside a recovery
  150. /// context.
  151. static Derived *create(T *x) {
  152. if (x) {
  153. if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent())
  154. return new Derived(context, x);
  155. }
  156. return nullptr;
  157. }
  158. };
  159. /// Cleanup handler that reclaims resource by calling destructor on it.
  160. template <typename T>
  161. class CrashRecoveryContextDestructorCleanup : public
  162. CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> {
  163. public:
  164. CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context,
  165. T *resource)
  166. : CrashRecoveryContextCleanupBase<
  167. CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {}
  168. void recoverResources() override {
  169. this->resource->~T();
  170. }
  171. };
  172. /// Cleanup handler that reclaims resource by calling 'delete' on it.
  173. template <typename T>
  174. class CrashRecoveryContextDeleteCleanup : public
  175. CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> {
  176. public:
  177. CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource)
  178. : CrashRecoveryContextCleanupBase<
  179. CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {}
  180. void recoverResources() override { delete this->resource; }
  181. };
  182. /// Cleanup handler that reclaims resource by calling its method 'Release'.
  183. template <typename T>
  184. class CrashRecoveryContextReleaseRefCleanup : public
  185. CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> {
  186. public:
  187. CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context,
  188. T *resource)
  189. : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>,
  190. T>(context, resource) {}
  191. void recoverResources() override { this->resource->Release(); }
  192. };
  193. /// Helper class for managing resource cleanups.
  194. ///
  195. /// \tparam T Type of resource been reclaimed.
  196. /// \tparam Cleanup Class that defines how the resource is reclaimed.
  197. ///
  198. /// Clients create objects of this type in the code executed in a crash recovery
  199. /// context to ensure that the resource will be reclaimed even in the case of
  200. /// crash. For example:
  201. ///
  202. /// \code
  203. /// void actual_work(void *) {
  204. /// ...
  205. /// std::unique_ptr<Resource> R(new Resource());
  206. /// CrashRecoveryContextCleanupRegistrar D(R.get());
  207. /// ...
  208. /// }
  209. ///
  210. /// void foo() {
  211. /// CrashRecoveryContext CRC;
  212. ///
  213. /// if (!CRC.RunSafely(actual_work, 0)) {
  214. /// ... a crash was detected, report error to user ...
  215. /// }
  216. /// \endcode
  217. ///
  218. /// If the code of `actual_work` in the example above does not crash, the
  219. /// destructor of CrashRecoveryContextCleanupRegistrar removes cleanup code from
  220. /// the current CrashRecoveryContext and the resource is reclaimed by the
  221. /// destructor of std::unique_ptr. If crash happens, destructors are not called
  222. /// and the resource is reclaimed by cleanup object registered in the recovery
  223. /// context by the constructor of CrashRecoveryContextCleanupRegistrar.
  224. template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> >
  225. class CrashRecoveryContextCleanupRegistrar {
  226. CrashRecoveryContextCleanup *cleanup;
  227. public:
  228. CrashRecoveryContextCleanupRegistrar(T *x)
  229. : cleanup(Cleanup::create(x)) {
  230. if (cleanup)
  231. cleanup->getContext()->registerCleanup(cleanup);
  232. }
  233. ~CrashRecoveryContextCleanupRegistrar() { unregister(); }
  234. void unregister() {
  235. if (cleanup && !cleanup->cleanupFired)
  236. cleanup->getContext()->unregisterCleanup(cleanup);
  237. cleanup = nullptr;
  238. }
  239. };
  240. } // end namespace llvm
  241. #endif // LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
  242. #ifdef __GNUC__
  243. #pragma GCC diagnostic pop
  244. #endif