-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[LLVM][rtsan] Add module pass to initialize rtsan #118989
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-clang Author: Chris Apple (cjappl) ChangesThis allows shared libraries instrumented with RTSan to be initialized. This approach directly mirrors the approach in Tsan, Asan and many of the other sanitizers:
Full diff: https://github.com/llvm/llvm-project/pull/118989.diff 5 Files Affected:
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index bf9b04f02e9f44..fbb3fb6e5ea423 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1024,12 +1024,14 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
FPM.addPass(BoundsCheckingPass());
});
- if (LangOpts.Sanitize.has(SanitizerKind::Realtime))
+ if (LangOpts.Sanitize.has(SanitizerKind::Realtime)) {
PB.registerScalarOptimizerLateEPCallback(
[](FunctionPassManager &FPM, OptimizationLevel Level) {
RealtimeSanitizerOptions Opts;
FPM.addPass(RealtimeSanitizerPass(Opts));
});
+ MPM.addPass(ModuleRealtimeSanitizerPass());
+ }
// Don't add sanitizers if we are here from ThinLTO PostLink. That already
// done on PreLink stage.
diff --git a/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
index f2ce1636551ce2..151e70e87b294d 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
@@ -33,6 +33,13 @@ class RealtimeSanitizerPass : public PassInfoMixin<RealtimeSanitizerPass> {
static bool isRequired() { return true; }
};
+/// Create ctor and init functions.
+struct ModuleRealtimeSanitizerPass
+ : public PassInfoMixin<ModuleRealtimeSanitizerPass> {
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+ static bool isRequired() { return true; }
+};
+
} // namespace llvm
#endif // LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 772ec5fd10e633..2ddebb07017c2a 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -138,6 +138,7 @@ MODULE_PASS("rel-lookup-table-converter", RelLookupTableConverterPass())
MODULE_PASS("rewrite-statepoints-for-gc", RewriteStatepointsForGC())
MODULE_PASS("rewrite-symbols", RewriteSymbolPass())
MODULE_PASS("rpo-function-attrs", ReversePostOrderFunctionAttrsPass())
+MODULE_PASS("rtsan-module", ModuleRealtimeSanitizerPass())
MODULE_PASS("sample-profile", SampleProfileLoaderPass())
MODULE_PASS("sancov-module", SanitizerCoveragePass())
MODULE_PASS("sanmd-module", SanitizerBinaryMetadataPass())
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index 88cb04695217d5..890c79ae96718a 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -17,12 +17,16 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Module.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
using namespace llvm;
+const char kRtsanModuleCtorName[] = "rtsan.module_ctor";
+const char kRtsanInitName[] = "__rtsan_ensure_initialized";
+
static SmallVector<Type *> getArgTypes(ArrayRef<Value *> FunctionArgs) {
SmallVector<Type *> Types;
for (Value *Arg : FunctionArgs)
@@ -89,3 +93,14 @@ PreservedAnalyses RealtimeSanitizerPass::run(Function &Fn,
return PreservedAnalyses::all();
}
+
+PreservedAnalyses ModuleRealtimeSanitizerPass::run(Module &M,
+ ModuleAnalysisManager &MAM) {
+ getOrCreateSanitizerCtorAndInitFunctions(
+ M, kRtsanModuleCtorName, kRtsanInitName, /*InitArgTypes=*/{},
+ /*InitArgs=*/{},
+ // This callback is invoked when the functions are created the first
+ // time. Hook them into the global ctors list in that case:
+ [&](Function *Ctor, FunctionCallee) { appendToGlobalCtors(M, Ctor, 0); });
+ return PreservedAnalyses::none();
+}
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll
index a0bc4aef2cc319..41b610d040e51c 100644
--- a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -passes=rtsan -S | FileCheck %s
+; RUN: opt < %s -passes='function(rtsan),module(rtsan-module)' -S | FileCheck %s
define void @violation() #0 {
%1 = alloca ptr, align 8
@@ -25,3 +25,7 @@ attributes #0 = { mustprogress noinline sanitize_realtime optnone ssp uwtable(sy
; RealtimeSanitizer pass should insert __rtsan_realtime_exit right before function return
; CHECK: call{{.*}}@__rtsan_realtime_exit
; CHECK-NEXT: ret{{.*}}void
+
+; RealtimeSanitizer pass should insert call to initialize the runtime
+; CHECK: define internal void @rtsan.module_ctor()
+; CHECK: call void @__rtsan_ensure_initialized()
|
@@ -1024,12 +1024,14 @@ void EmitAssemblyHelper::RunOptimizationPipeline( | |||
FPM.addPass(BoundsCheckingPass()); | |||
}); | |||
|
|||
if (LangOpts.Sanitize.has(SanitizerKind::Realtime)) | |||
if (LangOpts.Sanitize.has(SanitizerKind::Realtime)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll investigate if moving it is possible! Off the top of my head I don't know if there is a reason.
I'll report back with PRs on either/both of these soon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to consider performance vs quality.
For other sanitizers it's essentially:
- If it's early - better precision - in sense we detect issues in C/C++ program which can be optimized out. (can Realtime related issue be optimized out, and do you care about them at all)
- If it's late - better performance, but we may miss bugs
I believe performance is ~2x difference, so we can't afford that e.g. in Asan.
PB.registerScalarOptimizerLateEPCallback( | ||
[](FunctionPassManager &FPM, OptimizationLevel Level) { | ||
RealtimeSanitizerOptions Opts; | ||
FPM.addPass(RealtimeSanitizerPass(Opts)); | ||
}); | ||
MPM.addPass(ModuleRealtimeSanitizerPass()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also we converted all but tsan from function+module to just module pass. Easier to maintain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, I'll work on swapping rtsan over.
As mentioned in #118989, all sanitizers but tsan are converted to just module pass for easier maintainence. This patch removes the TySan function pass, convert TySan from function+module pass to just module pass.
…dule pass (#120667) As mentioned in llvm/llvm-project#118989, all sanitizers but tsan are converted to just module pass for easier maintenance. This patch removes the TySan function pass, convert TySan from function+module pass to just module pass.
This allows shared libraries instrumented with RTSan to be initialized.
This approach directly mirrors the approach in Tsan, Asan and many of the other sanitizers:
llvm-project/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
Line 175 in c74e223