Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions compiler-rt/lib/rtsan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ set(RTSAN_CXX_SOURCES
rtsan_context.cpp
rtsan_diagnostics.cpp
rtsan_flags.cpp
rtsan_interceptors.cpp)
rtsan_interceptors.cpp
rtsan_stats.cpp
)

set(RTSAN_PREINIT_SOURCES
rtsan_preinit.cpp)
Expand All @@ -16,7 +18,9 @@ set(RTSAN_HEADERS
rtsan_context.h
rtsan_diagnostics.h
rtsan_flags.h
rtsan_flags.inc)
rtsan_flags.inc
rtsan_stats.h
)

set(RTSAN_DEPS)

Expand Down
57 changes: 44 additions & 13 deletions compiler-rt/lib/rtsan/rtsan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <rtsan/rtsan_diagnostics.h>
#include <rtsan/rtsan_flags.h>
#include <rtsan/rtsan_interceptors.h>
#include <rtsan/rtsan_stats.h>

#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
Expand All @@ -22,30 +23,56 @@
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 = {0};

static void SetInitialized() {
atomic_store(&rtsan_initialized, 1, memory_order_release);
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 auto PrintDiagnosticsAndDieAction(DiagnosticsInfo info) {
return [info]() {
__rtsan::PrintDiagnostics(info);
Die();
static void RtsanAtexit() { PrintStatisticsSummary(); }

static auto DefaultErrorAction(DiagnosticsInfo info) {
return [info](const BufferedStackTrace &stack) {
if (flags().print_stats_on_exit)
IncrementTotalErrorCount();

PrintDiagnostics(info);
stack.Print();

if (flags().halt_on_error)
Die();
};
}

extern "C" {

SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() {
CHECK(!__rtsan_is_initialized());
CHECK(GetInitializationState() == InitializationState::Uninitialized);
SetInitializationState(InitializationState::Initializing);

SanitizerToolName = "RealtimeSanitizer";
InitializeFlags();
InitializeInterceptors();

SetInitialized();
if (flags().print_stats_on_exit)
Atexit(RtsanAtexit);

SetInitializationState(InitializationState::Initialized);
}

SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_ensure_initialized() {
Expand All @@ -62,7 +89,7 @@ SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_ensure_initialized() {
}

SANITIZER_INTERFACE_ATTRIBUTE bool __rtsan_is_initialized() {
return atomic_load(&rtsan_initialized, memory_order_acquire) == 1;
return GetInitializationState() == InitializationState::Initialized;
}

SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter() {
Expand All @@ -83,12 +110,16 @@ SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_enable() {

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(),
PrintDiagnosticsAndDieAction(
{DiagnosticsInfoType::InterceptedCall, func_name, pc, bp}));
DefaultErrorAction({DiagnosticsInfoType::InterceptedCall, func_name}), pc,
bp);
}

SANITIZER_INTERFACE_ATTRIBUTE void
Expand All @@ -97,8 +128,8 @@ __rtsan_notify_blocking_call(const char *func_name) {
GET_CALLER_PC_BP;
ExpectNotRealtime(
GetContextForThisThread(),
PrintDiagnosticsAndDieAction(
{DiagnosticsInfoType::BlockingCall, func_name, pc, bp}));
DefaultErrorAction({DiagnosticsInfoType::BlockingCall, func_name}), pc,
bp);
}

} // extern "C"
14 changes: 12 additions & 2 deletions compiler-rt/lib/rtsan/rtsan_assertions.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,25 @@

#include "rtsan/rtsan.h"
#include "rtsan/rtsan_context.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h"

namespace __rtsan {

template <typename OnViolationAction>
void ExpectNotRealtime(Context &context, OnViolationAction &&OnViolation) {
void ExpectNotRealtime(Context &context, OnViolationAction &&OnViolation,
__sanitizer::uptr caller_pc,
__sanitizer::uptr caller_bp) {
CHECK(__rtsan_is_initialized());
if (context.InRealtimeContext() && !context.IsBypassed()) {
context.BypassPush();
OnViolation();

__sanitizer::BufferedStackTrace stack;
stack.Unwind(caller_pc, caller_bp, nullptr,
/*fast*/ true);
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting the stack here is essential for deduplication. See the next change in the series here:

https://github.com/cjappl/llvm-project/pull/9/files#diff-26b1e9b52cc6bd23ad235825b8438ded1867285654d29b60536c5e87876adb3cR39-R46


OnViolation(stack);

context.BypassPop();
}
}
Expand Down
8 changes: 0 additions & 8 deletions compiler-rt/lib/rtsan/rtsan_diagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
};
} // namespace

static void PrintStackTrace(uptr pc, uptr bp) {
BufferedStackTrace stack{};

stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal);
stack.Print();
}

static void PrintError(const Decorator &decorator,
const DiagnosticsInfo &info) {
const auto ErrorTypeStr = [&info]() -> const char * {
Expand Down Expand Up @@ -91,5 +84,4 @@ void __rtsan::PrintDiagnostics(const DiagnosticsInfo &info) {
PrintError(d, info);
PrintReason(d, info);
Printf("%s", d.Default());
PrintStackTrace(info.pc, info.bp);
}
2 changes: 0 additions & 2 deletions compiler-rt/lib/rtsan/rtsan_diagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ enum class DiagnosticsInfoType {
struct DiagnosticsInfo {
DiagnosticsInfoType type;
const char *func_name;
__sanitizer::uptr pc;
__sanitizer::uptr bp;
};

void PrintDiagnostics(const DiagnosticsInfo &info);
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/rtsan/rtsan_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
// RTSAN_FLAG(Type, Name, DefaultValue, Description)
// See COMMON_FLAG in sanitizer_flags.inc for more details.

// Example flag, until we get a real one
// RTSAN_FLAG(bool, halt_on_error, true, "If true, halt the program on error")
RTSAN_FLAG(bool, halt_on_error, true, "Exit after first reported error.")
RTSAN_FLAG(bool, print_stats_on_exit, false, "Print stats on exit.")
35 changes: 35 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_stats.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===--- rtsan_stats.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
//
//===----------------------------------------------------------------------===//
//
// Part of the RealtimeSanitizer runtime library
//
//===----------------------------------------------------------------------===//

#include "rtsan/rtsan_stats.h"

#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"

using namespace __sanitizer;
using namespace __rtsan;

static atomic_uint32_t rtsan_total_error_count{0};

void __rtsan::IncrementTotalErrorCount() {
atomic_fetch_add(&rtsan_total_error_count, 1, memory_order_relaxed);
}

static u32 GetTotalErrorCount() {
return atomic_load(&rtsan_total_error_count, memory_order_relaxed);
}

void __rtsan::PrintStatisticsSummary() {
ScopedErrorReportLock l;
Printf("RealtimeSanitizer exit stats:\n");
Printf(" Total error count: %u\n", GetTotalErrorCount());
}
21 changes: 21 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_stats.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===--- rtsan_stats.h - 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
//
//===----------------------------------------------------------------------===//
//
// Part of the RealtimeSanitizer runtime library
//
//===----------------------------------------------------------------------===//

#pragma once

namespace __rtsan {

void IncrementTotalErrorCount();

void PrintStatisticsSummary();

} // namespace __rtsan
6 changes: 4 additions & 2 deletions compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <gmock/gmock.h>

using namespace __rtsan;
using namespace __sanitizer;

class TestRtsanAssertions : public ::testing::Test {
protected:
Expand All @@ -25,9 +26,10 @@ class TestRtsanAssertions : public ::testing::Test {

static void ExpectViolationAction(__rtsan::Context &context,
bool expect_violation_callback) {
::testing::MockFunction<void()> mock_on_violation;
::testing::MockFunction<void(const BufferedStackTrace &)> mock_on_violation;
EXPECT_CALL(mock_on_violation, Call).Times(expect_violation_callback ? 1 : 0);
ExpectNotRealtime(context, mock_on_violation.AsStdFunction());
GET_CALLER_PC_BP;
ExpectNotRealtime(context, mock_on_violation.AsStdFunction(), pc, bp);
}

TEST_F(TestRtsanAssertions,
Expand Down
23 changes: 23 additions & 0 deletions compiler-rt/test/rtsan/exit_stats.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %clangxx -fsanitize=realtime %s -o %t
// RUN: env RTSAN_OPTIONS="halt_on_error=false,print_stats_on_exit=true" %run %t 2>&1 | FileCheck %s

// UNSUPPORTED: ios

// Intent: Ensure exits stats are printed on exit.

#include <unistd.h>

void violation() [[clang::nonblocking]] {
const int kNumViolations = 10;
for (int i = 0; i < kNumViolations; i++) {
usleep(1);
}
}

int main() {
violation();
return 0;
}

// CHECK: RealtimeSanitizer exit stats:
// CHECK-NEXT: Total error count: 10
25 changes: 25 additions & 0 deletions compiler-rt/test/rtsan/halt_on_error.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RUN: %clangxx -fsanitize=realtime %s -o %t
// RUN: env RTSAN_OPTIONS="halt_on_error=false" %run %t 2>&1 | FileCheck %s
// UNSUPPORTED: ios

// Intent: Ensure that halt_on_error does not exit on the first violation.

#include <stdlib.h>

void *MallocViolation() { return malloc(10); }

void FreeViolation(void *Ptr) { free(Ptr); }

void process() [[clang::nonblocking]] {
void *Ptr = MallocViolation();
FreeViolation(Ptr);
}

int main() {
process();
return 0;
// CHECK: ==ERROR: RealtimeSanitizer
// CHECK-NEXT: {{.*`malloc`.*}}
// CHECK: ==ERROR: RealtimeSanitizer
// CHECK-NEXT: {{.*`free`.*}}
}