llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Vitaly Buka (vitalybuka) <details> <summary>Changes</summary> This check is a part of UBSAN, but does not support verbose output like other UBSAN checks. This is a step to fix that. --- Full diff: https://github.com/llvm/llvm-project/pull/119923.diff 6 Files Affected: - (modified) clang/lib/CodeGen/BackendUtil.cpp (+2-1) - (modified) llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h (+17-1) - (modified) llvm/lib/Passes/PassBuilder.cpp (+27) - (modified) llvm/lib/Passes/PassRegistry.def (+6-1) - (modified) llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp (+23) - (added) llvm/test/Instrumentation/BoundsChecking/runtimes.ll (+95) ``````````diff diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 8cf44592a17475..ae0e8b132aa356 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1020,7 +1020,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)); }); if (LangOpts.Sanitize.has(SanitizerKind::Realtime)) { diff --git a/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h b/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h index b1b1ece3eff5a0..29959acc29101a 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) {} 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 260a34f2e060d6..78df7eed10f31a 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -1286,6 +1286,33 @@ Expected<RealtimeSanitizerOptions> parseRtSanPassOptions(StringRef Params) { return Result; } +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 825f2f7f9a494a..c86ff0b5a042c2 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()) @@ -624,6 +623,12 @@ FUNCTION_PASS_WITH_PARAMS( "rtsan", "RealtimeSanitizerPass", [](RealtimeSanitizerOptions Opts) { return RealtimeSanitizerPass(Opts); }, parseRtSanPassOptions, "") +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..c86d967716a5a0 100644 --- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -229,3 +229,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 +} `````````` </details> https://github.com/llvm/llvm-project/pull/119923 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits