1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
//===--- 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"
|