https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/120038
>From b42a2ec4a07d94c6c0d73d4baedf2ffef3d3825c Mon Sep 17 00:00:00 2001 From: Vitaly Buka <vitalyb...@google.com> Date: Sun, 15 Dec 2024 21:24:50 -0800 Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?= =?UTF-8?q?anges=20to=20main=20this=20commit=20is=20based=20on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- clang/lib/CodeGen/BackendUtil.cpp | 3 +- .../Instrumentation/BoundsChecking.h | 18 +++- llvm/lib/Passes/PassBuilder.cpp | 27 ++++++ llvm/lib/Passes/PassRegistry.def | 7 +- .../Instrumentation/BoundsChecking.cpp | 29 +++++- .../BoundsChecking/runtimes.ll | 95 +++++++++++++++++++ 6 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 llvm/test/Instrumentation/BoundsChecking/runtimes.ll diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 2ef098172c01f5..1e99efd086478f 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1023,7 +1023,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline( if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) PB.registerScalarOptimizerLateEPCallback( [](FunctionPassManager &FPM, OptimizationLevel Level) { - FPM.addPass(BoundsCheckingPass()); + FPM.addPass( + BoundsCheckingPass(BoundsCheckingPass::ReportingMode::Trap)); }); // Don't add sanitizers if we are here from ThinLTO PostLink. That already diff --git a/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h b/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h index b1b1ece3eff5a0..1876e5b72e8c99 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h +++ b/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h @@ -16,9 +16,25 @@ class Function; /// A pass to instrument code and perform run-time bounds checking on loads, /// stores, and other memory intrinsics. -struct BoundsCheckingPass : PassInfoMixin<BoundsCheckingPass> { +class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> { +public: + enum class ReportingMode { + Trap, + MinRuntime, + MinRuntimeAbort, + FullRuntime, + FullRuntimeAbort, + }; + +private: + ReportingMode Mode = ReportingMode::Trap; + +public: + BoundsCheckingPass(ReportingMode Mode) : Mode(Mode) {} PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); static bool isRequired() { return true; } + void printPipeline(raw_ostream &OS, + function_ref<StringRef(StringRef)> MapClassName2PassName); }; } // end namespace llvm diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 6e1cefdb3f4d70..6879c101086697 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -1281,6 +1281,33 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) { return Opts; } +Expected<BoundsCheckingPass::ReportingMode> +parseBoundsCheckingOptions(StringRef Params) { + BoundsCheckingPass::ReportingMode Mode = + BoundsCheckingPass::ReportingMode::Trap; + while (!Params.empty()) { + StringRef ParamName; + std::tie(ParamName, Params) = Params.split(';'); + if (ParamName == "trap") { + Mode = BoundsCheckingPass::ReportingMode::Trap; + } else if (ParamName == "rt") { + Mode = BoundsCheckingPass::ReportingMode::FullRuntime; + } else if (ParamName == "rt-abort") { + Mode = BoundsCheckingPass::ReportingMode::FullRuntimeAbort; + } else if (ParamName == "min-rt") { + Mode = BoundsCheckingPass::ReportingMode::MinRuntime; + } else if (ParamName == "min-rt-abort") { + Mode = BoundsCheckingPass::ReportingMode::MinRuntimeAbort; + } else { + return make_error<StringError>( + formatv("invalid BoundsChecking pass parameter '{0}' ", ParamName) + .str(), + inconvertibleErrorCode()); + } + } + return Mode; +} + } // 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 b7fc7d2ac7fee3..a8b0a349af122a 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -339,7 +339,6 @@ FUNCTION_PASS("assume-builder", AssumeBuilderPass()) FUNCTION_PASS("assume-simplify", AssumeSimplifyPass()) FUNCTION_PASS("atomic-expand", AtomicExpandPass(TM)) FUNCTION_PASS("bdce", BDCEPass()) -FUNCTION_PASS("bounds-checking", BoundsCheckingPass()) FUNCTION_PASS("break-crit-edges", BreakCriticalEdgesPass()) FUNCTION_PASS("callbr-prepare", CallBrPreparePass()) FUNCTION_PASS("callsite-splitting", CallSiteSplittingPass()) @@ -620,6 +619,12 @@ FUNCTION_PASS_WITH_PARAMS( return WinEHPreparePass(DemoteCatchSwitchPHIOnly); }, parseWinEHPrepareOptions, "demote-catchswitch-only") +FUNCTION_PASS_WITH_PARAMS( + "bounds-checking", "BoundsCheckingPass", + [](BoundsCheckingPass::ReportingMode Mode) { + return BoundsCheckingPass(Mode); + }, + parseBoundsCheckingOptions, "trap") #undef FUNCTION_PASS_WITH_PARAMS #ifndef LOOPNEST_PASS diff --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp index b398a13383b9eb..c4511d574f2185 100644 --- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -126,16 +126,18 @@ static void insertBoundsCheck(Value *Or, BuilderTy &IRB, GetTrapBBT GetTrapBB) { BasicBlock *Cont = OldBB->splitBasicBlock(SplitI); OldBB->getTerminator()->eraseFromParent(); + BasicBlock * TrapBB = GetTrapBB(IRB); + if (C) { // If we have a constant zero, unconditionally branch. // FIXME: We should really handle this differently to bypass the splitting // the block. - BranchInst::Create(GetTrapBB(IRB), OldBB); + BranchInst::Create(TrapBB, OldBB); return; } // Create the conditional branch. - BranchInst::Create(GetTrapBB(IRB), Cont, Or, OldBB); + BranchInst::Create(TrapBB, Cont, Or, OldBB); } static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI, @@ -229,3 +231,26 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager & return PreservedAnalyses::none(); } + +void BoundsCheckingPass::printPipeline( + raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { + static_cast<PassInfoMixin<BoundsCheckingPass> *>(this)->printPipeline( + OS, MapClassName2PassName); + switch (Mode) { + case ReportingMode::Trap: + OS << "<trap>"; + break; + case ReportingMode::MinRuntime: + OS << "<min-rt>"; + break; + case ReportingMode::MinRuntimeAbort: + OS << "<min-rt-abort>"; + break; + case ReportingMode::FullRuntime: + OS << "<rt>"; + break; + case ReportingMode::FullRuntimeAbort: + OS << "<rt-abort>"; + break; + } +} \ No newline at end of file diff --git a/llvm/test/Instrumentation/BoundsChecking/runtimes.ll b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll new file mode 100644 index 00000000000000..fd27694c155d2b --- /dev/null +++ b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll @@ -0,0 +1,95 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s --check-prefixes=TR +; RUN: opt < %s -passes='bounds-checking<trap>' -S | FileCheck %s --check-prefixes=TR +; RUN: opt < %s -passes='bounds-checking<rt>' -S | FileCheck %s --check-prefixes=RT +; RUN: opt < %s -passes='bounds-checking<rt-abort>' -S | FileCheck %s --check-prefixes=RTABORT +; RUN: opt < %s -passes='bounds-checking<min-rt>' -S | FileCheck %s --check-prefixes=MINRT +; RUN: opt < %s -passes='bounds-checking<min-rt-abort>' -S | FileCheck %s --check-prefixes=MINRTABORT + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" + +define void @f1(i64 %x) nounwind { +; TR-LABEL: define void @f1( +; TR-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; TR-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; TR-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; TR-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; TR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; TR-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; TR-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; TR-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; TR: [[BB7]]: +; TR-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; TR-NEXT: ret void +; TR: [[TRAP]]: +; TR-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]] +; TR-NEXT: unreachable +; +; RT-LABEL: define void @f1( +; RT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; RT-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; RT-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; RT-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; RT-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; RT-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; RT-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; RT-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; RT: [[BB7]]: +; RT-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; RT-NEXT: ret void +; RT: [[TRAP]]: +; RT-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]] +; RT-NEXT: unreachable +; +; RTABORT-LABEL: define void @f1( +; RTABORT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; RTABORT-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; RTABORT-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; RTABORT-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; RTABORT-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; RTABORT-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; RTABORT-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; RTABORT-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; RTABORT: [[BB7]]: +; RTABORT-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; RTABORT-NEXT: ret void +; RTABORT: [[TRAP]]: +; RTABORT-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]] +; RTABORT-NEXT: unreachable +; +; MINRT-LABEL: define void @f1( +; MINRT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; MINRT-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; MINRT-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; MINRT-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; MINRT-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; MINRT-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; MINRT-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; MINRT-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; MINRT: [[BB7]]: +; MINRT-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; MINRT-NEXT: ret void +; MINRT: [[TRAP]]: +; MINRT-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]] +; MINRT-NEXT: unreachable +; +; MINRTABORT-LABEL: define void @f1( +; MINRTABORT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; MINRTABORT-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; MINRTABORT-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; MINRTABORT-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; MINRTABORT-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; MINRTABORT-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; MINRTABORT-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; MINRTABORT-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; MINRTABORT: [[BB7]]: +; MINRTABORT-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; MINRTABORT-NEXT: ret void +; MINRTABORT: [[TRAP]]: +; MINRTABORT-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]] +; MINRTABORT-NEXT: unreachable +; + %1 = alloca i128, i64 %x + %3 = load i128, ptr %1, align 4 + ret void +} >From 0c12eaff9f2e4c175268d8f021825b115b2771ec Mon Sep 17 00:00:00 2001 From: Vitaly Buka <vitalyb...@google.com> Date: Wed, 18 Dec 2024 15:18:04 -0800 Subject: [PATCH 2/2] rebase Created using spr 1.3.4 --- compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp | 2 +- compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp b/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp index 92e9e62dbc8698..edfe439c92790d 100644 --- a/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp +++ b/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp @@ -19,7 +19,7 @@ __attribute__((noinline, no_sanitize("memory"))) int test(char i) { init(&a); S b; init(&b); - return ((int*)(&a))[i]; + return ((int *)(&a))[i]; } int main(int argc, char **argv) { diff --git a/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp b/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp index 92e9e62dbc8698..edfe439c92790d 100644 --- a/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp +++ b/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp @@ -19,7 +19,7 @@ __attribute__((noinline, no_sanitize("memory"))) int test(char i) { init(&a); S b; init(&b); - return ((int*)(&a))[i]; + return ((int *)(&a))[i]; } int main(int argc, char **argv) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits