[llvm] Rtsan/blocking 2 llvm pass (PR #109543)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 21 11:58:55 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-compiler-rt-sanitizer
Author: None (davidtrevelyan)
<details>
<summary>Changes</summary>
# Pass update for sanitize_realtime_unsafe
Follows https://github.com/llvm/llvm-project/pull/106754
## Motivation
Calls to system library functions such as malloc are easy for RealtimeSanitizer to intercept. If such a call is made in a `[[clang::nonblocking]]` function (a real-time context), RealtimeSanitizer will error. Real-time programmers also write their own blocking (real-time unsafe) functions that may or may not call intercepted functions. We wish to introduce a mechanism whereby RealtimeSanitizer can error on calls to these, too, if called within a real-time context.
At the same time as introducing `[[clang::nonblocking]]`, the `[[clang::blocking]]` attribute was also introduced. With the function effects warnings (as errors) activated, blocking functions cannot be called from non-blocking functions, and this is enforced at compile time. The purpose of this series of PRs is to introduce similar functionality into RealtimeSanitizer, so that it can make the equivalent check at run time.
## Implementation
We recently merged the `sanitize_realtime_unsafe` LLVM function attribute into `main`. Our next steps are to:
1. when `sanitize_realtime_unsafe` is detected, update RealtimeSanitizer's LLVM pass to insert a call to `__rtsan_notify_blocking_call`, and
2. switch on the feature by updating Clang's CodeGen to actually add the `sanitize_realtime_unsafe` attribute to the IR for functions attributed with `[[clang::blocking]]`.
Once the feature is switched on, RealtimeSanitizer will error if any calls to functions attributed with `[[clang::blocking]]` are made from `[[clang::nonblocking]]` functions.
## Integration Roadmap
The above functionality is currently split into three patches.
- [x] Introduction of the sanitize_realtime_unsafe LLVM attribute (previous PR), and
- [ ] An update to RealtimeSanitizer's LLVM pass to use it (this PR)
- [ ] An update to Clang's CodeGen to add the `sanitize_realtime_unsafe` attribute to functions attributed with `[[clang::blocking]]` (next PR)
---
Full diff: https://github.com/llvm/llvm-project/pull/109543.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp (+26-3)
- (added) llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll (+19)
``````````diff
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index 7854cf4f2c625f..f27cf83cd3cf3d 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -17,6 +17,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
using namespace llvm;
@@ -45,6 +46,26 @@ static void insertCallAtAllFunctionExitPoints(Function &Fn,
insertCallBeforeInstruction(Fn, I, InsertFnName);
}
+static PreservedAnalyses rtsanPreservedCFGAnalyses() {
+ PreservedAnalyses PA;
+ PA.preserveSet<CFGAnalyses>();
+ return PA;
+}
+
+static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &F) {
+ IRBuilder<> Builder(&F.front().front());
+ Value *NameArg = Builder.CreateGlobalString(demangle(F.getName()));
+
+ FunctionType *FuncType =
+ FunctionType::get(Type::getVoidTy(F.getContext()),
+ {PointerType::getUnqual(F.getContext())}, false);
+
+ FunctionCallee Func = F.getParent()->getOrInsertFunction(
+ "__rtsan_notify_blocking_call", FuncType);
+
+ Builder.CreateCall(Func, {NameArg});
+}
+
RealtimeSanitizerPass::RealtimeSanitizerPass(
const RealtimeSanitizerOptions &Options) {}
@@ -53,10 +74,12 @@ PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
if (F.hasFnAttribute(Attribute::SanitizeRealtime)) {
insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
+ return rtsanPreservedCFGAnalyses();
+ }
- PreservedAnalyses PA;
- PA.preserveSet<CFGAnalyses>();
- return PA;
+ if (F.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
+ insertNotifyBlockingCallAtFunctionEntryPoint(F);
+ return rtsanPreservedCFGAnalyses();
}
return PreservedAnalyses::all();
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
new file mode 100644
index 00000000000000..fe9f13778e35af
--- /dev/null
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
@@ -0,0 +1,19 @@
+; RUN: opt < %s -passes=rtsan -S | FileCheck %s
+
+define void @_Z17blocking_functionv() #0 {
+ ret void
+}
+
+define noundef i32 @main() #2 {
+ call void @_Z17blocking_functionv() #4
+ ret i32 0
+}
+
+attributes #0 = { mustprogress noinline sanitize_realtime_unsafe optnone ssp uwtable(sync) }
+
+; RealtimeSanitizer pass should create the demangled function name as a global string, and
+; pass it as input to an inserted __rtsan_expect_not_realtime call at the function entrypoint
+; CHECK: [[GLOBAL_STR:@[a-zA-Z0-9\.]+]]
+; CHECK-SAME: c"blocking_function()\00"
+; CHECK-LABEL: @_Z17blocking_functionv()
+; CHECK-NEXT: call{{.*}}@__rtsan_notify_blocking_call(ptr{{.*}}[[GLOBAL_STR]])
``````````
</details>
https://github.com/llvm/llvm-project/pull/109543
More information about the llvm-commits
mailing list