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