Skip to content

Commit 9d3d49f

Browse files
committed
[clang][rtsan] Introduce realtime sanitizer codegen and driver
1 parent e2f9c18 commit 9d3d49f

14 files changed

+135
-5
lines changed

clang/include/clang/Basic/Sanitizers.def

+3
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ SANITIZER("thread", Thread)
7979
// Numerical stability sanitizer.
8080
SANITIZER("numerical", NumericalStability)
8181

82+
// RealtimeSanitizer
83+
SANITIZER("realtime", Realtime)
84+
8285
// LeakSanitizer
8386
SANITIZER("leak", Leak)
8487

clang/include/clang/Driver/SanitizerArgs.h

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class SanitizerArgs {
106106
bool needsNsanRt() const {
107107
return Sanitizers.has(SanitizerKind::NumericalStability);
108108
}
109+
bool needsRtsanRt() const { return Sanitizers.has(SanitizerKind::Realtime); }
109110

110111
bool hasMemTag() const {
111112
return hasMemtagHeap() || hasMemtagStack() || hasMemtagGlobals();

clang/lib/CodeGen/BackendUtil.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
7979
#include "llvm/Transforms/Instrumentation/NumericalStabilitySanitizer.h"
8080
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
81+
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
8182
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
8283
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
8384
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
@@ -989,6 +990,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
989990
FPM.addPass(BoundsCheckingPass());
990991
});
991992

993+
if (LangOpts.Sanitize.has(SanitizerKind::Realtime))
994+
PB.registerScalarOptimizerLateEPCallback(
995+
[](FunctionPassManager &FPM, OptimizationLevel Level) {
996+
RealtimeSanitizerOptions Opts;
997+
FPM.addPass(RealtimeSanitizerPass(Opts));
998+
});
999+
9921000
// Don't add sanitizers if we are here from ThinLTO PostLink. That already
9931001
// done on PreLink stage.
9941002
if (!IsThinLTOPostLink) {

clang/lib/CodeGen/CodeGenFunction.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,12 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
845845
if (SanOpts.has(SanitizerKind::ShadowCallStack))
846846
Fn->addFnAttr(llvm::Attribute::ShadowCallStack);
847847

848+
if (SanOpts.has(SanitizerKind::Realtime)) {
849+
for (const FunctionEffectWithCondition &Fe : FD->getFunctionEffects())
850+
if (Fe.Effect.kind() == FunctionEffect::Kind::NonBlocking)
851+
Fn->addFnAttr(llvm::Attribute::SanitizeRealtime);
852+
}
853+
848854
// Apply fuzzing attribute to the function.
849855
if (SanOpts.hasOneOf(SanitizerKind::Fuzzer | SanitizerKind::FuzzerNoLink))
850856
Fn->addFnAttr(llvm::Attribute::OptForFuzzing);

clang/lib/Driver/SanitizerArgs.cpp

+9-5
Original file line numberDiff line numberDiff line change
@@ -552,11 +552,15 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
552552
SanitizerKind::Leak | SanitizerKind::Thread |
553553
SanitizerKind::Memory | SanitizerKind::KernelAddress |
554554
SanitizerKind::Scudo | SanitizerKind::SafeStack),
555-
std::make_pair(SanitizerKind::MemTag,
556-
SanitizerKind::Address | SanitizerKind::KernelAddress |
557-
SanitizerKind::HWAddress |
558-
SanitizerKind::KernelHWAddress),
559-
std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function)};
555+
std::make_pair(SanitizerKind::MemTag, SanitizerKind::Address |
556+
SanitizerKind::KernelAddress |
557+
SanitizerKind::HWAddress |
558+
SanitizerKind::KernelHWAddress),
559+
std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function),
560+
std::make_pair(SanitizerKind::Realtime,
561+
SanitizerKind::Address | SanitizerKind::Thread |
562+
SanitizerKind::Undefined | SanitizerKind::Memory)};
563+
560564
// Enable toolchain specific default sanitizers if not explicitly disabled.
561565
SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;
562566

clang/lib/Driver/ToolChains/CommonArgs.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
14311431
if (!Args.hasArg(options::OPT_shared))
14321432
HelperStaticRuntimes.push_back("hwasan-preinit");
14331433
}
1434+
if (SanArgs.needsRtsanRt() && SanArgs.linkRuntimes())
1435+
SharedRuntimes.push_back("rtsan");
14341436
}
14351437

14361438
// The stats_client library is also statically linked into DSOs.
@@ -1456,6 +1458,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
14561458
StaticRuntimes.push_back("asan_cxx");
14571459
}
14581460

1461+
if (!SanArgs.needsSharedRt() && SanArgs.needsRtsanRt() &&
1462+
SanArgs.linkRuntimes())
1463+
StaticRuntimes.push_back("rtsan");
1464+
14591465
if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt()) {
14601466
StaticRuntimes.push_back("memprof");
14611467
if (SanArgs.linkCXXRuntimes())

clang/lib/Driver/ToolChains/Darwin.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
15191519
const char *sanitizer = nullptr;
15201520
if (Sanitize.needsUbsanRt()) {
15211521
sanitizer = "UndefinedBehaviorSanitizer";
1522+
} else if (Sanitize.needsRtsanRt()) {
1523+
sanitizer = "RealtimeSanitizer";
15221524
} else if (Sanitize.needsAsanRt()) {
15231525
sanitizer = "AddressSanitizer";
15241526
} else if (Sanitize.needsTsanRt()) {
@@ -1541,6 +1543,11 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
15411543
AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
15421544
}
15431545
}
1546+
if (Sanitize.needsRtsanRt()) {
1547+
assert(Sanitize.needsSharedRt() &&
1548+
"Static sanitizer runtimes not supported");
1549+
AddLinkSanitizerLibArgs(Args, CmdArgs, "rtsan");
1550+
}
15441551
if (Sanitize.needsLsanRt())
15451552
AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan");
15461553
if (Sanitize.needsUbsanRt()) {
@@ -3531,6 +3538,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
35313538
Res |= SanitizerKind::Address;
35323539
Res |= SanitizerKind::PointerCompare;
35333540
Res |= SanitizerKind::PointerSubtract;
3541+
Res |= SanitizerKind::Realtime;
35343542
Res |= SanitizerKind::Leak;
35353543
Res |= SanitizerKind::Fuzzer;
35363544
Res |= SanitizerKind::FuzzerNoLink;

clang/lib/Driver/ToolChains/Linux.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
800800
Res |= SanitizerKind::Address;
801801
Res |= SanitizerKind::PointerCompare;
802802
Res |= SanitizerKind::PointerSubtract;
803+
Res |= SanitizerKind::Realtime;
803804
Res |= SanitizerKind::Fuzzer;
804805
Res |= SanitizerKind::FuzzerNoLink;
805806
Res |= SanitizerKind::KernelAddress;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %clang -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s
2+
3+
float process(float *a) [[clang::nonblocking]] { return *a; }
4+
5+
// CHECK-LABEL: @process{{.*}}#0 {
6+
// CHECK: attributes #0 = {
7+
// CHECK-SAME: {{.*sanitize_realtime.*}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsanitize=realtime -emit-llvm -o - %s | FileCheck %s
2+
3+
// The first instruction after the function is entred should be a call to
4+
// enable the realtime sanitizer stack
5+
6+
int foo(int *a) [[clang::nonblocking]] { return *a; }
7+
// CHECK-LABEL: define{{.*}}@foo
8+
// CHECK-NEXT: entry:
9+
// CHECK-NEXT: call{{.*}}__rtsan_realtime_enter
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsanitize=realtime -emit-llvm -o - %s | FileCheck %s
2+
3+
// __rtsan_realtime_exit should be inserted at all function returns
4+
5+
int bar(int* x) [[clang::nonblocking]] {
6+
return *x;
7+
}
8+
// CHECK-LABEL: call{{.*}}__rtsan_realtime_exit
9+
// CHECK-NEXT: ret
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %clang -target x86_64-unknown-linux %s -S -emit-llvm -o - | FileCheck %s
2+
3+
4+
float process(float *a) [[clang::nonblocking]] { return *a; }
5+
6+
// Without the -fsanitize=realtime flag, we shouldn't attach
7+
// the attribute
8+
// CHECK-NOT: {{.*sanitize_realtime.*}}

clang/test/Driver/fsanitize.c

+46
Original file line numberDiff line numberDiff line change
@@ -1040,3 +1040,49 @@
10401040
// RUN: not %clang --target=aarch64-none-elf -fsanitize=dataflow %s -### 2>&1 | FileCheck %s -check-prefix=UNSUPPORTED-BAREMETAL
10411041
// RUN: not %clang --target=arm-arm-none-eabi -fsanitize=shadow-call-stack %s -### 2>&1 | FileCheck %s -check-prefix=UNSUPPORTED-BAREMETAL
10421042
// UNSUPPORTED-BAREMETAL: unsupported option '-fsanitize={{.*}}' for target
1043+
1044+
// RUN: %clang --target=x86_64-apple-darwin -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-DARWIN
1045+
// CHECK-RTSAN-X86-64-DARWIN-NOT: unsupported option
1046+
1047+
// RUN: %clang --target=x86_64-apple-darwin -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-DARWIN
1048+
// CHECK-RTSAN-X86-64-DARWIN-NOT: unsupported option
1049+
// RUN: %clang --target=x86_64-apple-macos -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-MACOS
1050+
// CHECK-RTSAN-X86-64-MACOS-NOT: unsupported option
1051+
// RUN: %clang --target=arm64-apple-macos -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-ARM64-MACOS
1052+
// CHECK-RTSAN-ARM64-MACOS-NOT: unsupported option
1053+
1054+
// RUN: %clang --target=arm64-apple-ios-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-ARM64-IOSSIMULATOR
1055+
// CHECK-RTSAN-ARM64-IOSSIMULATOR-NOT: unsupported option
1056+
1057+
// RUN: %clang --target=arm64-apple-watchos-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-ARM64-WATCHOSSIMULATOR
1058+
// CHECK-RTSAN-ARM64-WATCHOSSIMULATOR-NOT: unsupported option
1059+
1060+
// RUN: %clang --target=arm64-apple-tvos-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-ARM64-TVOSSIMULATOR
1061+
// CHECK-RTSAN-ARM64-TVOSSIMULATOR-NOT: unsupported option
1062+
1063+
// RUN: %clang --target=x86_64-apple-ios-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-IOSSIMULATOR
1064+
// CHECK-RTSAN-X86-64-IOSSIMULATOR-NOT: unsupported option
1065+
1066+
// RUN: %clang --target=x86_64-apple-watchos-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-WATCHOSSIMULATOR
1067+
// CHECK-RTSAN-X86-64-WATCHOSSIMULATOR-NOT: unsupported option
1068+
1069+
// RUN: %clang --target=x86_64-apple-tvos-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-TVOSSIMULATOR
1070+
// CHECK-RTSAN-X86-64-TVOSSIMULATOR-NOT: unsupported option
1071+
1072+
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-LINUX
1073+
// CHECK-RTSAN-X86-64-LINUX-NOT: unsupported option
1074+
1075+
// RUN: not %clang --target=i386-pc-openbsd -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-OPENBSD
1076+
// CHECK-RTSAN-OPENBSD: unsupported option '-fsanitize=realtime' for target 'i386-pc-openbsd'
1077+
1078+
// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=realtime,thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-REALTIME-TSAN
1079+
// CHECK-REALTIME-TSAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=thread'
1080+
1081+
// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=realtime,address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-REALTIME-ASAN
1082+
// CHECK-REALTIME-ASAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=address'
1083+
1084+
// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=realtime,memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-REALTIME-MSAN
1085+
// CHECK-REALTIME-MSAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=memory'
1086+
1087+
// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=realtime,undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-REALTIME-UBSAN
1088+
// CHECK-REALTIME-UBSAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=undefined'

clang/test/Driver/rtsan.c

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s
2+
// RUN: %clang -O1 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s
3+
// RUN: %clang -O2 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s
4+
// RUN: %clang -O3 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s
5+
// RUN: %clang -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -flto=thin -o - | FileCheck %s
6+
// RUN: %clang -O2 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -flto=thin -o - | FileCheck %s
7+
// RUN: %clang -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -flto -o - | FileCheck %s
8+
// RUN: %clang -O2 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -flto -o - | FileCheck %s
9+
10+
// Ensure the rtsan_realtime calls are never optimized away
11+
12+
int foo(int *a) [[clang::nonblocking]] { return *a; }
13+
// CHECK: __rtsan_realtime_enter
14+
// CHECK: __rtsan_realtime_exit

0 commit comments

Comments
 (0)