Skip to content

Commit 8acf885

Browse files
authored
[LLVM][rtsan] Add RealtimeSanitizer transform pass (#101232)
Split from #100596. Introduce the RealtimeSanitizer transform, which inserts the rtsan_enter/exit functions at the appropriate places in an instrumented function.
1 parent 1d9e1c6 commit 8acf885

File tree

7 files changed

+170
-0
lines changed

7 files changed

+170
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===- RealtimeSanitizer.h - RealtimeSanitizer instrumentation --*- 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 RealtimeSanitizer, an LLVM transformation for
10+
// detecting and reporting realtime safety violations.
11+
//
12+
// The instrumentation pass inserts calls to __rtsan_realtime_enter and
13+
// __rtsan_realtime_exit at the entry and exit points of functions that are
14+
// marked with the appropriate attribute.
15+
//
16+
// See also: llvm-project/compiler-rt/lib/rtsan/
17+
//
18+
//===----------------------------------------------------------------------===//
19+
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
20+
#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
21+
22+
#include "llvm/IR/PassManager.h"
23+
24+
namespace llvm {
25+
26+
struct RealtimeSanitizerOptions {};
27+
28+
class RealtimeSanitizerPass : public PassInfoMixin<RealtimeSanitizerPass> {
29+
public:
30+
RealtimeSanitizerPass(const RealtimeSanitizerOptions &Options);
31+
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
32+
33+
static bool isRequired() { return true; }
34+
35+
private:
36+
RealtimeSanitizerOptions Options{};
37+
};
38+
39+
} // namespace llvm
40+
41+
#endif // LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@
199199
#include "llvm/Transforms/Instrumentation/PGOForceFunctionAttrs.h"
200200
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
201201
#include "llvm/Transforms/Instrumentation/PoisonChecking.h"
202+
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
202203
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
203204
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
204205
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
@@ -1210,6 +1211,11 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
12101211
return Opts;
12111212
}
12121213

1214+
Expected<RealtimeSanitizerOptions> parseRtSanPassOptions(StringRef Params) {
1215+
RealtimeSanitizerOptions Result;
1216+
return Result;
1217+
}
1218+
12131219
} // namespace
12141220

12151221
/// Tests whether a pass name starts with a valid prefix for a default pipeline

llvm/lib/Passes/PassRegistry.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,10 @@ FUNCTION_PASS_WITH_PARAMS(
592592
return WinEHPreparePass(DemoteCatchSwitchPHIOnly);
593593
},
594594
parseWinEHPrepareOptions, "demote-catchswitch-only")
595+
FUNCTION_PASS_WITH_PARAMS(
596+
"rtsan", "RealtimeSanitizerPass",
597+
[](RealtimeSanitizerOptions Opts) { return RealtimeSanitizerPass(Opts); },
598+
parseRtSanPassOptions, "")
595599
#undef FUNCTION_PASS_WITH_PARAMS
596600

597601
#ifndef LOOPNEST_PASS

llvm/lib/Transforms/Instrumentation/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_llvm_component_library(LLVMInstrumentation
2525
ValueProfileCollector.cpp
2626
ThreadSanitizer.cpp
2727
HWAddressSanitizer.cpp
28+
RealtimeSanitizer.cpp
2829

2930
ADDITIONAL_HEADER_DIRS
3031
${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===- RealtimeSanitizer.cpp - RealtimeSanitizer instrumentation *- 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 RealtimeSanitizer, an LLVM transformation for
10+
// detecting and reporting realtime safety violations.
11+
//
12+
// See also: llvm-project/compiler-rt/lib/rtsan/
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "llvm/IR/Analysis.h"
17+
#include "llvm/IR/IRBuilder.h"
18+
#include "llvm/IR/Module.h"
19+
20+
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
21+
22+
using namespace llvm;
23+
24+
static void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction,
25+
const char *FunctionName) {
26+
LLVMContext &Context = Fn.getContext();
27+
FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context), false);
28+
FunctionCallee Func =
29+
Fn.getParent()->getOrInsertFunction(FunctionName, FuncType);
30+
IRBuilder<> Builder{&Instruction};
31+
Builder.CreateCall(Func, {});
32+
}
33+
34+
static void insertCallAtFunctionEntryPoint(Function &Fn,
35+
const char *InsertFnName) {
36+
37+
insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName);
38+
}
39+
40+
static void insertCallAtAllFunctionExitPoints(Function &Fn,
41+
const char *InsertFnName) {
42+
for (auto &BB : Fn)
43+
for (auto &I : BB)
44+
if (auto *RI = dyn_cast<ReturnInst>(&I))
45+
insertCallBeforeInstruction(Fn, I, InsertFnName);
46+
}
47+
48+
RealtimeSanitizerPass::RealtimeSanitizerPass(
49+
const RealtimeSanitizerOptions &Options)
50+
: Options{Options} {}
51+
52+
PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
53+
AnalysisManager<Function> &AM) {
54+
if (F.hasFnAttribute(Attribute::SanitizeRealtime)) {
55+
insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
56+
insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
57+
return PreservedAnalyses::none();
58+
}
59+
60+
return PreservedAnalyses::all();
61+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
; RUN: opt < %s -passes=rtsan -S | FileCheck %s
2+
3+
define void @violation() #0 {
4+
%1 = alloca ptr, align 8
5+
%2 = call ptr @malloc(i64 noundef 2) #3
6+
store ptr %2, ptr %1, align 8
7+
ret void
8+
}
9+
10+
declare ptr @malloc(i64 noundef) #1
11+
12+
define noundef i32 @main() #2 {
13+
%1 = alloca i32, align 4
14+
store i32 0, ptr %1, align 4
15+
call void @violation() #4
16+
ret i32 0
17+
}
18+
19+
attributes #0 = { mustprogress noinline sanitize_realtime optnone ssp uwtable(sync) }
20+
21+
; RealtimeSanitizer pass should insert __rtsan_realtime_enter right after function definition
22+
; CHECK-LABEL: @violation()
23+
; CHECK-NEXT: call{{.*}}@__rtsan_realtime_enter
24+
25+
; RealtimeSanitizer pass should insert __rtsan_realtime_exit right before function return
26+
; CHECK: call{{.*}}@__rtsan_realtime_exit
27+
; CHECK-NEXT: ret{{.*}}void
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
; RUN: opt < %s -passes=rtsan -S | FileCheck %s
2+
3+
define i32 @example(i32 %x) #0 {
4+
entry:
5+
%retval = alloca i32
6+
%cmp = icmp sgt i32 %x, 10
7+
br i1 %cmp, label %then, label %else
8+
9+
then:
10+
ret i32 1
11+
12+
else:
13+
ret i32 0
14+
}
15+
16+
attributes #0 = { mustprogress noinline sanitize_realtime optnone ssp uwtable(sync) }
17+
18+
; RealtimeSanitizer pass should insert __rtsan_realtime_enter right after function definition
19+
; CHECK-LABEL: @example(
20+
; CHECK-NEXT: entry:
21+
; CHECK-NEXT: call{{.*}}@__rtsan_realtime_enter
22+
23+
; RealtimeSanitizer pass should insert the call at both function returns
24+
; CHECK-LABEL: then:
25+
; CHECK-NEXT: call{{.*}}@__rtsan_realtime_exit
26+
; CHECK-NEXT: ret i32 1
27+
28+
; CHECK-LABEL: else:
29+
; CHECK-NEXT: call{{.*}}@__rtsan_realtime_exit
30+
; CHECK-NEXT: ret i32 0

0 commit comments

Comments
 (0)