Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rtsan] Support basic call stack suppressions #111608

Merged
merged 5 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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"

cjappl marked this conversation as resolved.
Show resolved Hide resolved
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 (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(InCallStack, "in-call-stack")
fmayer marked this conversation as resolved.
Show resolved Hide resolved
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.")
94 changes: 94 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_suppressions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//===--- 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!");
}

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

// We will use suppression_ctx == nullptr as an early out
if (flags().suppressions[0] == 0)
fmayer marked this conversation as resolved.
Show resolved Hide resolved
return;

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

bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) {
if (suppression_ctx == nullptr)
cjappl marked this conversation as resolved.
Show resolved Hide resolved
return false;

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

Symbolizer *symbolizer = Symbolizer::GetOrInit();
Suppression *s;
fmayer marked this conversation as resolved.
Show resolved Hide resolved

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;

if (suppression_ctx->Match(function_name, call_stack_flag, &s))
return true;
}
}
return false;
}
22 changes: 22 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_suppressions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===--- 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 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 @@
in-call-stack:MallocViolation
in-call-stack:std::*vector
in-call-stack:free
in-call-stack:BlockFunc
Loading