|  | //===--- rtsan.cpp - Realtime Sanitizer -------------------------*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "rtsan/rtsan.h" | 
|  | #include "rtsan/rtsan_assertions.h" | 
|  | #include "rtsan/rtsan_diagnostics.h" | 
|  | #include "rtsan/rtsan_flags.h" | 
|  | #include "rtsan/rtsan_interceptors.h" | 
|  | #include "rtsan/rtsan_stats.h" | 
|  | #include "rtsan/rtsan_suppressions.h" | 
|  |  | 
|  | #include "sanitizer_common/sanitizer_atomic.h" | 
|  | #include "sanitizer_common/sanitizer_common.h" | 
|  | #include "sanitizer_common/sanitizer_mutex.h" | 
|  | #include "sanitizer_common/sanitizer_stackdepot.h" | 
|  |  | 
|  | using namespace __rtsan; | 
|  | using namespace __sanitizer; | 
|  |  | 
|  | namespace { | 
|  | enum class InitializationState : u8 { | 
|  | Uninitialized, | 
|  | Initializing, | 
|  | Initialized, | 
|  | }; | 
|  | } // namespace | 
|  |  | 
|  | static StaticSpinMutex rtsan_inited_mutex; | 
|  | static atomic_uint8_t rtsan_initialized = { | 
|  | static_cast<u8>(InitializationState::Uninitialized)}; | 
|  |  | 
|  | static void SetInitializationState(InitializationState state) { | 
|  | atomic_store(&rtsan_initialized, static_cast<u8>(state), | 
|  | memory_order_release); | 
|  | } | 
|  |  | 
|  | static InitializationState GetInitializationState() { | 
|  | return static_cast<InitializationState>( | 
|  | atomic_load(&rtsan_initialized, memory_order_acquire)); | 
|  | } | 
|  |  | 
|  | static void OnViolation(const BufferedStackTrace &stack, | 
|  | const DiagnosticsInfo &info) { | 
|  | IncrementTotalErrorCount(); | 
|  |  | 
|  | // If in the future we interop with other sanitizers, we will | 
|  | // need to make our own stackdepot | 
|  | StackDepotHandle handle = StackDepotPut_WithHandle(stack); | 
|  |  | 
|  | const bool is_stack_novel = handle.use_count() == 0; | 
|  | if (is_stack_novel || !flags().suppress_equal_stacks) { | 
|  | IncrementUniqueErrorCount(); | 
|  |  | 
|  | { | 
|  | ScopedErrorReportLock l; | 
|  | PrintDiagnostics(info); | 
|  | stack.Print(); | 
|  | PrintErrorSummary(info, stack); | 
|  | } | 
|  |  | 
|  | handle.inc_use_count_unsafe(); | 
|  | } | 
|  |  | 
|  | if (flags().halt_on_error) { | 
|  | if (flags().print_stats_on_exit) | 
|  | PrintStatisticsSummary(); | 
|  | Die(); | 
|  | } | 
|  | } | 
|  |  | 
|  | extern "C" { | 
|  |  | 
|  | SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() { | 
|  | CHECK(GetInitializationState() == InitializationState::Uninitialized); | 
|  | SetInitializationState(InitializationState::Initializing); | 
|  |  | 
|  | SanitizerToolName = "RealtimeSanitizer"; | 
|  | InitializeFlags(); | 
|  |  | 
|  | InitializePlatformEarly(); | 
|  |  | 
|  | InitializeInterceptors(); | 
|  |  | 
|  | InitializeSuppressions(); | 
|  |  | 
|  | if (flags().print_stats_on_exit) | 
|  | Atexit(PrintStatisticsSummary); | 
|  |  | 
|  | SetInitializationState(InitializationState::Initialized); | 
|  | } | 
|  |  | 
|  | SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_ensure_initialized() { | 
|  | if (LIKELY(__rtsan_is_initialized())) | 
|  | return; | 
|  |  | 
|  | SpinMutexLock lock(&rtsan_inited_mutex); | 
|  |  | 
|  | // Someone may have initialized us while we were waiting for the lock | 
|  | if (__rtsan_is_initialized()) | 
|  | return; | 
|  |  | 
|  | __rtsan_init(); | 
|  | } | 
|  |  | 
|  | SANITIZER_INTERFACE_ATTRIBUTE bool __rtsan_is_initialized() { | 
|  | return GetInitializationState() == InitializationState::Initialized; | 
|  | } | 
|  |  | 
|  | SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter() { | 
|  | GetContextForThisThread().RealtimePush(); | 
|  | } | 
|  |  | 
|  | SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_exit() { | 
|  | GetContextForThisThread().RealtimePop(); | 
|  | } | 
|  |  | 
|  | SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_disable() { | 
|  | GetContextForThisThread().BypassPush(); | 
|  | } | 
|  |  | 
|  | SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_enable() { | 
|  | GetContextForThisThread().BypassPop(); | 
|  | } | 
|  |  | 
|  | SANITIZER_INTERFACE_ATTRIBUTE void | 
|  | __rtsan_notify_intercepted_call(const char *func_name) { | 
|  | // While initializing, we need all intercepted functions to behave normally | 
|  | if (GetInitializationState() == InitializationState::Initializing) | 
|  | return; | 
|  |  | 
|  | __rtsan_ensure_initialized(); | 
|  | GET_CALLER_PC_BP; | 
|  | ExpectNotRealtime(GetContextForThisThread(), | 
|  | {DiagnosticsInfoType::InterceptedCall, func_name, pc, bp}, | 
|  | OnViolation); | 
|  | } | 
|  |  | 
|  | SANITIZER_INTERFACE_ATTRIBUTE void | 
|  | __rtsan_notify_blocking_call(const char *func_name) { | 
|  | __rtsan_ensure_initialized(); | 
|  | GET_CALLER_PC_BP; | 
|  | ExpectNotRealtime(GetContextForThisThread(), | 
|  | {DiagnosticsInfoType::BlockingCall, func_name, pc, bp}, | 
|  | OnViolation); | 
|  | } | 
|  |  | 
|  | } // extern "C" |