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