Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 3 additions & 0 deletions compiler-rt/lib/rtsan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ set(RTSAN_CXX_SOURCES
rtsan_flags.cpp
rtsan_interceptors.cpp
rtsan_stats.cpp
rtsan_suppressions.cpp
)

set(RTSAN_PREINIT_SOURCES
rtsan_preinit.cpp)

set(RTSAN_HEADERS
rtsan.h
rtsan_checks.inc
rtsan_assertions.h
rtsan_context.h
rtsan_diagnostics.h
rtsan_flags.h
rtsan_flags.inc
rtsan_stats.h
rtsan_suppressions.h
)

set(RTSAN_DEPS)
Expand Down
4 changes: 3 additions & 1 deletion compiler-rt/lib/rtsan/rtsan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
#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"
#include "sanitizer_common/sanitizer_stacktrace.h"

using namespace __rtsan;
using namespace __sanitizer;
Expand Down Expand Up @@ -85,6 +85,8 @@ SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() {
InitializeFlags();
InitializeInterceptors();

InitializeSuppressions();

if (flags().print_stats_on_exit)
Atexit(PrintStatisticsSummary);

Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_assertions.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "rtsan/rtsan.h"
#include "rtsan/rtsan_context.h"
#include "rtsan/rtsan_diagnostics.h"
#include "rtsan/rtsan_suppressions.h"

#include "sanitizer_common/sanitizer_stacktrace.h"

Expand All @@ -34,6 +35,9 @@ void ExpectNotRealtime(Context &context, const DiagnosticsInfo &info,
stack.Unwind(info.pc, info.bp, nullptr,
__sanitizer::common_flags()->fast_unwind_on_fatal);

if (HasSuppressions() && IsStackTraceSuppressed(stack))
return;

OnViolation(stack, info);
}
}
Expand Down
19 changes: 19 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_checks.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===-- rtsan_checks.inc ----------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// List of suppression checks handled by RTSan runtime.
//
//===----------------------------------------------------------------------===//
#ifndef RTSAN_CHECK
#error "Define RTSAN_CHECK prior to including this file!"
#endif

// RTSAN_CHECK(Name, SummaryKind)
// SummaryKind should be a string literal.

RTSAN_CHECK(CallStackContains, "call-stack-contains")
1 change: 1 addition & 0 deletions compiler-rt/lib/rtsan/rtsan_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@

RTSAN_FLAG(bool, halt_on_error, true, "Exit after first reported error.")
RTSAN_FLAG(bool, print_stats_on_exit, false, "Print stats on exit.")
RTSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
95 changes: 95 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_suppressions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//===--- rtsan_suppressions.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
//
//===----------------------------------------------------------------------===//
//
// This file is a part of the RTSan runtime, providing support for suppressions
//
//===----------------------------------------------------------------------===//

#include "rtsan/rtsan_suppressions.h"

#include "rtsan/rtsan_flags.h"

#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_suppressions.h"
#include "sanitizer_common/sanitizer_symbolizer.h"

#include <new>

using namespace __sanitizer;
using namespace __rtsan;

namespace {
enum class ErrorType {
#define RTSAN_CHECK(Name, FSanitizeFlagName) Name,
#include "rtsan_checks.inc"
#undef RTSAN_CHECK
};
} // namespace

alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)];
static SuppressionContext *suppression_ctx = nullptr;

static const char *kSuppressionTypes[] = {
#define RTSAN_CHECK(Name, FSanitizeFlagName) FSanitizeFlagName,
#include "rtsan_checks.inc"
#undef RTSAN_CHECK
};

static const char *ConvertTypeToFlagName(ErrorType Type) {
switch (Type) {
#define RTSAN_CHECK(Name, FSanitizeFlagName) \
case ErrorType::Name: \
return FSanitizeFlagName;
#include "rtsan_checks.inc"
#undef RTSAN_CHECK
}
UNREACHABLE("unknown ErrorType!");
}

bool __rtsan::HasSuppressions() { return suppression_ctx != nullptr; }

void __rtsan::InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);

// We will use suppression_ctx == nullptr as an early out
if (flags().suppressions[0] == '\0')
return;

suppression_ctx = new (suppression_placeholder)
SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
suppression_ctx->ParseFromFile(flags().suppressions);
}

bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) {
CHECK(HasSuppressions());

const char *call_stack_flag =
ConvertTypeToFlagName(ErrorType::CallStackContains);
if (!suppression_ctx->HasSuppressionType(call_stack_flag))
return false;

Symbolizer *symbolizer = Symbolizer::GetOrInit();
for (uptr i = 0; i < stack.size && stack.trace[i]; i++) {
const uptr addr = stack.trace[i];

SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr));
const SymbolizedStack *frames = symbolized_stack.get();
CHECK(frames);
for (const SymbolizedStack *cur = frames; cur; cur = cur->next) {
const char *function_name = cur->info.function;
if (!function_name)
continue;

Suppression *s;
if (suppression_ctx->Match(function_name, call_stack_flag, &s))
return true;
}
}
return false;
}
23 changes: 23 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_suppressions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===--- rtsan_suppressions.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
//
//===----------------------------------------------------------------------===//
//
// This file is a part of the RTSan runtime, providing support for suppressions
//
//===----------------------------------------------------------------------===//

#pragma once

#include "sanitizer_common/sanitizer_stacktrace.h"

namespace __rtsan {

void InitializeSuppressions();
bool HasSuppressions();
bool IsStackTraceSuppressed(const __sanitizer::StackTrace &stack);

} // namespace __rtsan
53 changes: 53 additions & 0 deletions compiler-rt/test/rtsan/stack_suppressions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// RUN: %clangxx -fsanitize=realtime %s -o %t
// RUN: %env_rtsan_opts=suppressions='%s.supp' not %run %t 2>&1 | FileCheck %s
// UNSUPPORTED: ios

// Intent: Ensure that suppressions work as intended

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <vector>

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

void VectorViolations() {
// All of these should be suppressed by *vector*
std::vector<int> v(10);
v.resize(20);
v.clear();
v.resize(0);
v.push_back(1);
v.reserve(10);
}

void BlockFunc() [[clang::blocking]] { usleep(1); }

void *process() [[clang::nonblocking]] {
void *ptr = MallocViolation();
VectorViolations();
BlockFunc();
free(ptr);

// This is the one that should abort the program
// Everything else is suppressed
usleep(1);

return ptr;
}

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

// CHECK-NOT: failed to open suppressions file
// CHECK: Intercepted call to real-time unsafe function
// CHECK-SAME: usleep

// CHECK-NOT: Intercepted call to real-time unsafe function
// CHECK-NOT: malloc
// CHECK-NOT: vector
// CHECK-NOT: free
// CHECK-NOT: BlockFunc
4 changes: 4 additions & 0 deletions compiler-rt/test/rtsan/stack_suppressions.cpp.supp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
call-stack-contains:MallocViolation
call-stack-contains:std::*vector
call-stack-contains:free
call-stack-contains:BlockFunc
Loading