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 17namespace __sanitizer { 18 19static const int kMaxNumOfInternalDieCallbacks = 5; 20static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks]; 21 22bool 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 32bool 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 45static DieCallbackType UserDieCallback; 46void SetUserDieCallback(DieCallbackType callback) { 47 UserDieCallback = callback; 48} 49 50void 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 62static void (*CheckUnwindCallback)(); 63void SetCheckUnwindCallback(void (*callback)()) { 64 CheckUnwindCallback = callback; 65} 66 67void 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 92using namespace __sanitizer; 93 94extern "C" { 95SANITIZER_INTERFACE_ATTRIBUTE 96void __sanitizer_set_death_callback(void (*callback)(void)) { 97 SetUserDieCallback(callback); 98} 99} // extern "C" 100