1*7c3d14c8STreehugger Robot //===-- sanitizer_termination.cc --------------------------------*- C++ -*-===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot ///
10*7c3d14c8STreehugger Robot /// This file contains the Sanitizer termination functions CheckFailed and Die,
11*7c3d14c8STreehugger Robot /// and the callback functionalities associated with them.
12*7c3d14c8STreehugger Robot ///
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot
15*7c3d14c8STreehugger Robot #include "sanitizer_common.h"
16*7c3d14c8STreehugger Robot #include "sanitizer_libc.h"
17*7c3d14c8STreehugger Robot
18*7c3d14c8STreehugger Robot namespace __sanitizer {
19*7c3d14c8STreehugger Robot
20*7c3d14c8STreehugger Robot static const int kMaxNumOfInternalDieCallbacks = 5;
21*7c3d14c8STreehugger Robot static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
22*7c3d14c8STreehugger Robot
AddDieCallback(DieCallbackType callback)23*7c3d14c8STreehugger Robot bool AddDieCallback(DieCallbackType callback) {
24*7c3d14c8STreehugger Robot for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
25*7c3d14c8STreehugger Robot if (InternalDieCallbacks[i] == nullptr) {
26*7c3d14c8STreehugger Robot InternalDieCallbacks[i] = callback;
27*7c3d14c8STreehugger Robot return true;
28*7c3d14c8STreehugger Robot }
29*7c3d14c8STreehugger Robot }
30*7c3d14c8STreehugger Robot return false;
31*7c3d14c8STreehugger Robot }
32*7c3d14c8STreehugger Robot
RemoveDieCallback(DieCallbackType callback)33*7c3d14c8STreehugger Robot bool RemoveDieCallback(DieCallbackType callback) {
34*7c3d14c8STreehugger Robot for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
35*7c3d14c8STreehugger Robot if (InternalDieCallbacks[i] == callback) {
36*7c3d14c8STreehugger Robot internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1],
37*7c3d14c8STreehugger Robot sizeof(InternalDieCallbacks[0]) *
38*7c3d14c8STreehugger Robot (kMaxNumOfInternalDieCallbacks - i - 1));
39*7c3d14c8STreehugger Robot InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr;
40*7c3d14c8STreehugger Robot return true;
41*7c3d14c8STreehugger Robot }
42*7c3d14c8STreehugger Robot }
43*7c3d14c8STreehugger Robot return false;
44*7c3d14c8STreehugger Robot }
45*7c3d14c8STreehugger Robot
46*7c3d14c8STreehugger Robot static DieCallbackType UserDieCallback;
SetUserDieCallback(DieCallbackType callback)47*7c3d14c8STreehugger Robot void SetUserDieCallback(DieCallbackType callback) {
48*7c3d14c8STreehugger Robot UserDieCallback = callback;
49*7c3d14c8STreehugger Robot }
50*7c3d14c8STreehugger Robot
Die()51*7c3d14c8STreehugger Robot void NORETURN Die() {
52*7c3d14c8STreehugger Robot if (UserDieCallback)
53*7c3d14c8STreehugger Robot UserDieCallback();
54*7c3d14c8STreehugger Robot for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) {
55*7c3d14c8STreehugger Robot if (InternalDieCallbacks[i])
56*7c3d14c8STreehugger Robot InternalDieCallbacks[i]();
57*7c3d14c8STreehugger Robot }
58*7c3d14c8STreehugger Robot if (common_flags()->abort_on_error)
59*7c3d14c8STreehugger Robot Abort();
60*7c3d14c8STreehugger Robot internal__exit(common_flags()->exitcode);
61*7c3d14c8STreehugger Robot }
62*7c3d14c8STreehugger Robot
63*7c3d14c8STreehugger Robot static CheckFailedCallbackType CheckFailedCallback;
SetCheckFailedCallback(CheckFailedCallbackType callback)64*7c3d14c8STreehugger Robot void SetCheckFailedCallback(CheckFailedCallbackType callback) {
65*7c3d14c8STreehugger Robot CheckFailedCallback = callback;
66*7c3d14c8STreehugger Robot }
67*7c3d14c8STreehugger Robot
68*7c3d14c8STreehugger Robot const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
69*7c3d14c8STreehugger Robot
CheckFailed(const char * file,int line,const char * cond,u64 v1,u64 v2)70*7c3d14c8STreehugger Robot void NORETURN CheckFailed(const char *file, int line, const char *cond,
71*7c3d14c8STreehugger Robot u64 v1, u64 v2) {
72*7c3d14c8STreehugger Robot static atomic_uint32_t num_calls;
73*7c3d14c8STreehugger Robot if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) {
74*7c3d14c8STreehugger Robot SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed);
75*7c3d14c8STreehugger Robot Trap();
76*7c3d14c8STreehugger Robot }
77*7c3d14c8STreehugger Robot
78*7c3d14c8STreehugger Robot if (CheckFailedCallback) {
79*7c3d14c8STreehugger Robot CheckFailedCallback(file, line, cond, v1, v2);
80*7c3d14c8STreehugger Robot }
81*7c3d14c8STreehugger Robot Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
82*7c3d14c8STreehugger Robot v1, v2);
83*7c3d14c8STreehugger Robot Die();
84*7c3d14c8STreehugger Robot }
85*7c3d14c8STreehugger Robot
86*7c3d14c8STreehugger Robot } // namespace __sanitizer
87