[llvm] [llvm][rtsan] Add transform pass for sanitize_realtime_unsafe (PR #109543)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 24 09:24:40 PDT 2024


https://github.com/davidtrevelyan updated https://github.com/llvm/llvm-project/pull/109543

>From 5c3e345d1a02ca1ebbc4243f23f7f1fb5d37ec6a Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Fri, 30 Aug 2024 15:14:24 +0100
Subject: [PATCH 1/6] Implement sanitize_realtime_unsafe Pass

---
 .../Instrumentation/RealtimeSanitizer.cpp     | 28 +++++++++++++++++--
 .../RealtimeSanitizer/rtsan_unsafe.ll         | 16 +++++++++++
 2 files changed, 41 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll

diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index 7854cf4f2c625f..ae60122c13b079 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -45,6 +45,26 @@ static void insertCallAtAllFunctionExitPoints(Function &Fn,
         insertCallBeforeInstruction(Fn, I, InsertFnName);
 }
 
+static PreservedAnalyses rtsanPreservedAnalyses() {
+  PreservedAnalyses PA;
+  PA.preserveSet<CFGAnalyses>();
+  return PA;
+}
+
+static void transformRealtimeUnsafeFunction(Function &F) {
+  IRBuilder<> Builder(&F.front().front());
+  Value *NameArg = Builder.CreateGlobalString(F.getName());
+
+  FunctionType *FuncType =
+      FunctionType::get(Type::getVoidTy(F.getContext()),
+                        {PointerType::getUnqual(F.getContext())}, false);
+
+  FunctionCallee Func = F.getParent()->getOrInsertFunction(
+      "__rtsan_expect_not_realtime", FuncType);
+
+  Builder.CreateCall(Func, {NameArg});
+}
+
 RealtimeSanitizerPass::RealtimeSanitizerPass(
     const RealtimeSanitizerOptions &Options) {}
 
@@ -53,10 +73,12 @@ PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
   if (F.hasFnAttribute(Attribute::SanitizeRealtime)) {
     insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
     insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
+    return rtsanPreservedAnalyses();
+  }
 
-    PreservedAnalyses PA;
-    PA.preserveSet<CFGAnalyses>();
-    return PA;
+  if (F.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
+    transformRealtimeUnsafeFunction(F);
+    return rtsanPreservedAnalyses();
   }
 
   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..646a9a0e22e213
--- /dev/null
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
@@ -0,0 +1,16 @@
+; RUN: opt < %s -passes=rtsan -S | FileCheck %s
+
+define void @blocking_function() #0 {
+  ret void
+}
+
+define noundef i32 @main() #2 {
+  call void @blocking_function() #4
+  ret i32 0
+}
+
+attributes #0 = { mustprogress noinline sanitize_realtime_unsafe optnone ssp uwtable(sync) }
+
+; RealtimeSanitizer pass should insert __rtsan_expect_not_realtime at function entrypoint
+; CHECK-LABEL: @blocking_function()
+; CHECK-NEXT: call{{.*}}@__rtsan_expect_not_realtime({{ptr .*}})

>From 21b7f16c4d302a9e4363263d101f72e8535e8f72 Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Fri, 30 Aug 2024 16:24:06 +0100
Subject: [PATCH 2/6] Rename rtsan pass functions to be more explicit

---
 .../Transforms/Instrumentation/RealtimeSanitizer.cpp   | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index ae60122c13b079..b977badc9d6c1f 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -45,13 +45,13 @@ static void insertCallAtAllFunctionExitPoints(Function &Fn,
         insertCallBeforeInstruction(Fn, I, InsertFnName);
 }
 
-static PreservedAnalyses rtsanPreservedAnalyses() {
+static PreservedAnalyses rtsanPreservedCFGAnalyses() {
   PreservedAnalyses PA;
   PA.preserveSet<CFGAnalyses>();
   return PA;
 }
 
-static void transformRealtimeUnsafeFunction(Function &F) {
+static void insertExpectNotRealtimeAtFunctionEntryPoint(Function &F) {
   IRBuilder<> Builder(&F.front().front());
   Value *NameArg = Builder.CreateGlobalString(F.getName());
 
@@ -73,12 +73,12 @@ PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
   if (F.hasFnAttribute(Attribute::SanitizeRealtime)) {
     insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
     insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
-    return rtsanPreservedAnalyses();
+    return rtsanPreservedCFGAnalyses();
   }
 
   if (F.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
-    transformRealtimeUnsafeFunction(F);
-    return rtsanPreservedAnalyses();
+    insertExpectNotRealtimeAtFunctionEntryPoint(F);
+    return rtsanPreservedCFGAnalyses();
   }
 
   return PreservedAnalyses::all();

>From b0e4cf35c36f1738d6ddb665187bd02f6bd9e97f Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Sat, 31 Aug 2024 19:04:23 +0100
Subject: [PATCH 3/6] Demangle [[clang::blocking]] function names in rtsan pass

---
 .../Instrumentation/RealtimeSanitizer.cpp           |  3 ++-
 .../RealtimeSanitizer/rtsan_unsafe.ll               | 13 ++++++++-----
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index b977badc9d6c1f..c3ea1471796bdf 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;
@@ -53,7 +54,7 @@ static PreservedAnalyses rtsanPreservedCFGAnalyses() {
 
 static void insertExpectNotRealtimeAtFunctionEntryPoint(Function &F) {
   IRBuilder<> Builder(&F.front().front());
-  Value *NameArg = Builder.CreateGlobalString(F.getName());
+  Value *NameArg = Builder.CreateGlobalString(demangle(F.getName()));
 
   FunctionType *FuncType =
       FunctionType::get(Type::getVoidTy(F.getContext()),
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
index 646a9a0e22e213..0df01b95a79aea 100644
--- a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
@@ -1,16 +1,19 @@
 ; RUN: opt < %s -passes=rtsan -S | FileCheck %s
 
-define void @blocking_function() #0 {
+define void @_Z17blocking_functionv() #0 {
   ret void
 }
 
 define noundef i32 @main() #2 {
-  call void @blocking_function() #4
+  call void @_Z17blocking_functionv() #4
   ret i32 0
 }
 
 attributes #0 = { mustprogress noinline sanitize_realtime_unsafe optnone ssp uwtable(sync) }
 
-; RealtimeSanitizer pass should insert __rtsan_expect_not_realtime at function entrypoint
-; CHECK-LABEL: @blocking_function()
-; CHECK-NEXT: call{{.*}}@__rtsan_expect_not_realtime({{ptr .*}})
+; 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_expect_not_realtime(ptr{{.*}}[[GLOBAL_STR]])

>From c3dd787b960e48799decfbfbebdf22534b51d7a3 Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Sat, 21 Sep 2024 12:47:43 -0600
Subject: [PATCH 4/6] [rtsan] Update notify function name in blocking Pass

---
 llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp   | 6 +++---
 llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index c3ea1471796bdf..f27cf83cd3cf3d 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -52,7 +52,7 @@ static PreservedAnalyses rtsanPreservedCFGAnalyses() {
   return PA;
 }
 
-static void insertExpectNotRealtimeAtFunctionEntryPoint(Function &F) {
+static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &F) {
   IRBuilder<> Builder(&F.front().front());
   Value *NameArg = Builder.CreateGlobalString(demangle(F.getName()));
 
@@ -61,7 +61,7 @@ static void insertExpectNotRealtimeAtFunctionEntryPoint(Function &F) {
                         {PointerType::getUnqual(F.getContext())}, false);
 
   FunctionCallee Func = F.getParent()->getOrInsertFunction(
-      "__rtsan_expect_not_realtime", FuncType);
+      "__rtsan_notify_blocking_call", FuncType);
 
   Builder.CreateCall(Func, {NameArg});
 }
@@ -78,7 +78,7 @@ PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
   }
 
   if (F.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
-    insertExpectNotRealtimeAtFunctionEntryPoint(F);
+    insertNotifyBlockingCallAtFunctionEntryPoint(F);
     return rtsanPreservedCFGAnalyses();
   }
 
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
index 0df01b95a79aea..fe9f13778e35af 100644
--- a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
@@ -16,4 +16,4 @@ attributes #0 = { mustprogress noinline sanitize_realtime_unsafe optnone ssp uwt
 ; CHECK: [[GLOBAL_STR:@[a-zA-Z0-9\.]+]]
 ; CHECK-SAME: c"blocking_function()\00"
 ; CHECK-LABEL: @_Z17blocking_functionv()
-; CHECK-NEXT: call{{.*}}@__rtsan_expect_not_realtime(ptr{{.*}}[[GLOBAL_STR]])
+; CHECK-NEXT: call{{.*}}@__rtsan_notify_blocking_call(ptr{{.*}}[[GLOBAL_STR]])

>From e8dad4ce774d4a5b19a9112e8b6476c2e8df15ff Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Tue, 24 Sep 2024 16:58:16 +0100
Subject: [PATCH 5/6] [rtsan][NFC] Update test comment and variable names

---
 .../Instrumentation/RealtimeSanitizer.cpp     | 24 +++++++++----------
 .../RealtimeSanitizer/rtsan_unsafe.ll         |  4 ++--
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index f27cf83cd3cf3d..3885fe049adc02 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -52,15 +52,15 @@ static PreservedAnalyses rtsanPreservedCFGAnalyses() {
   return PA;
 }
 
-static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &F) {
-  IRBuilder<> Builder(&F.front().front());
-  Value *NameArg = Builder.CreateGlobalString(demangle(F.getName()));
+static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &Fn) {
+  IRBuilder<> Builder(&Fn.front().front());
+  Value *NameArg = Builder.CreateGlobalString(demangle(Fn.getName()));
 
   FunctionType *FuncType =
-      FunctionType::get(Type::getVoidTy(F.getContext()),
-                        {PointerType::getUnqual(F.getContext())}, false);
+      FunctionType::get(Type::getVoidTy(Fn.getContext()),
+                        {PointerType::getUnqual(Fn.getContext())}, false);
 
-  FunctionCallee Func = F.getParent()->getOrInsertFunction(
+  FunctionCallee Func = Fn.getParent()->getOrInsertFunction(
       "__rtsan_notify_blocking_call", FuncType);
 
   Builder.CreateCall(Func, {NameArg});
@@ -69,16 +69,16 @@ static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &F) {
 RealtimeSanitizerPass::RealtimeSanitizerPass(
     const RealtimeSanitizerOptions &Options) {}
 
-PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
+PreservedAnalyses RealtimeSanitizerPass::run(Function &Fn,
                                              AnalysisManager<Function> &AM) {
-  if (F.hasFnAttribute(Attribute::SanitizeRealtime)) {
-    insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
-    insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
+  if (Fn.hasFnAttribute(Attribute::SanitizeRealtime)) {
+    insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter");
+    insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit");
     return rtsanPreservedCFGAnalyses();
   }
 
-  if (F.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
-    insertNotifyBlockingCallAtFunctionEntryPoint(F);
+  if (Fn.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
+    insertNotifyBlockingCallAtFunctionEntryPoint(Fn);
     return rtsanPreservedCFGAnalyses();
   }
 
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
index fe9f13778e35af..68d9e0b195ba46 100644
--- a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
@@ -11,8 +11,8 @@ define noundef i32 @main() #2 {
 
 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
+; RealtimeSanitizer pass should create the demangled function name as a global string and,
+; at the function entrypoint, pass it as an argument to the rtsan notify method
 ; CHECK: [[GLOBAL_STR:@[a-zA-Z0-9\.]+]]
 ; CHECK-SAME: c"blocking_function()\00"
 ; CHECK-LABEL: @_Z17blocking_functionv()

>From 4dbd4e96299be0951d6001f54c8cc2b44abc5d59 Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Tue, 24 Sep 2024 17:23:14 +0100
Subject: [PATCH 6/6] [LLVM][rtsan] Refactor rtsan pass for code re-use

---
 .../Instrumentation/RealtimeSanitizer.cpp     | 63 ++++++++++---------
 1 file changed, 35 insertions(+), 28 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index 3885fe049adc02..fd68f43f882540 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -20,30 +20,43 @@
 #include "llvm/Demangle/Demangle.h"
 #include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
 
+#include <vector>
+
 using namespace llvm;
 
+static std::vector<Type *> getArgTypes(ArrayRef<Value *> FunctionArgs) {
+  std::vector<Type *> Types;
+  for (Value *Arg : FunctionArgs)
+    Types.push_back(Arg->getType());
+  return Types;
+}
+
 static void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction,
-                                        const char *FunctionName) {
+                                        const char *FunctionName,
+                                        ArrayRef<Value *> FunctionArgs) {
   LLVMContext &Context = Fn.getContext();
-  FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context), false);
+  FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context),
+                                             getArgTypes(FunctionArgs), false);
   FunctionCallee Func =
       Fn.getParent()->getOrInsertFunction(FunctionName, FuncType);
   IRBuilder<> Builder{&Instruction};
-  Builder.CreateCall(Func, {});
+  Builder.CreateCall(Func, FunctionArgs);
 }
 
 static void insertCallAtFunctionEntryPoint(Function &Fn,
-                                           const char *InsertFnName) {
-
-  insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName);
+                                           const char *InsertFnName,
+                                           ArrayRef<Value *> FunctionArgs) {
+  insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName,
+                              FunctionArgs);
 }
 
 static void insertCallAtAllFunctionExitPoints(Function &Fn,
-                                              const char *InsertFnName) {
+                                              const char *InsertFnName,
+                                              ArrayRef<Value *> FunctionArgs) {
   for (auto &BB : Fn)
     for (auto &I : BB)
       if (isa<ReturnInst>(&I))
-        insertCallBeforeInstruction(Fn, I, InsertFnName);
+        insertCallBeforeInstruction(Fn, I, InsertFnName, FunctionArgs);
 }
 
 static PreservedAnalyses rtsanPreservedCFGAnalyses() {
@@ -52,18 +65,17 @@ static PreservedAnalyses rtsanPreservedCFGAnalyses() {
   return PA;
 }
 
-static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &Fn) {
-  IRBuilder<> Builder(&Fn.front().front());
-  Value *NameArg = Builder.CreateGlobalString(demangle(Fn.getName()));
-
-  FunctionType *FuncType =
-      FunctionType::get(Type::getVoidTy(Fn.getContext()),
-                        {PointerType::getUnqual(Fn.getContext())}, false);
-
-  FunctionCallee Func = Fn.getParent()->getOrInsertFunction(
-      "__rtsan_notify_blocking_call", FuncType);
+static PreservedAnalyses runSanitizeRealtime(Function &Fn) {
+  insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter", {});
+  insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit", {});
+  return rtsanPreservedCFGAnalyses();
+}
 
-  Builder.CreateCall(Func, {NameArg});
+static PreservedAnalyses runSanitizeRealtimeUnsafe(Function &Fn) {
+  IRBuilder<> Builder(&Fn.front().front());
+  Value *Name = Builder.CreateGlobalString(demangle(Fn.getName()));
+  insertCallAtFunctionEntryPoint(Fn, "__rtsan_notify_blocking_call", {Name});
+  return rtsanPreservedCFGAnalyses();
 }
 
 RealtimeSanitizerPass::RealtimeSanitizerPass(
@@ -71,16 +83,11 @@ RealtimeSanitizerPass::RealtimeSanitizerPass(
 
 PreservedAnalyses RealtimeSanitizerPass::run(Function &Fn,
                                              AnalysisManager<Function> &AM) {
-  if (Fn.hasFnAttribute(Attribute::SanitizeRealtime)) {
-    insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter");
-    insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit");
-    return rtsanPreservedCFGAnalyses();
-  }
+  if (Fn.hasFnAttribute(Attribute::SanitizeRealtime))
+    return runSanitizeRealtime(Fn);
 
-  if (Fn.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
-    insertNotifyBlockingCallAtFunctionEntryPoint(Fn);
-    return rtsanPreservedCFGAnalyses();
-  }
+  if (Fn.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe))
+    return runSanitizeRealtimeUnsafe(Fn);
 
   return PreservedAnalyses::all();
 }



More information about the llvm-commits mailing list