xref: /netbsd-src/external/gpl3/gcc.old/dist/libsanitizer/sanitizer_common/sanitizer_termination.cc (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
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 
16 namespace __sanitizer {
17 
18 static const int kMaxNumOfInternalDieCallbacks = 5;
19 static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
20 
AddDieCallback(DieCallbackType callback)21 bool 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 
RemoveDieCallback(DieCallbackType callback)31 bool 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 
44 static DieCallbackType UserDieCallback;
SetUserDieCallback(DieCallbackType callback)45 void SetUserDieCallback(DieCallbackType callback) {
46   UserDieCallback = callback;
47 }
48 
Die()49 void 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 
61 static CheckFailedCallbackType CheckFailedCallback;
SetCheckFailedCallback(CheckFailedCallbackType callback)62 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
63   CheckFailedCallback = callback;
64 }
65 
66 const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
67 
CheckFailed(const char * file,int line,const char * cond,u64 v1,u64 v2)68 void 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 
86 using namespace __sanitizer;  // NOLINT
87 
88 extern "C" {
89 SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_set_death_callback(void (* callback)(void))90 void __sanitizer_set_death_callback(void (*callback)(void)) {
91   SetUserDieCallback(callback);
92 }
93 }  // extern "C"
94