1 //===--- rtsan.cpp - Realtime Sanitizer -------------------------*- 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "rtsan/rtsan.h" 12 #include "rtsan/rtsan_assertions.h" 13 #include "rtsan/rtsan_diagnostics.h" 14 #include "rtsan/rtsan_flags.h" 15 #include "rtsan/rtsan_interceptors.h" 16 #include "rtsan/rtsan_stats.h" 17 #include "rtsan/rtsan_suppressions.h" 18 19 #include "sanitizer_common/sanitizer_atomic.h" 20 #include "sanitizer_common/sanitizer_common.h" 21 #include "sanitizer_common/sanitizer_mutex.h" 22 #include "sanitizer_common/sanitizer_stackdepot.h" 23 24 using namespace __rtsan; 25 using namespace __sanitizer; 26 27 namespace { 28 enum class InitializationState : u8 { 29 Uninitialized, 30 Initializing, 31 Initialized, 32 }; 33 } // namespace 34 35 static StaticSpinMutex rtsan_inited_mutex; 36 static atomic_uint8_t rtsan_initialized = { 37 static_cast<u8>(InitializationState::Uninitialized)}; 38 39 static void SetInitializationState(InitializationState state) { 40 atomic_store(&rtsan_initialized, static_cast<u8>(state), 41 memory_order_release); 42 } 43 44 static InitializationState GetInitializationState() { 45 return static_cast<InitializationState>( 46 atomic_load(&rtsan_initialized, memory_order_acquire)); 47 } 48 49 static void OnViolation(const BufferedStackTrace &stack, 50 const DiagnosticsInfo &info) { 51 IncrementTotalErrorCount(); 52 53 // If in the future we interop with other sanitizers, we will 54 // need to make our own stackdepot 55 StackDepotHandle handle = StackDepotPut_WithHandle(stack); 56 57 const bool is_stack_novel = handle.use_count() == 0; 58 if (is_stack_novel || !flags().suppress_equal_stacks) { 59 IncrementUniqueErrorCount(); 60 61 { 62 ScopedErrorReportLock l; 63 PrintDiagnostics(info); 64 stack.Print(); 65 PrintErrorSummary(info, stack); 66 } 67 68 handle.inc_use_count_unsafe(); 69 } 70 71 if (flags().halt_on_error) { 72 if (flags().print_stats_on_exit) 73 PrintStatisticsSummary(); 74 Die(); 75 } 76 } 77 78 extern "C" { 79 80 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() { 81 CHECK(GetInitializationState() == InitializationState::Uninitialized); 82 SetInitializationState(InitializationState::Initializing); 83 84 SanitizerToolName = "RealtimeSanitizer"; 85 InitializeFlags(); 86 87 InitializePlatformEarly(); 88 89 InitializeInterceptors(); 90 91 InitializeSuppressions(); 92 93 if (flags().print_stats_on_exit) 94 Atexit(PrintStatisticsSummary); 95 96 SetInitializationState(InitializationState::Initialized); 97 } 98 99 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_ensure_initialized() { 100 if (LIKELY(__rtsan_is_initialized())) 101 return; 102 103 SpinMutexLock lock(&rtsan_inited_mutex); 104 105 // Someone may have initialized us while we were waiting for the lock 106 if (__rtsan_is_initialized()) 107 return; 108 109 __rtsan_init(); 110 } 111 112 SANITIZER_INTERFACE_ATTRIBUTE bool __rtsan_is_initialized() { 113 return GetInitializationState() == InitializationState::Initialized; 114 } 115 116 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter() { 117 GetContextForThisThread().RealtimePush(); 118 } 119 120 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_exit() { 121 GetContextForThisThread().RealtimePop(); 122 } 123 124 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_disable() { 125 GetContextForThisThread().BypassPush(); 126 } 127 128 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_enable() { 129 GetContextForThisThread().BypassPop(); 130 } 131 132 SANITIZER_INTERFACE_ATTRIBUTE void 133 __rtsan_notify_intercepted_call(const char *func_name) { 134 // While initializing, we need all intercepted functions to behave normally 135 if (GetInitializationState() == InitializationState::Initializing) 136 return; 137 138 __rtsan_ensure_initialized(); 139 GET_CALLER_PC_BP; 140 ExpectNotRealtime(GetContextForThisThread(), 141 {DiagnosticsInfoType::InterceptedCall, func_name, pc, bp}, 142 OnViolation); 143 } 144 145 SANITIZER_INTERFACE_ATTRIBUTE void 146 __rtsan_notify_blocking_call(const char *func_name) { 147 __rtsan_ensure_initialized(); 148 GET_CALLER_PC_BP; 149 ExpectNotRealtime(GetContextForThisThread(), 150 {DiagnosticsInfoType::BlockingCall, func_name, pc, bp}, 151 OnViolation); 152 } 153 154 } // extern "C" 155