Following the example of tsan, where we took the name This would allow users to determine if they want to see ALL output from rtsan. Additionally, remove the UNLIKELY hint, as it is now up to the flag whether or not it is likely that we go through this conditional.
152 lines
4.3 KiB
C++
152 lines
4.3 KiB
C++
//===--- 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();
|
|
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"
|