Home | History | Annotate | Download | only in sanitizer_common
      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 
     18 namespace __sanitizer {
     19 
     20 static const int kMaxNumOfInternalDieCallbacks = 5;
     21 static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
     22 
     23 bool 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 
     33 bool 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 
     46 static DieCallbackType UserDieCallback;
     47 void SetUserDieCallback(DieCallbackType callback) {
     48   UserDieCallback = callback;
     49 }
     50 
     51 void 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 
     63 static CheckFailedCallbackType CheckFailedCallback;
     64 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
     65   CheckFailedCallback = callback;
     66 }
     67 
     68 const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
     69 
     70 void 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