[llvm] [LLVM][rtsan] Add RealtimeSanitizer transform pass (PR #101232)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 30 12:44:25 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Chris Apple (cjappl)

<details>
<summary>Changes</summary>

Split from #<!-- -->100596 at the request of the reviewers. (This review directly depends on that review being merged first)

Introduce the RealtimeSanitizer transform, which inserts the rtsan_enter/exit functions at the appropriate places in an instrumented function.

---
Full diff: https://github.com/llvm/llvm-project/pull/101232.diff


7 Files Affected:

- (added) llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h (+35) 
- (added) llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h (+17) 
- (modified) llvm/lib/Passes/PassBuilder.cpp (+6) 
- (modified) llvm/lib/Passes/PassRegistry.def (+4) 
- (modified) llvm/lib/Transforms/Instrumentation/CMakeLists.txt (+1) 
- (added) llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp (+50) 
- (added) llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll (+35) 


``````````diff
diff --git a/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
new file mode 100644
index 0000000000000..9cf2448361608
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
@@ -0,0 +1,35 @@
+//===--------- Definition of the RealtimeSanitizer class ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
+
+#include "llvm/IR/PassManager.h"
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h"
+
+namespace llvm {
+
+struct RealtimeSanitizerOptions {};
+
+class RealtimeSanitizerPass : public PassInfoMixin<RealtimeSanitizerPass> {
+public:
+  RealtimeSanitizerPass(const RealtimeSanitizerOptions &Options);
+  PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
+
+  static bool isRequired() { return true; }
+
+private:
+  RealtimeSanitizerOptions Options{};
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
diff --git a/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h
new file mode 100644
index 0000000000000..35376a5647c60
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h
@@ -0,0 +1,17 @@
+//===--------- Definition of the RealtimeSanitizer options -------*- 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 defines data types used to set Realtime Sanitizer options.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
+
+namespace llvm {} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 5dbb1e2f49871..faf3e25cb31d9 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -198,6 +198,7 @@
 #include "llvm/Transforms/Instrumentation/PGOForceFunctionAttrs.h"
 #include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
 #include "llvm/Transforms/Instrumentation/PoisonChecking.h"
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
 #include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
 #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
 #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
@@ -1207,6 +1208,11 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
   return Opts;
 }
 
+Expected<RealtimeSanitizerOptions> parseRtSanPassOptions(StringRef Params) {
+  RealtimeSanitizerOptions Result;
+  return Result;
+}
+
 } // namespace
 
 /// Tests whether a pass name starts with a valid prefix for a default pipeline
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 3b92823cd283b..f795c7242f958 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -590,6 +590,10 @@ FUNCTION_PASS_WITH_PARAMS(
       return WinEHPreparePass(DemoteCatchSwitchPHIOnly);
     },
     parseWinEHPrepareOptions, "demote-catchswitch-only")
+FUNCTION_PASS_WITH_PARAMS(
+    "rtsan", "RealtimeSanitizerPass",
+    [](RealtimeSanitizerOptions Opts) { return RealtimeSanitizerPass(Opts); },
+    parseRtSanPassOptions, "")
 #undef FUNCTION_PASS_WITH_PARAMS
 
 #ifndef LOOPNEST_PASS
diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
index 4e3f9e27e0c34..deab37801ff1d 100644
--- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
+++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
@@ -25,6 +25,7 @@ add_llvm_component_library(LLVMInstrumentation
   ValueProfileCollector.cpp
   ThreadSanitizer.cpp
   HWAddressSanitizer.cpp
+  RealtimeSanitizer.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
new file mode 100644
index 0000000000000..2fa2389c4984f
--- /dev/null
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -0,0 +1,50 @@
+#include "llvm/IR/Analysis.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
+
+using namespace llvm;
+
+namespace {
+
+void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction,
+                                 const char *FunctionName) {
+  LLVMContext &Context = Fn.getContext();
+  FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context), false);
+  FunctionCallee Func =
+      Fn.getParent()->getOrInsertFunction(FunctionName, FuncType);
+  IRBuilder<> Builder{&Instruction};
+  Builder.CreateCall(Func, {});
+}
+
+void insertCallAtFunctionEntryPoint(Function &Fn, const char *InsertFnName) {
+
+  insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName);
+}
+
+void insertCallAtAllFunctionExitPoints(Function &Fn, const char *InsertFnName) {
+  for (auto &BB : Fn) {
+    for (auto &I : BB) {
+      if (auto *RI = dyn_cast<ReturnInst>(&I)) {
+        insertCallBeforeInstruction(Fn, I, InsertFnName);
+      }
+    }
+  }
+}
+} // namespace
+
+RealtimeSanitizerPass::RealtimeSanitizerPass(
+    const RealtimeSanitizerOptions &Options)
+    : Options{Options} {}
+
+PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
+                                             AnalysisManager<Function> &AM) {
+  if (F.hasFnAttribute(Attribute::NonBlocking)) {
+    insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
+    insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
+    return PreservedAnalyses::none();
+  }
+
+  return PreservedAnalyses::all();
+}
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll
new file mode 100644
index 0000000000000..222df484273c7
--- /dev/null
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -passes=rtsan -S | FileCheck %s
+
+; Function Attrs: mustprogress noinline nonblocking optnone ssp uwtable(sync)
+define void @violation() #0 {
+  %1 = alloca ptr, align 8
+  %2 = call ptr @malloc(i64 noundef 2) #3
+  store ptr %2, ptr %1, align 8
+  ret void
+}
+
+; Function Attrs: allocsize(0)
+declare ptr @malloc(i64 noundef) #1
+
+; Function Attrs: mustprogress noinline norecurse optnone ssp uwtable(sync)
+define noundef i32 @main() #2 {
+  %1 = alloca i32, align 4
+  store i32 0, ptr %1, align 4
+  call void @violation() #4
+  ret i32 0
+}
+
+attributes #0 = { mustprogress noinline nonblocking optnone ssp uwtable(sync) }
+attributes #1 = { allocsize(0) }
+attributes #2 = { mustprogress noinline norecurse optnone ssp uwtable(sync) }
+attributes #3 = { allocsize(0) }
+attributes #4 = { nonblocking }
+
+; RealtimeSanitizer pass should insert __rtsan_realtime_enter right after function definition
+; CHECK: define{{.*}}violation
+; CHECK-NEXT: call{{.*}}__rtsan_realtime_enter
+
+; RealtimeSanitizer pass should insert __rtsan_realtime_exit right before function return
+; CHECK: call{{.*}}@__rtsan_realtime_exit
+; CHECK-NEXT: ret{{.*}}void
+

``````````

</details>


https://github.com/llvm/llvm-project/pull/101232


More information about the llvm-commits mailing list