//===--- 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(InitializationState::Uninitialized)}; static void SetInitializationState(InitializationState state) { atomic_store(&rtsan_initialized, static_cast(state), memory_order_release); } static InitializationState GetInitializationState() { return static_cast( 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"