https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/120682
>From ee51ed7bd68df7b2dae3f1426471b34d0388a42f Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Fri, 20 Dec 2024 04:11:36 +0000 Subject: [PATCH 1/5] Remove -bounds-checking-unique-traps (replace with -fno-sanitize-merge=local-bounds) -fno-sanitize-merge (introduced in #120511) combines the functionality of -ubsan-unique-traps and -bounds-checking-unique-traps, while allowing fine-grained control of which UBSan checks to prevent merging. #120613 removed -ubsan-unique-traps. This patch removes -bound-checking-unique-traps, which can be controlled via -fno-sanitize-merge=local-bounds. Note: this patch subtly changes -fsanitize-merge (the default) to also include -fsanitize-merge=local-bounds. This is different from the previous behavior, where -fsanitize-merge (or the old -ubsan-unique-traps) did not affect local-bounds (requiring the separate -bounds-checking-unique-traps). However, we argue that the new behavior is more intuitive. Removing -bounds-checking-unique-traps and merging its functionality into -fsanitize-merge breaks backwards compatibility; we hope that this is acceptable since '-mllvm -bounds-checking-unique-traps' was an experimental flag. --- clang/docs/ReleaseNotes.rst | 14 ++- clang/lib/CodeGen/BackendUtil.cpp | 5 +- clang/test/CodeGen/bounds-checking.c | 14 ++- .../Instrumentation/BoundsChecking.h | 15 ++- llvm/lib/Passes/PassBuilder.cpp | 29 +++-- llvm/lib/Passes/PassRegistry.def | 4 +- .../Instrumentation/BoundsChecking.cpp | 24 ++-- .../BoundsChecking/runtimes.ll | 107 ++++++++++++++++++ .../BoundsChecking/ubsan-unique-traps.ll | 5 +- 9 files changed, 178 insertions(+), 39 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b8d92a6c881c68..0c6c894e17416a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -445,9 +445,10 @@ New Compiler Flags - The ``-Warray-compare-cxx26`` warning has been added to warn about array comparison starting from C++26, this warning is enabled as an error by default. -- '-fsanitize-merge' (default) and '-fno-sanitize-merge' have been added for - fine-grained control of which UBSan checks are allowed to be merged by the - backend (for example, -fno-sanitize-merge=bool,enum). +- ``-fsanitize-merge`` (default) and ``-fno-sanitize-merge`` have been added for + fine-grained, unified control of which UBSan checks can potentially be merged + by the compiler (for example, + ``-fno-sanitize-merge=bool,enum,array-bounds,local-bounds``). Deprecated Compiler Flags ------------------------- @@ -488,8 +489,11 @@ Removed Compiler Flags derivatives) is now removed, since it's no longer possible to suppress the diagnostic (see above). Users can expect an `unknown warning` diagnostic if it's still in use. -- The experimental flag '-ubsan-unique-traps' has been removed. It is - superseded by '-fno-sanitize-merge'. +- The experimental flags '-ubsan-unique-traps' and + '-bounds-checking-unique-traps' have been removed. The combination of the + two flags is equivalent to '-fno-sanitize-merge' with no parameters. + '-bounds-checking-unique-traps' can be selectively controlled via + '-f(no-)sanitize-merge=local-bounds'. Attribute Changes in Clang -------------------------- diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index e6c9d77d29f6f1..bfb73aa51b9b5b 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1030,6 +1030,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline( PB.registerScalarOptimizerLateEPCallback( [this](FunctionPassManager &FPM, OptimizationLevel Level) { BoundsCheckingPass::ReportingMode Mode; + bool Merge = CodeGenOpts.SanitizeMergeHandlers.has(SanitizerKind::LocalBounds); + if (CodeGenOpts.SanitizeTrap.has(SanitizerKind::LocalBounds)) { Mode = BoundsCheckingPass::ReportingMode::Trap; } else if (CodeGenOpts.SanitizeMinimalRuntime) { @@ -1041,7 +1043,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline( ? BoundsCheckingPass::ReportingMode::FullRuntime : BoundsCheckingPass::ReportingMode::FullRuntimeAbort; } - FPM.addPass(BoundsCheckingPass(Mode)); + BoundsCheckingPass::BoundsCheckingOptions Options(Mode, Merge); + FPM.addPass(BoundsCheckingPass(Options)); }); // Don't add sanitizers if we are here from ThinLTO PostLink. That already diff --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c index f9319ca61670c3..5e6b317a99969e 100644 --- a/clang/test/CodeGen/bounds-checking.c +++ b/clang/test/CodeGen/bounds-checking.c @@ -1,12 +1,14 @@ -// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s -// RUN: %clang_cc1 -fsanitize=array-bounds -O -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s +// N.B. The clang driver defaults to -fsanitize-merge but clang_cc1 effectively +// defaults to -fno-sanitize-merge. // RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s +// RUN: %clang_cc1 -fsanitize=array-bounds -O -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s // -// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -O3 -mllvm -bounds-checking-unique-traps -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTLOCAL -// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s --check-prefixes=NOOPTLOCAL +// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s +// +// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTLOCAL +// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -fno-sanitize-merge -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTLOCAL +// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -fsanitize-merge=local-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s --check-prefixes=NOOPTLOCAL // -// N.B. The clang driver defaults to -fsanitize-merge but clang_cc1 effectively -// defaults to -fno-sanitize-merge. // RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTARRAY // RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -fno-sanitize-merge -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTARRAY // RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -fsanitize-merge=array-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s --check-prefixes=NOOPTARRAY diff --git a/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h b/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h index 1876e5b72e8c99..eca93d89838134 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h +++ b/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h @@ -17,6 +17,7 @@ class Function; /// A pass to instrument code and perform run-time bounds checking on loads, /// stores, and other memory intrinsics. class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> { + public: enum class ReportingMode { Trap, @@ -26,15 +27,21 @@ class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> { FullRuntimeAbort, }; -private: - ReportingMode Mode = ReportingMode::Trap; + struct BoundsCheckingOptions { + BoundsCheckingOptions(ReportingMode Mode, bool Merge); -public: - BoundsCheckingPass(ReportingMode Mode) : Mode(Mode) {} + ReportingMode Mode; + bool Merge; + }; + + BoundsCheckingPass(BoundsCheckingOptions Options) : Options(Options) {} PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); static bool isRequired() { return true; } void printPipeline(raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName); + + private: + BoundsCheckingOptions Options; }; } // end namespace llvm diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index d70ac48f251180..87756acf724261 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -1281,23 +1281,34 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) { return Opts; } -Expected<BoundsCheckingPass::ReportingMode> +Expected<BoundsCheckingPass::BoundsCheckingOptions> parseBoundsCheckingOptions(StringRef Params) { - BoundsCheckingPass::ReportingMode Mode = - BoundsCheckingPass::ReportingMode::Trap; + BoundsCheckingPass::BoundsCheckingOptions Options (BoundsCheckingPass::ReportingMode::Trap, true); while (!Params.empty()) { StringRef ParamName; std::tie(ParamName, Params) = Params.split(';'); if (ParamName == "trap") { - Mode = BoundsCheckingPass::ReportingMode::Trap; + Options.Mode = BoundsCheckingPass::ReportingMode::Trap; } else if (ParamName == "rt") { - Mode = BoundsCheckingPass::ReportingMode::FullRuntime; + Options.Mode = BoundsCheckingPass::ReportingMode::FullRuntime; } else if (ParamName == "rt-abort") { - Mode = BoundsCheckingPass::ReportingMode::FullRuntimeAbort; + Options.Mode = BoundsCheckingPass::ReportingMode::FullRuntimeAbort; } else if (ParamName == "min-rt") { - Mode = BoundsCheckingPass::ReportingMode::MinRuntime; + Options.Mode = BoundsCheckingPass::ReportingMode::MinRuntime; } else if (ParamName == "min-rt-abort") { - Mode = BoundsCheckingPass::ReportingMode::MinRuntimeAbort; + Options.Mode = BoundsCheckingPass::ReportingMode::MinRuntimeAbort; + } else if (ParamName.consume_front("merge=")) { + if (ParamName == "true") + Options.Merge = true; + else if (ParamName == "false") + Options.Merge = false; + else { + return make_error<StringError>( + formatv("invalid BoundsChecking pass merge parameter: '{0}' ", + ParamName) + .str(), + inconvertibleErrorCode()); + } } else { return make_error<StringError>( formatv("invalid BoundsChecking pass parameter '{0}' ", ParamName) @@ -1305,7 +1316,7 @@ parseBoundsCheckingOptions(StringRef Params) { inconvertibleErrorCode()); } } - return Mode; + return Options; } } // namespace diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index ba3adcb0e317c0..9f0b09278edcca 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -624,8 +624,8 @@ FUNCTION_PASS_WITH_PARAMS( parseWinEHPrepareOptions, "demote-catchswitch-only") FUNCTION_PASS_WITH_PARAMS( "bounds-checking", "BoundsCheckingPass", - [](BoundsCheckingPass::ReportingMode Mode) { - return BoundsCheckingPass(Mode); + [](BoundsCheckingPass::BoundsCheckingOptions Options) { + return BoundsCheckingPass(Options); }, parseBoundsCheckingOptions, "trap") #undef FUNCTION_PASS_WITH_PARAMS diff --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp index f639d0628d6053..5ce3e0de59c559 100644 --- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -37,15 +37,15 @@ using namespace llvm; static cl::opt<bool> SingleTrapBB("bounds-checking-single-trap", cl::desc("Use one trap block per function")); -static cl::opt<bool> DebugTrapBB("bounds-checking-unique-traps", - cl::desc("Always use one trap per check")); - STATISTIC(ChecksAdded, "Bounds checks added"); STATISTIC(ChecksSkipped, "Bounds checks skipped"); STATISTIC(ChecksUnable, "Bounds checks unable to add"); using BuilderTy = IRBuilder<TargetFolder>; +BoundsCheckingPass::BoundsCheckingOptions::BoundsCheckingOptions(ReportingMode Mode, bool Merge) + : Mode(Mode), Merge(Merge) {} + /// Gets the conditions under which memory accessing instructions will overflow. /// /// \p Ptr is the pointer that will be read/written, and \p InstVal is either @@ -105,7 +105,7 @@ static Value *getBoundsCheckCond(Value *Ptr, Value *InstVal, return Or; } -static CallInst *InsertTrap(BuilderTy &IRB) { +static CallInst *InsertTrap(BuilderTy &IRB, bool DebugTrapBB) { if (!DebugTrapBB) return IRB.CreateIntrinsic(Intrinsic::trap, {}, {}); // FIXME: Ideally we would use the SanitizerHandler::OutOfBounds constant. @@ -169,9 +169,10 @@ struct ReportingOpts { bool MayReturn = false; bool UseTrap = false; bool MinRuntime = false; + bool MayMerge = true; StringRef Name; - ReportingOpts(BoundsCheckingPass::ReportingMode Mode) { + ReportingOpts(BoundsCheckingPass::ReportingMode Mode, bool Merge) { switch (Mode) { case BoundsCheckingPass::ReportingMode::Trap: UseTrap = true; @@ -193,6 +194,8 @@ struct ReportingOpts { Name = "__ubsan_handle_local_out_of_bounds_abort"; break; } + + MayMerge = Merge; } }; @@ -253,13 +256,12 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI, BasicBlock *TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn); IRB.SetInsertPoint(TrapBB); + bool DebugTrapBB = !Opts.MayMerge; CallInst *TrapCall = Opts.UseTrap - ? InsertTrap(IRB) + ? InsertTrap(IRB, DebugTrapBB) : InsertCall(IRB, Opts.MayReturn, Opts.Name); - if (DebugTrapBB) { - // FIXME: Pass option form clang. + if (DebugTrapBB) TrapCall->addFnAttr(llvm::Attribute::NoMerge); - } TrapCall->setDoesNotThrow(); TrapCall->setDebugLoc(DebugLoc); @@ -289,7 +291,7 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager & auto &TLI = AM.getResult<TargetLibraryAnalysis>(F); auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F); - if (!addBoundsChecking(F, TLI, SE, ReportingOpts(Mode))) + if (!addBoundsChecking(F, TLI, SE, ReportingOpts(Options.Mode, Options.Merge))) return PreservedAnalyses::all(); return PreservedAnalyses::none(); @@ -299,7 +301,7 @@ void BoundsCheckingPass::printPipeline( raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { static_cast<PassInfoMixin<BoundsCheckingPass> *>(this)->printPipeline( OS, MapClassName2PassName); - switch (Mode) { + switch (Options.Mode) { case ReportingMode::Trap: OS << "<trap>"; break; diff --git a/llvm/test/Instrumentation/BoundsChecking/runtimes.ll b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll index 357f92aca85c08..8726606665d7ca 100644 --- a/llvm/test/Instrumentation/BoundsChecking/runtimes.ll +++ b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll @@ -5,6 +5,21 @@ ; 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 +; +; merge defaults to true +; RUN: opt < %s -passes='bounds-checking<merge=true>' -S | FileCheck %s --check-prefixes=TR +; RUN: opt < %s -passes='bounds-checking<trap;merge=true>' -S | FileCheck %s --check-prefixes=TR +; RUN: opt < %s -passes='bounds-checking<rt;merge=true>' -S | FileCheck %s --check-prefixes=RT +; RUN: opt < %s -passes='bounds-checking<rt-abort;merge=true>' -S | FileCheck %s --check-prefixes=RTABORT +; RUN: opt < %s -passes='bounds-checking<min-rt;merge=true>' -S | FileCheck %s --check-prefixes=MINRT +; RUN: opt < %s -passes='bounds-checking<min-rt-abort;merge=true>' -S | FileCheck %s --check-prefixes=MINRTABORT +; +; RUN: opt < %s -passes='bounds-checking<merge=false>' -S | FileCheck %s --check-prefixes=TR-NOMERGE +; RUN: opt < %s -passes='bounds-checking<trap;merge=false>' -S | FileCheck %s --check-prefixes=TR-NOMERGE +; RUN: opt < %s -passes='bounds-checking<rt;merge=false>' -S | FileCheck %s --check-prefixes=RT-NOMERGE +; RUN: opt < %s -passes='bounds-checking<rt-abort;merge=false>' -S | FileCheck %s --check-prefixes=RTABORT-NOMERGE +; RUN: opt < %s -passes='bounds-checking<min-rt;merge=false>' -S | FileCheck %s --check-prefixes=MINRT-NOMERGE +; RUN: opt < %s -passes='bounds-checking<min-rt-abort;merge=false>' -S | FileCheck %s --check-prefixes=MINRTABORT-NOMERGE 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" @@ -88,8 +103,100 @@ define void @f1(i64 %x) nounwind { ; MINRTABORT: [[TRAP]]: ; MINRTABORT-NEXT: call void @__ubsan_handle_local_out_of_bounds_minimal_abort() #[[ATTR1:[0-9]+]] ; MINRTABORT-NEXT: unreachable +; +; TR-NOMERGE-LABEL: define void @f1( +; TR-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; TR-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; TR-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; TR-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; TR-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; TR-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; TR-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; TR-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; TR-NOMERGE: [[BB7]]: +; TR-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; TR-NOMERGE-NEXT: ret void +; TR-NOMERGE: [[TRAP]]: +; TR-NOMERGE-NEXT: call void @llvm.ubsantrap(i8 3) #[[ATTR2:[0-9]+]] +; TR-NOMERGE-NEXT: unreachable +; +; RT-NOMERGE-LABEL: define void @f1( +; RT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; RT-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; RT-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; RT-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; RT-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; RT-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; RT-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; RT-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; RT-NOMERGE: [[BB7]]: +; RT-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; RT-NOMERGE-NEXT: ret void +; RT-NOMERGE: [[TRAP]]: +; RT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR1:[0-9]+]] +; RT-NOMERGE-NEXT: br label %[[BB7]] +; +; RTABORT-NOMERGE-LABEL: define void @f1( +; RTABORT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; RTABORT-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; RTABORT-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; RTABORT-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; RTABORT-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; RTABORT-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; RTABORT-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; RTABORT-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; RTABORT-NOMERGE: [[BB7]]: +; RTABORT-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; RTABORT-NOMERGE-NEXT: ret void +; RTABORT-NOMERGE: [[TRAP]]: +; RTABORT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR2:[0-9]+]] +; RTABORT-NOMERGE-NEXT: unreachable +; +; MINRT-NOMERGE-LABEL: define void @f1( +; MINRT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; MINRT-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; MINRT-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; MINRT-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; MINRT-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; MINRT-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; MINRT-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; MINRT-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; MINRT-NOMERGE: [[BB7]]: +; MINRT-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; MINRT-NOMERGE-NEXT: ret void +; MINRT-NOMERGE: [[TRAP]]: +; MINRT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds_minimal() #[[ATTR1:[0-9]+]] +; MINRT-NOMERGE-NEXT: br label %[[BB7]] +; +; MINRTABORT-NOMERGE-LABEL: define void @f1( +; MINRTABORT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +; MINRTABORT-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] +; MINRTABORT-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8 +; MINRTABORT-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0 +; MINRTABORT-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16 +; MINRTABORT-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]] +; MINRTABORT-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]] +; MINRTABORT-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]] +; MINRTABORT-NOMERGE: [[BB7]]: +; MINRTABORT-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4 +; MINRTABORT-NOMERGE-NEXT: ret void +; MINRTABORT-NOMERGE: [[TRAP]]: +; MINRTABORT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds_minimal_abort() #[[ATTR2:[0-9]+]] +; MINRTABORT-NOMERGE-NEXT: unreachable ; %1 = alloca i128, i64 %x %3 = load i128, ptr %1, align 4 ret void } + +; TR: attributes #[[ATTR2]] = { noreturn nounwind } +; RT: attributes #[[ATTR0]] = { nounwind } +; RTABORT: attributes #[[ATTR1]] = { noreturn nounwind } +; MINRT: attributes #[[ATTR0]] = { nounwind } +; MINRTABORT: attributes #[[ATTR1]] = { noreturn nounwind } + +; TR-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind } +; RT-NOMERGE: attributes #[[ATTR1]] = { nomerge nounwind } +; RTABORT-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind } +; MINRT-NOMERGE: attributes #[[ATTR1]] = { nomerge nounwind } +; MINRTABORT-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind } diff --git a/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll b/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll index a3f34007e9b09f..a79db52905e824 100644 --- a/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll +++ b/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll @@ -1,5 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=bounds-checking -bounds-checking-unique-traps -S | FileCheck %s +; RUN: opt < %s -passes='bounds-checking<merge=false>' -S | FileCheck %s +; RUN: opt < %s -passes='bounds-checking<merge=true>' -S | not FileCheck %s +; RUN: opt < %s -passes=bounds-checking -S | not FileCheck %s + target datalayout = "e-p:64:64:64-p1:16:16:16-p2:64:64:64:48-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" declare noalias ptr @malloc(i64) nounwind allocsize(0) >From 77a3e495adaa4ff98c0a8c8b62dddbf1788705f9 Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Fri, 20 Dec 2024 04:26:09 +0000 Subject: [PATCH 2/5] clang-format --- clang/lib/CodeGen/BackendUtil.cpp | 3 ++- .../llvm/Transforms/Instrumentation/BoundsChecking.h | 4 ++-- llvm/lib/Passes/PassBuilder.cpp | 3 ++- llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp | 6 ++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index bfb73aa51b9b5b..04358cd6d7c232 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1030,7 +1030,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline( PB.registerScalarOptimizerLateEPCallback( [this](FunctionPassManager &FPM, OptimizationLevel Level) { BoundsCheckingPass::ReportingMode Mode; - bool Merge = CodeGenOpts.SanitizeMergeHandlers.has(SanitizerKind::LocalBounds); + bool Merge = CodeGenOpts.SanitizeMergeHandlers.has( + SanitizerKind::LocalBounds); if (CodeGenOpts.SanitizeTrap.has(SanitizerKind::LocalBounds)) { Mode = BoundsCheckingPass::ReportingMode::Trap; diff --git a/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h b/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h index eca93d89838134..ee71aa64f85eed 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h +++ b/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h @@ -40,8 +40,8 @@ class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> { void printPipeline(raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName); - private: - BoundsCheckingOptions Options; +private: + BoundsCheckingOptions Options; }; } // end namespace llvm diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 87756acf724261..797915236ddbdb 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -1283,7 +1283,8 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) { Expected<BoundsCheckingPass::BoundsCheckingOptions> parseBoundsCheckingOptions(StringRef Params) { - BoundsCheckingPass::BoundsCheckingOptions Options (BoundsCheckingPass::ReportingMode::Trap, true); + BoundsCheckingPass::BoundsCheckingOptions Options( + BoundsCheckingPass::ReportingMode::Trap, true); while (!Params.empty()) { StringRef ParamName; std::tie(ParamName, Params) = Params.split(';'); diff --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp index 5ce3e0de59c559..4dc8f60d714bc1 100644 --- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -43,7 +43,8 @@ STATISTIC(ChecksUnable, "Bounds checks unable to add"); using BuilderTy = IRBuilder<TargetFolder>; -BoundsCheckingPass::BoundsCheckingOptions::BoundsCheckingOptions(ReportingMode Mode, bool Merge) +BoundsCheckingPass::BoundsCheckingOptions::BoundsCheckingOptions( + ReportingMode Mode, bool Merge) : Mode(Mode), Merge(Merge) {} /// Gets the conditions under which memory accessing instructions will overflow. @@ -291,7 +292,8 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager & auto &TLI = AM.getResult<TargetLibraryAnalysis>(F); auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F); - if (!addBoundsChecking(F, TLI, SE, ReportingOpts(Options.Mode, Options.Merge))) + if (!addBoundsChecking(F, TLI, SE, + ReportingOpts(Options.Mode, Options.Merge))) return PreservedAnalyses::all(); return PreservedAnalyses::none(); >From 94c8083d0e040c78fa671527b9e99e19c87735ce Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Fri, 20 Dec 2024 05:29:31 +0000 Subject: [PATCH 3/5] Address Vitaly's feedback --- clang/docs/ReleaseNotes.rst | 15 ++-- llvm/lib/Passes/PassBuilder.cpp | 16 +--- .../Instrumentation/BoundsChecking.cpp | 13 +-- .../BoundsChecking/runtimes.ll | 85 +++---------------- 4 files changed, 27 insertions(+), 102 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0c6c894e17416a..341c7682155fa0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -445,11 +445,6 @@ New Compiler Flags - The ``-Warray-compare-cxx26`` warning has been added to warn about array comparison starting from C++26, this warning is enabled as an error by default. -- ``-fsanitize-merge`` (default) and ``-fno-sanitize-merge`` have been added for - fine-grained, unified control of which UBSan checks can potentially be merged - by the compiler (for example, - ``-fno-sanitize-merge=bool,enum,array-bounds,local-bounds``). - Deprecated Compiler Flags ------------------------- @@ -489,11 +484,6 @@ Removed Compiler Flags derivatives) is now removed, since it's no longer possible to suppress the diagnostic (see above). Users can expect an `unknown warning` diagnostic if it's still in use. -- The experimental flags '-ubsan-unique-traps' and - '-bounds-checking-unique-traps' have been removed. The combination of the - two flags is equivalent to '-fno-sanitize-merge' with no parameters. - '-bounds-checking-unique-traps' can be selectively controlled via - '-f(no-)sanitize-merge=local-bounds'. Attribute Changes in Clang -------------------------- @@ -1212,6 +1202,11 @@ Sanitizers - Implemented ``-f[no-]sanitize-trap=local-bounds``, and ``-f[no-]sanitize-recover=local-bounds``. +- ``-fsanitize-merge`` (default) and ``-fno-sanitize-merge`` have been added for + fine-grained, unified control of which UBSan checks can potentially be merged + by the compiler (for example, + ``-fno-sanitize-merge=bool,enum,array-bounds,local-bounds``). + Python Binding Changes ---------------------- - Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``. diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 797915236ddbdb..a936f5381137c6 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -1284,7 +1284,7 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) { Expected<BoundsCheckingPass::BoundsCheckingOptions> parseBoundsCheckingOptions(StringRef Params) { BoundsCheckingPass::BoundsCheckingOptions Options( - BoundsCheckingPass::ReportingMode::Trap, true); + BoundsCheckingPass::ReportingMode::Trap, false); while (!Params.empty()) { StringRef ParamName; std::tie(ParamName, Params) = Params.split(';'); @@ -1298,18 +1298,8 @@ parseBoundsCheckingOptions(StringRef Params) { Options.Mode = BoundsCheckingPass::ReportingMode::MinRuntime; } else if (ParamName == "min-rt-abort") { Options.Mode = BoundsCheckingPass::ReportingMode::MinRuntimeAbort; - } else if (ParamName.consume_front("merge=")) { - if (ParamName == "true") - Options.Merge = true; - else if (ParamName == "false") - Options.Merge = false; - else { - return make_error<StringError>( - formatv("invalid BoundsChecking pass merge parameter: '{0}' ", - ParamName) - .str(), - inconvertibleErrorCode()); - } + } else if (ParamName == "merge") { + Options.Merge = true; } else { return make_error<StringError>( formatv("invalid BoundsChecking pass parameter '{0}' ", ParamName) diff --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp index 4dc8f60d714bc1..41e50385812460 100644 --- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -305,19 +305,22 @@ void BoundsCheckingPass::printPipeline( OS, MapClassName2PassName); switch (Options.Mode) { case ReportingMode::Trap: - OS << "<trap>"; + OS << "<trap"; break; case ReportingMode::MinRuntime: - OS << "<min-rt>"; + OS << "<min-rt"; break; case ReportingMode::MinRuntimeAbort: - OS << "<min-rt-abort>"; + OS << "<min-rt-abort"; break; case ReportingMode::FullRuntime: - OS << "<rt>"; + OS << "<rt"; break; case ReportingMode::FullRuntimeAbort: - OS << "<rt-abort>"; + OS << "<rt-abort"; break; } + if (Options.Merge) + OS << ";merge"; + OS << ">"; } diff --git a/llvm/test/Instrumentation/BoundsChecking/runtimes.ll b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll index 8726606665d7ca..7b95a4092af77e 100644 --- a/llvm/test/Instrumentation/BoundsChecking/runtimes.ll +++ b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll @@ -1,25 +1,13 @@ ; 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 +; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s --check-prefixes=TR-NOMERGE +; RUN: opt < %s -passes='bounds-checking<trap>' -S | FileCheck %s --check-prefixes=TR-NOMERGE +; RUN: opt < %s -passes='bounds-checking<rt>' -S | FileCheck %s --check-prefixes=RT-NOMERGE +; RUN: opt < %s -passes='bounds-checking<rt-abort>' -S | FileCheck %s --check-prefixes=RTABORT-NOMERGE +; RUN: opt < %s -passes='bounds-checking<min-rt>' -S | FileCheck %s --check-prefixes=MINRT-NOMERGE +; RUN: opt < %s -passes='bounds-checking<min-rt-abort>' -S | FileCheck %s --check-prefixes=MINRTABORT-NOMERGE ; -; merge defaults to true -; RUN: opt < %s -passes='bounds-checking<merge=true>' -S | FileCheck %s --check-prefixes=TR -; RUN: opt < %s -passes='bounds-checking<trap;merge=true>' -S | FileCheck %s --check-prefixes=TR -; RUN: opt < %s -passes='bounds-checking<rt;merge=true>' -S | FileCheck %s --check-prefixes=RT -; RUN: opt < %s -passes='bounds-checking<rt-abort;merge=true>' -S | FileCheck %s --check-prefixes=RTABORT -; RUN: opt < %s -passes='bounds-checking<min-rt;merge=true>' -S | FileCheck %s --check-prefixes=MINRT -; RUN: opt < %s -passes='bounds-checking<min-rt-abort;merge=true>' -S | FileCheck %s --check-prefixes=MINRTABORT -; -; RUN: opt < %s -passes='bounds-checking<merge=false>' -S | FileCheck %s --check-prefixes=TR-NOMERGE -; RUN: opt < %s -passes='bounds-checking<trap;merge=false>' -S | FileCheck %s --check-prefixes=TR-NOMERGE -; RUN: opt < %s -passes='bounds-checking<rt;merge=false>' -S | FileCheck %s --check-prefixes=RT-NOMERGE -; RUN: opt < %s -passes='bounds-checking<rt-abort;merge=false>' -S | FileCheck %s --check-prefixes=RTABORT-NOMERGE -; RUN: opt < %s -passes='bounds-checking<min-rt;merge=false>' -S | FileCheck %s --check-prefixes=MINRT-NOMERGE -; RUN: opt < %s -passes='bounds-checking<min-rt-abort;merge=false>' -S | FileCheck %s --check-prefixes=MINRTABORT-NOMERGE +; RUN: opt < %s -passes='bounds-checking<trap;merge>' -S | FileCheck %s --check-prefixes=TR +; RUN: opt < %s -passes='bounds-checking<rt;merge>' -S | FileCheck %s --check-prefixes=RT 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" @@ -56,54 +44,6 @@ define void @f1(i64 %x) nounwind { ; RT-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR0]] ; RT-NEXT: br label %[[BB7]] ; -; 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 @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR1:[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 @__ubsan_handle_local_out_of_bounds_minimal() #[[ATTR0]] -; MINRT-NEXT: br label %[[BB7]] -; -; 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 @__ubsan_handle_local_out_of_bounds_minimal_abort() #[[ATTR1:[0-9]+]] -; MINRTABORT-NEXT: unreachable -; ; TR-NOMERGE-LABEL: define void @f1( ; TR-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] { ; TR-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]] @@ -189,14 +129,11 @@ define void @f1(i64 %x) nounwind { ret void } -; TR: attributes #[[ATTR2]] = { noreturn nounwind } -; RT: attributes #[[ATTR0]] = { nounwind } -; RTABORT: attributes #[[ATTR1]] = { noreturn nounwind } -; MINRT: attributes #[[ATTR0]] = { nounwind } -; MINRTABORT: attributes #[[ATTR1]] = { noreturn nounwind } - ; TR-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind } ; RT-NOMERGE: attributes #[[ATTR1]] = { nomerge nounwind } ; RTABORT-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind } ; MINRT-NOMERGE: attributes #[[ATTR1]] = { nomerge nounwind } ; MINRTABORT-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind } +; +; TR: attributes #[[ATTR2]] = { noreturn nounwind } +; RT: attributes #[[ATTR0]] = { nounwind } >From 5af3938dbe6b6df3a64af6dda1b61a7d954d5b99 Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Fri, 20 Dec 2024 05:53:10 +0000 Subject: [PATCH 4/5] Update tests to add merge flag --- llvm/test/Instrumentation/BoundsChecking/many-trap.ll | 4 ++-- llvm/test/Instrumentation/BoundsChecking/simple-32.ll | 2 +- llvm/test/Instrumentation/BoundsChecking/simple.ll | 2 +- .../Instrumentation/BoundsChecking/ubsan-unique-traps.ll | 5 ++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/llvm/test/Instrumentation/BoundsChecking/many-trap.ll b/llvm/test/Instrumentation/BoundsChecking/many-trap.ll index e9cde95cd09e59..4e157520dbafe3 100644 --- a/llvm/test/Instrumentation/BoundsChecking/many-trap.ll +++ b/llvm/test/Instrumentation/BoundsChecking/many-trap.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s -; RUN: opt < %s -passes=bounds-checking -bounds-checking-single-trap -S | FileCheck -check-prefix=SINGLE %s +; RUN: opt < %s -passes='bounds-checking<merge>' -S | FileCheck %s +; RUN: opt < %s -passes='bounds-checking<merge>' -bounds-checking-single-trap -S | FileCheck -check-prefix=SINGLE %s 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" ; CHECK: @f1 diff --git a/llvm/test/Instrumentation/BoundsChecking/simple-32.ll b/llvm/test/Instrumentation/BoundsChecking/simple-32.ll index b707adaca434ca..6f8d373d4c5966 100644 --- a/llvm/test/Instrumentation/BoundsChecking/simple-32.ll +++ b/llvm/test/Instrumentation/BoundsChecking/simple-32.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s +; RUN: opt < %s -passes='bounds-checking<merge>' -S | FileCheck %s target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" diff --git a/llvm/test/Instrumentation/BoundsChecking/simple.ll b/llvm/test/Instrumentation/BoundsChecking/simple.ll index 914cafdc57f9d3..ce2540cf49cccc 100644 --- a/llvm/test/Instrumentation/BoundsChecking/simple.ll +++ b/llvm/test/Instrumentation/BoundsChecking/simple.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s +; RUN: opt < %s -passes='bounds-checking<merge>' -S | FileCheck %s target datalayout = "e-p:64:64:64-p1:16:16:16-p2:64:64:64:48-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" @.str = private constant [8 x i8] c"abcdefg\00" diff --git a/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll b/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll index a79db52905e824..5fdb9c78357e73 100644 --- a/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll +++ b/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll @@ -1,7 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes='bounds-checking<merge=false>' -S | FileCheck %s -; RUN: opt < %s -passes='bounds-checking<merge=true>' -S | not FileCheck %s -; RUN: opt < %s -passes=bounds-checking -S | not FileCheck %s +; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s +; RUN: opt < %s -passes='bounds-checking<merge>' -S | not FileCheck %s target datalayout = "e-p:64:64:64-p1:16:16:16-p2:64:64:64:48-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" >From 630c5a4200e372e2093af1bca1b300c9224a99db Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Fri, 20 Dec 2024 18:06:12 +0000 Subject: [PATCH 5/5] Mention -fno-sanitize-merge in https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#stack-traces-and-report-symbolization, per Vitaly's feedback --- clang/docs/UndefinedBehaviorSanitizer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst index 671db7f9f36714..b9ee4484fb9aec 100644 --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -276,8 +276,8 @@ Stack traces and report symbolization If you want UBSan to print symbolized stack trace for each error report, you will need to: -#. Compile with ``-g`` and ``-fno-omit-frame-pointer`` to get proper debug - information in your binary. +#. Compile with ``-g``, ``-fno-sanitize-merge`` and ``-fno-omit-frame-pointer`` + to get proper debug information in your binary. #. Run your program with environment variable ``UBSAN_OPTIONS=print_stacktrace=1``. #. Make sure ``llvm-symbolizer`` binary is in ``PATH``. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits