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