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 void (*CheckUnwindCallback)(); 63 void SetCheckUnwindCallback(void (*callback)()) { 64 CheckUnwindCallback = callback; 65 } 66 67 void NORETURN CheckFailed(const char *file, int line, const char *cond, 68 u64 v1, u64 v2) { 69 u32 tid = GetTid(); 70 Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n", 71 SanitizerToolName, StripModuleName(file), line, cond, (uptr)v1, 72 (uptr)v2, tid); 73 static atomic_uint32_t first_tid; 74 u32 cmp = 0; 75 if (!atomic_compare_exchange_strong(&first_tid, &cmp, tid, 76 memory_order_relaxed)) { 77 if (cmp == tid) { 78 // Recursing into CheckFailed. 79 } else { 80 // Another thread fails already, let it print the stack and terminate. 81 SleepForSeconds(2); 82 } 83 Trap(); 84 } 85 if (CheckUnwindCallback) 86 CheckUnwindCallback(); 87 Die(); 88 } 89 90 } // namespace __sanitizer 91 92 using namespace __sanitizer; 93 94 extern "C" { 95 SANITIZER_INTERFACE_ATTRIBUTE 96 void __sanitizer_set_death_callback(void (*callback)(void)) { 97 SetUserDieCallback(callback); 98 } 99 } // extern "C" 100