Home | History | Annotate | Line # | Download | only in sanitizer_common
      1  1.1  mrg //===-- sanitizer_termination.cpp -------------------------------*- C++ -*-===//
      2  1.1  mrg //
      3  1.1  mrg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4  1.1  mrg // See https://llvm.org/LICENSE.txt for license information.
      5  1.1  mrg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6  1.1  mrg //
      7  1.1  mrg //===----------------------------------------------------------------------===//
      8  1.1  mrg ///
      9  1.1  mrg /// This file contains the Sanitizer termination functions CheckFailed and Die,
     10  1.1  mrg /// and the callback functionalities associated with them.
     11  1.1  mrg ///
     12  1.1  mrg //===----------------------------------------------------------------------===//
     13  1.1  mrg 
     14  1.1  mrg #include "sanitizer_common.h"
     15  1.1  mrg #include "sanitizer_libc.h"
     16  1.1  mrg 
     17  1.1  mrg namespace __sanitizer {
     18  1.1  mrg 
     19  1.1  mrg static const int kMaxNumOfInternalDieCallbacks = 5;
     20  1.1  mrg static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
     21  1.1  mrg 
     22  1.1  mrg bool AddDieCallback(DieCallbackType callback) {
     23  1.1  mrg   for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
     24  1.1  mrg     if (InternalDieCallbacks[i] == nullptr) {
     25  1.1  mrg       InternalDieCallbacks[i] = callback;
     26  1.1  mrg       return true;
     27  1.1  mrg     }
     28  1.1  mrg   }
     29  1.1  mrg   return false;
     30  1.1  mrg }
     31  1.1  mrg 
     32  1.1  mrg bool RemoveDieCallback(DieCallbackType callback) {
     33  1.1  mrg   for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
     34  1.1  mrg     if (InternalDieCallbacks[i] == callback) {
     35  1.1  mrg       internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1],
     36  1.1  mrg                        sizeof(InternalDieCallbacks[0]) *
     37  1.1  mrg                            (kMaxNumOfInternalDieCallbacks - i - 1));
     38  1.1  mrg       InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr;
     39  1.1  mrg       return true;
     40  1.1  mrg     }
     41  1.1  mrg   }
     42  1.1  mrg   return false;
     43  1.1  mrg }
     44  1.1  mrg 
     45  1.1  mrg static DieCallbackType UserDieCallback;
     46  1.1  mrg void SetUserDieCallback(DieCallbackType callback) {
     47  1.1  mrg   UserDieCallback = callback;
     48  1.1  mrg }
     49  1.1  mrg 
     50  1.1  mrg void NORETURN Die() {
     51  1.1  mrg   if (UserDieCallback)
     52  1.1  mrg     UserDieCallback();
     53  1.1  mrg   for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) {
     54  1.1  mrg     if (InternalDieCallbacks[i])
     55  1.1  mrg       InternalDieCallbacks[i]();
     56  1.1  mrg   }
     57  1.1  mrg   if (common_flags()->abort_on_error)
     58  1.1  mrg     Abort();
     59  1.1  mrg   internal__exit(common_flags()->exitcode);
     60  1.1  mrg }
     61  1.1  mrg 
     62  1.1  mrg static void (*CheckUnwindCallback)();
     63  1.1  mrg void SetCheckUnwindCallback(void (*callback)()) {
     64  1.1  mrg   CheckUnwindCallback = callback;
     65  1.1  mrg }
     66  1.1  mrg 
     67  1.1  mrg void NORETURN CheckFailed(const char *file, int line, const char *cond,
     68  1.1  mrg                           u64 v1, u64 v2) {
     69  1.1  mrg   u32 tid = GetTid();
     70  1.1  mrg   Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n",
     71  1.1  mrg          SanitizerToolName, StripModuleName(file), line, cond, (uptr)v1,
     72  1.1  mrg          (uptr)v2, tid);
     73  1.1  mrg   static atomic_uint32_t first_tid;
     74  1.1  mrg   u32 cmp = 0;
     75  1.1  mrg   if (!atomic_compare_exchange_strong(&first_tid, &cmp, tid,
     76  1.1  mrg                                       memory_order_relaxed)) {
     77  1.1  mrg     if (cmp == tid) {
     78  1.1  mrg       // Recursing into CheckFailed.
     79  1.1  mrg     } else {
     80  1.1  mrg       // Another thread fails already, let it print the stack and terminate.
     81  1.1  mrg       SleepForSeconds(2);
     82  1.1  mrg     }
     83  1.1  mrg     Trap();
     84  1.1  mrg   }
     85  1.1  mrg   if (CheckUnwindCallback)
     86  1.1  mrg     CheckUnwindCallback();
     87  1.1  mrg   Die();
     88  1.1  mrg }
     89  1.1  mrg 
     90  1.1  mrg } // namespace __sanitizer
     91  1.1  mrg 
     92  1.1  mrg using namespace __sanitizer;
     93  1.1  mrg 
     94  1.1  mrg extern "C" {
     95  1.1  mrg SANITIZER_INTERFACE_ATTRIBUTE
     96  1.1  mrg void __sanitizer_set_death_callback(void (*callback)(void)) {
     97  1.1  mrg   SetUserDieCallback(callback);
     98  1.1  mrg }
     99  1.1  mrg }  // extern "C"
    100