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