1//===-- sanitizer_termination.cc --------------------------------*- C++ -*-===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7///
8/// This file contains the Sanitizer termination functions CheckFailed and Die,
9/// and the callback functionalities associated with them.
10///
11//===----------------------------------------------------------------------===//
12
13#include "sanitizer_common.h"
14#include "sanitizer_libc.h"
15
16namespace __sanitizer {
17
18static const int kMaxNumOfInternalDieCallbacks = 5;
19static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
20
21bool AddDieCallback(DieCallbackType callback) {
22  for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
23    if (InternalDieCallbacks[i] == nullptr) {
24      InternalDieCallbacks[i] = callback;
25      return true;
26    }
27  }
28  return false;
29}
30
31bool RemoveDieCallback(DieCallbackType callback) {
32  for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
33    if (InternalDieCallbacks[i] == callback) {
34      internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1],
35                       sizeof(InternalDieCallbacks[0]) *
36                           (kMaxNumOfInternalDieCallbacks - i - 1));
37      InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr;
38      return true;
39    }
40  }
41  return false;
42}
43
44static DieCallbackType UserDieCallback;
45void SetUserDieCallback(DieCallbackType callback) {
46  UserDieCallback = callback;
47}
48
49void NORETURN Die() {
50  if (UserDieCallback)
51    UserDieCallback();
52  for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) {
53    if (InternalDieCallbacks[i])
54      InternalDieCallbacks[i]();
55  }
56  if (common_flags()->abort_on_error)
57    Abort();
58  internal__exit(common_flags()->exitcode);
59}
60
61static CheckFailedCallbackType CheckFailedCallback;
62void SetCheckFailedCallback(CheckFailedCallbackType callback) {
63  CheckFailedCallback = callback;
64}
65
66const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
67
68void NORETURN CheckFailed(const char *file, int line, const char *cond,
69                          u64 v1, u64 v2) {
70  static atomic_uint32_t num_calls;
71  if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) {
72    SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed);
73    Trap();
74  }
75
76  if (CheckFailedCallback) {
77    CheckFailedCallback(file, line, cond, v1, v2);
78  }
79  Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
80                                                            v1, v2);
81  Die();
82}
83
84} // namespace __sanitizer
85
86using namespace __sanitizer;  // NOLINT
87
88extern "C" {
89SANITIZER_INTERFACE_ATTRIBUTE
90void __sanitizer_set_death_callback(void (*callback)(void)) {
91  SetUserDieCallback(callback);
92}
93}  // extern "C"
94