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