100 lines · cpp
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-exception6//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 __sanitizer91 92using namespace __sanitizer;93 94extern "C" {95SANITIZER_INTERFACE_ATTRIBUTE96void __sanitizer_set_death_callback(void (*callback)(void)) {97 SetUserDieCallback(callback);98}99} // extern "C"100