Skip to content

Commit 0f6ea9f

Browse files
cjapplDanielCChen
authored andcommitted
[rtsan] Support basic call stack suppressions (llvm#111608)
This adds basic support for suppressions, which is a first class feature of the other sanitizers.
1 parent d732ea1 commit 0f6ea9f

File tree

9 files changed

+203
-1
lines changed

9 files changed

+203
-1
lines changed

compiler-rt/lib/rtsan/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,22 @@ set(RTSAN_CXX_SOURCES
77
rtsan_flags.cpp
88
rtsan_interceptors.cpp
99
rtsan_stats.cpp
10+
rtsan_suppressions.cpp
1011
)
1112

1213
set(RTSAN_PREINIT_SOURCES
1314
rtsan_preinit.cpp)
1415

1516
set(RTSAN_HEADERS
1617
rtsan.h
18+
rtsan_checks.inc
1719
rtsan_assertions.h
1820
rtsan_context.h
1921
rtsan_diagnostics.h
2022
rtsan_flags.h
2123
rtsan_flags.inc
2224
rtsan_stats.h
25+
rtsan_suppressions.h
2326
)
2427

2528
set(RTSAN_DEPS)

compiler-rt/lib/rtsan/rtsan.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
#include "rtsan/rtsan_flags.h"
1515
#include "rtsan/rtsan_interceptors.h"
1616
#include "rtsan/rtsan_stats.h"
17+
#include "rtsan/rtsan_suppressions.h"
1718

1819
#include "sanitizer_common/sanitizer_atomic.h"
1920
#include "sanitizer_common/sanitizer_common.h"
2021
#include "sanitizer_common/sanitizer_mutex.h"
2122
#include "sanitizer_common/sanitizer_stackdepot.h"
22-
#include "sanitizer_common/sanitizer_stacktrace.h"
2323

2424
using namespace __rtsan;
2525
using namespace __sanitizer;
@@ -85,6 +85,8 @@ SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() {
8585
InitializeFlags();
8686
InitializeInterceptors();
8787

88+
InitializeSuppressions();
89+
8890
if (flags().print_stats_on_exit)
8991
Atexit(PrintStatisticsSummary);
9092

compiler-rt/lib/rtsan/rtsan_assertions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "rtsan/rtsan.h"
1616
#include "rtsan/rtsan_context.h"
1717
#include "rtsan/rtsan_diagnostics.h"
18+
#include "rtsan/rtsan_suppressions.h"
1819

1920
#include "sanitizer_common/sanitizer_stacktrace.h"
2021

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

38+
if (IsStackTraceSuppressed(stack))
39+
return;
40+
3741
OnViolation(stack, info);
3842
}
3943
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- rtsan_checks.inc ----------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// List of suppression checks handled by RTSan runtime.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
#ifndef RTSAN_CHECK
13+
#error "Define RTSAN_CHECK prior to including this file!"
14+
#endif
15+
16+
// RTSAN_CHECK(Name, SummaryKind)
17+
// SummaryKind should be a string literal.
18+
19+
RTSAN_CHECK(CallStackContains, "call-stack-contains")

compiler-rt/lib/rtsan/rtsan_flags.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@
1818

1919
RTSAN_FLAG(bool, halt_on_error, true, "Exit after first reported error.")
2020
RTSAN_FLAG(bool, print_stats_on_exit, false, "Print stats on exit.")
21+
RTSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//===--- rtsan_suppressions.cpp - Realtime Sanitizer ------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of the RTSan runtime, providing support for suppressions
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "rtsan/rtsan_suppressions.h"
14+
15+
#include "rtsan/rtsan_flags.h"
16+
17+
#include "sanitizer_common/sanitizer_common.h"
18+
#include "sanitizer_common/sanitizer_internal_defs.h"
19+
#include "sanitizer_common/sanitizer_suppressions.h"
20+
#include "sanitizer_common/sanitizer_symbolizer.h"
21+
22+
#include <new>
23+
24+
using namespace __sanitizer;
25+
using namespace __rtsan;
26+
27+
namespace {
28+
enum class ErrorType {
29+
#define RTSAN_CHECK(Name, FSanitizeFlagName) Name,
30+
#include "rtsan_checks.inc"
31+
#undef RTSAN_CHECK
32+
};
33+
} // namespace
34+
35+
alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)];
36+
static SuppressionContext *suppression_ctx = nullptr;
37+
38+
static const char *kSuppressionTypes[] = {
39+
#define RTSAN_CHECK(Name, FSanitizeFlagName) FSanitizeFlagName,
40+
#include "rtsan_checks.inc"
41+
#undef RTSAN_CHECK
42+
};
43+
44+
static const char *ConvertTypeToFlagName(ErrorType Type) {
45+
switch (Type) {
46+
#define RTSAN_CHECK(Name, FSanitizeFlagName) \
47+
case ErrorType::Name: \
48+
return FSanitizeFlagName;
49+
#include "rtsan_checks.inc"
50+
#undef RTSAN_CHECK
51+
}
52+
UNREACHABLE("unknown ErrorType!");
53+
}
54+
55+
void __rtsan::InitializeSuppressions() {
56+
CHECK_EQ(nullptr, suppression_ctx);
57+
58+
// We will use suppression_ctx == nullptr as an early out
59+
if (flags().suppressions[0] == '\0')
60+
return;
61+
62+
suppression_ctx = new (suppression_placeholder)
63+
SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
64+
suppression_ctx->ParseFromFile(flags().suppressions);
65+
}
66+
67+
bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) {
68+
if (suppression_ctx == nullptr)
69+
return false;
70+
71+
const char *call_stack_flag =
72+
ConvertTypeToFlagName(ErrorType::CallStackContains);
73+
if (!suppression_ctx->HasSuppressionType(call_stack_flag))
74+
return false;
75+
76+
Symbolizer *symbolizer = Symbolizer::GetOrInit();
77+
for (uptr i = 0; i < stack.size && stack.trace[i]; i++) {
78+
const uptr addr = stack.trace[i];
79+
80+
SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr));
81+
const SymbolizedStack *frames = symbolized_stack.get();
82+
CHECK(frames);
83+
for (const SymbolizedStack *cur = frames; cur; cur = cur->next) {
84+
const char *function_name = cur->info.function;
85+
if (!function_name)
86+
continue;
87+
88+
Suppression *s;
89+
if (suppression_ctx->Match(function_name, call_stack_flag, &s))
90+
return true;
91+
}
92+
}
93+
return false;
94+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===--- rtsan_suppressions.h - Realtime Sanitizer --------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of the RTSan runtime, providing support for suppressions
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#pragma once
14+
15+
#include "sanitizer_common/sanitizer_stacktrace.h"
16+
17+
namespace __rtsan {
18+
19+
void InitializeSuppressions();
20+
bool IsStackTraceSuppressed(const __sanitizer::StackTrace &stack);
21+
22+
} // namespace __rtsan
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %clangxx -fsanitize=realtime %s -o %t
2+
// RUN: %env_rtsan_opts=suppressions='%s.supp' not %run %t 2>&1 | FileCheck %s
3+
// UNSUPPORTED: ios
4+
5+
// Intent: Ensure that suppressions work as intended
6+
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
#include <unistd.h>
10+
11+
#include <vector>
12+
13+
void *MallocViolation() { return malloc(10); }
14+
15+
void VectorViolations() {
16+
// All of these should be suppressed by *vector*
17+
std::vector<int> v(10);
18+
v.resize(20);
19+
v.clear();
20+
v.resize(0);
21+
v.push_back(1);
22+
v.reserve(10);
23+
}
24+
25+
void BlockFunc() [[clang::blocking]] { usleep(1); }
26+
27+
void *process() [[clang::nonblocking]] {
28+
void *ptr = MallocViolation();
29+
VectorViolations();
30+
BlockFunc();
31+
free(ptr);
32+
33+
// This is the one that should abort the program
34+
// Everything else is suppressed
35+
usleep(1);
36+
37+
return ptr;
38+
}
39+
40+
int main() {
41+
process();
42+
return 0;
43+
}
44+
45+
// CHECK-NOT: failed to open suppressions file
46+
// CHECK: Intercepted call to real-time unsafe function
47+
// CHECK-SAME: usleep
48+
49+
// CHECK-NOT: Intercepted call to real-time unsafe function
50+
// CHECK-NOT: malloc
51+
// CHECK-NOT: vector
52+
// CHECK-NOT: free
53+
// CHECK-NOT: BlockFunc
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
call-stack-contains:MallocViolation
2+
call-stack-contains:std::*vector
3+
call-stack-contains:free
4+
call-stack-contains:BlockFunc

0 commit comments

Comments
 (0)