13cab2bb3Spatrick //===-- sanitizer_termination.cpp -------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick ///
93cab2bb3Spatrick /// This file contains the Sanitizer termination functions CheckFailed and Die,
103cab2bb3Spatrick /// and the callback functionalities associated with them.
113cab2bb3Spatrick ///
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick
143cab2bb3Spatrick #include "sanitizer_common.h"
153cab2bb3Spatrick #include "sanitizer_libc.h"
163cab2bb3Spatrick
173cab2bb3Spatrick namespace __sanitizer {
183cab2bb3Spatrick
193cab2bb3Spatrick static const int kMaxNumOfInternalDieCallbacks = 5;
203cab2bb3Spatrick static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
213cab2bb3Spatrick
AddDieCallback(DieCallbackType callback)223cab2bb3Spatrick bool AddDieCallback(DieCallbackType callback) {
233cab2bb3Spatrick for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
243cab2bb3Spatrick if (InternalDieCallbacks[i] == nullptr) {
253cab2bb3Spatrick InternalDieCallbacks[i] = callback;
263cab2bb3Spatrick return true;
273cab2bb3Spatrick }
283cab2bb3Spatrick }
293cab2bb3Spatrick return false;
303cab2bb3Spatrick }
313cab2bb3Spatrick
RemoveDieCallback(DieCallbackType callback)323cab2bb3Spatrick bool RemoveDieCallback(DieCallbackType callback) {
333cab2bb3Spatrick for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
343cab2bb3Spatrick if (InternalDieCallbacks[i] == callback) {
353cab2bb3Spatrick internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1],
363cab2bb3Spatrick sizeof(InternalDieCallbacks[0]) *
373cab2bb3Spatrick (kMaxNumOfInternalDieCallbacks - i - 1));
383cab2bb3Spatrick InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr;
393cab2bb3Spatrick return true;
403cab2bb3Spatrick }
413cab2bb3Spatrick }
423cab2bb3Spatrick return false;
433cab2bb3Spatrick }
443cab2bb3Spatrick
453cab2bb3Spatrick static DieCallbackType UserDieCallback;
SetUserDieCallback(DieCallbackType callback)463cab2bb3Spatrick void SetUserDieCallback(DieCallbackType callback) {
473cab2bb3Spatrick UserDieCallback = callback;
483cab2bb3Spatrick }
493cab2bb3Spatrick
Die()503cab2bb3Spatrick void NORETURN Die() {
513cab2bb3Spatrick if (UserDieCallback)
523cab2bb3Spatrick UserDieCallback();
533cab2bb3Spatrick for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) {
543cab2bb3Spatrick if (InternalDieCallbacks[i])
553cab2bb3Spatrick InternalDieCallbacks[i]();
563cab2bb3Spatrick }
573cab2bb3Spatrick if (common_flags()->abort_on_error)
583cab2bb3Spatrick Abort();
593cab2bb3Spatrick internal__exit(common_flags()->exitcode);
603cab2bb3Spatrick }
613cab2bb3Spatrick
62*d89ec533Spatrick static void (*CheckUnwindCallback)();
SetCheckUnwindCallback(void (* callback)())63*d89ec533Spatrick void SetCheckUnwindCallback(void (*callback)()) {
64*d89ec533Spatrick CheckUnwindCallback = callback;
653cab2bb3Spatrick }
663cab2bb3Spatrick
CheckFailed(const char * file,int line,const char * cond,u64 v1,u64 v2)673cab2bb3Spatrick void NORETURN CheckFailed(const char *file, int line, const char *cond,
683cab2bb3Spatrick u64 v1, u64 v2) {
69*d89ec533Spatrick u32 tid = GetTid();
70*d89ec533Spatrick Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n",
71*d89ec533Spatrick SanitizerToolName, StripModuleName(file), line, cond, (uptr)v1,
72*d89ec533Spatrick (uptr)v2, tid);
73*d89ec533Spatrick static atomic_uint32_t first_tid;
74*d89ec533Spatrick u32 cmp = 0;
75*d89ec533Spatrick if (!atomic_compare_exchange_strong(&first_tid, &cmp, tid,
76*d89ec533Spatrick memory_order_relaxed)) {
77*d89ec533Spatrick if (cmp == tid) {
78*d89ec533Spatrick // Recursing into CheckFailed.
79*d89ec533Spatrick } else {
80*d89ec533Spatrick // Another thread fails already, let it print the stack and terminate.
81*d89ec533Spatrick SleepForSeconds(2);
82*d89ec533Spatrick }
833cab2bb3Spatrick Trap();
843cab2bb3Spatrick }
85*d89ec533Spatrick if (CheckUnwindCallback)
86*d89ec533Spatrick CheckUnwindCallback();
873cab2bb3Spatrick Die();
883cab2bb3Spatrick }
893cab2bb3Spatrick
903cab2bb3Spatrick } // namespace __sanitizer
913cab2bb3Spatrick
923cab2bb3Spatrick using namespace __sanitizer;
933cab2bb3Spatrick
943cab2bb3Spatrick extern "C" {
953cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_set_death_callback(void (* callback)(void))963cab2bb3Spatrick void __sanitizer_set_death_callback(void (*callback)(void)) {
973cab2bb3Spatrick SetUserDieCallback(callback);
983cab2bb3Spatrick }
993cab2bb3Spatrick } // extern "C"
100