Skip to content

[ubsan] Add -fsanitize-merge (and -fno-sanitize-merge) #120464

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

Merged
merged 19 commits into from
Dec 18, 2024

Conversation

thurstond
Copy link
Contributor

@thurstond thurstond commented Dec 18, 2024

'-mllvm -ubsan-unique-traps' (#65972) applies to all UBSan checks. This patch introduces -fsanitize-merge (defaults to on, maintaining the status quo behavior) and -fno-sanitize-merge (equivalent to '-mllvm -ubsan-unique-traps'), with the option to selectively applying non-merged handlers to a subset of UBSan checks (e.g., -fno-sanitize-merge=bool,enum).

N.B. we do not use "trap" in the argument name since #119302 has generalized -ubsan-unique-traps to work for non-trap modes (min-rt and regular rt).

This patch does not remove the -ubsan-unique-traps flag; that will override -f(no-)sanitize-merge.

…d-handlers)

'-mllvm -ubsan-unique-traps' (llvm#65972) applies to all UBSan
checks. This patch introduces -fsanitize-nonmerged-handlers and
-fno-sanitize-nonmerged-handlers, which allows selectively applying
non-merged handlers to a subset of UBSan checks.

N.B. we use "non-merged handlers" instead of "unique traps", since
llvm#119302 has generalized it to
work for non-trap mode as well (min-rt and regular rt).

This patch does not remove the -ubsan-unique-traps flag; that will
override -f(no-)sanitize-non-merged-handlers.
Copy link

github-actions bot commented Dec 18, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@thurstond thurstond marked this pull request as ready for review December 18, 2024 19:12
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. labels Dec 18, 2024
@thurstond thurstond changed the title [ubsan] Add -fsanitize-nonmerged-handlers (and -fno-sanitize-nonmerge… [ubsan] Add -fsanitize-nonmerged-handlers (and -fno-sanitize-nonmerged-handlers) Dec 18, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 18, 2024

@llvm/pr-subscribers-clang-codegen

Author: Thurston Dang (thurstond)

Changes

'-mllvm -ubsan-unique-traps' (#65972) applies to all UBSan checks. This patch introduces -fsanitize-nonmerged-handlers and -fno-sanitize-nonmerged-handlers, which allows selectively applying non-merged handlers to a subset of UBSan checks.

N.B. we use "non-merged handlers" instead of "unique traps", since #119302 has generalized it to work for non-trap mode as well (min-rt and regular rt).

This patch does not remove the -ubsan-unique-traps flag; that will override -f(no-)sanitize-non-merged-handlers.


Full diff: https://github.com/llvm/llvm-project/pull/120464.diff

9 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.h (+4)
  • (modified) clang/include/clang/Driver/Options.td (+8)
  • (modified) clang/include/clang/Driver/SanitizerArgs.h (+1)
  • (modified) clang/lib/CodeGen/CGExpr.cpp (+17-13)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+2-1)
  • (modified) clang/lib/Driver/SanitizerArgs.cpp (+31-7)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+7)
  • (modified) clang/test/CodeGen/ubsan-trap-merge.c (+6-1)
  • (modified) clang/test/Driver/fsanitize.c (+5)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 2dcf98b465661e..9b97adce42cc2a 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -380,6 +380,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// Set of sanitizer checks that trap rather than diagnose.
   SanitizerSet SanitizeTrap;
 
+  /// Set of sanitizer checks that have non-merged handlers (better
+  /// debuggability at the expense of code size).
+  SanitizerSet SanitizeNonMergedHandlers;
+
   /// List of backend command-line options for -fembed-bitcode.
   std::vector<uint8_t> CmdArgs;
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 7b544d2534d469..e9fd59df3f9111 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2548,6 +2548,14 @@ def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Gro
 def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>,
                            Visibility<[ClangOption, CLOption]>,
                            HelpText<"Disable trapping for specified sanitizers">;
+def fsanitize_nonmerged_handlers_EQ
+    : CommaJoined<["-"], "fsanitize-nonmerged-handlers=">,
+      Group<f_clang_Group>,
+      HelpText<"Enable non-merged handlers for specified sanitizers">;
+def fno_sanitize_nonmerged_handlers_EQ
+    : CommaJoined<["-"], "fno-sanitize-nonmerged-handlers=">,
+      Group<f_clang_Group>,
+      HelpText<"Disable non-merged handlers for specified sanitizers">;
 def fsanitize_trap : Flag<["-"], "fsanitize-trap">, Group<f_clang_Group>,
                      Alias<fsanitize_trap_EQ>, AliasArgs<["all"]>,
                      HelpText<"Enable trapping for all sanitizers">;
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 4f08ea2b260179..28cfe72d6a34bd 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -25,6 +25,7 @@ class SanitizerArgs {
   SanitizerSet Sanitizers;
   SanitizerSet RecoverableSanitizers;
   SanitizerSet TrapSanitizers;
+  SanitizerSet NonMergedHandlers;
 
   std::vector<std::string> UserIgnorelistFiles;
   std::vector<std::string> SystemIgnorelistFiles;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 79955f55714164..9c0ddda2e28d9d 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3546,7 +3546,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
                                  ArrayRef<llvm::Value *> FnArgs,
                                  SanitizerHandler CheckHandler,
                                  CheckRecoverableKind RecoverKind, bool IsFatal,
-                                 llvm::BasicBlock *ContBB) {
+                                 llvm::BasicBlock *ContBB, bool NoMerge) {
   assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable);
   std::optional<ApplyDebugLocation> DL;
   if (!CGF.Builder.getCurrentDebugLocation()) {
@@ -3581,10 +3581,9 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
                                llvm::AttributeList::FunctionIndex, B),
       /*Local=*/true);
   llvm::CallInst *HandlerCall = CGF.EmitNounwindRuntimeCall(Fn, FnArgs);
-  bool NoMerge =
-      ClSanitizeDebugDeoptimization ||
-      !CGF.CGM.getCodeGenOpts().OptimizationLevel ||
-      (CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr<OptimizeNoneAttr>());
+  NoMerge = NoMerge || ClSanitizeDebugDeoptimization ||
+            !CGF.CGM.getCodeGenOpts().OptimizationLevel ||
+            (CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr<OptimizeNoneAttr>());
   if (NoMerge)
     HandlerCall->addFnAttr(llvm::Attribute::NoMerge);
   if (!MayReturn) {
@@ -3608,6 +3607,7 @@ void CodeGenFunction::EmitCheck(
   llvm::Value *FatalCond = nullptr;
   llvm::Value *RecoverableCond = nullptr;
   llvm::Value *TrapCond = nullptr;
+  bool NoMerge = false;
   for (int i = 0, n = Checked.size(); i < n; ++i) {
     llvm::Value *Check = Checked[i].first;
     // -fsanitize-trap= overrides -fsanitize-recover=.
@@ -3618,6 +3618,9 @@ void CodeGenFunction::EmitCheck(
                   ? RecoverableCond
                   : FatalCond;
     Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check;
+
+    if (CGM.getCodeGenOpts().SanitizeNonMergedHandlers.has(Checked[i].second))
+      NoMerge = true;
   }
 
   if (ClSanitizeGuardChecks) {
@@ -3632,7 +3635,7 @@ void CodeGenFunction::EmitCheck(
   }
 
   if (TrapCond)
-    EmitTrapCheck(TrapCond, CheckHandler);
+    EmitTrapCheck(TrapCond, CheckHandler, NoMerge);
   if (!FatalCond && !RecoverableCond)
     return;
 
@@ -3698,7 +3701,7 @@ void CodeGenFunction::EmitCheck(
     // Simple case: we need to generate a single handler call, either
     // fatal, or non-fatal.
     emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind,
-                         (FatalCond != nullptr), Cont);
+                         (FatalCond != nullptr), Cont, NoMerge);
   } else {
     // Emit two handler calls: first one for set of unrecoverable checks,
     // another one for recoverable.
@@ -3708,10 +3711,10 @@ void CodeGenFunction::EmitCheck(
     Builder.CreateCondBr(FatalCond, NonFatalHandlerBB, FatalHandlerBB);
     EmitBlock(FatalHandlerBB);
     emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, true,
-                         NonFatalHandlerBB);
+                         NonFatalHandlerBB, NoMerge);
     EmitBlock(NonFatalHandlerBB);
     emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, false,
-                         Cont);
+                         Cont, NoMerge);
   }
 
   EmitBlock(Cont);
@@ -3901,7 +3904,8 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {
 }
 
 void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
-                                    SanitizerHandler CheckHandlerID) {
+                                    SanitizerHandler CheckHandlerID,
+                                    bool NoMerge) {
   llvm::BasicBlock *Cont = createBasicBlock("cont");
 
   // If we're optimizing, collapse all calls to trap down to just one per
@@ -3911,9 +3915,9 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
 
   llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];
 
-  bool NoMerge = ClSanitizeDebugDeoptimization ||
-                 !CGM.getCodeGenOpts().OptimizationLevel ||
-                 (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
+  NoMerge = NoMerge || ClSanitizeDebugDeoptimization ||
+            !CGM.getCodeGenOpts().OptimizationLevel ||
+            (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
 
   if (TrapBB && !NoMerge) {
     auto Call = TrapBB->begin();
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 092d55355a0a17..99a2a44248d274 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -5166,7 +5166,8 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   /// Create a basic block that will call the trap intrinsic, and emit a
   /// conditional branch to it, for the -ftrapv checks.
-  void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID);
+  void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID,
+                     bool NoMerge = false);
 
   /// Emit a call to trap or debugtrap and attach function attribute
   /// "trap-func-name" if specified.
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 81f94f23873661..969d112e570474 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -68,6 +68,9 @@ static const SanitizerMask TrappingSupported =
     SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
     SanitizerKind::LocalBounds | SanitizerKind::CFI |
     SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
+static const SanitizerMask NonMergedDefault;
+static const SanitizerMask NonMergedSupported =
+    (SanitizerKind::Undefined & ~SanitizerKind::Vptr);
 static const SanitizerMask TrappingDefault = SanitizerKind::CFI;
 static const SanitizerMask CFIClasses =
     SanitizerKind::CFIVCall | SanitizerKind::CFINVCall |
@@ -696,6 +699,17 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
   TrappingKinds &= Kinds;
   RecoverableKinds &= ~TrappingKinds;
 
+  // Parse -f(no-)?sanitize-nonmerged-handlers flags
+  SanitizerMask AlwaysNonMerged; // Empty
+  SanitizerMask NeverNonMerged = ~(setGroupBits(NonMergedSupported));
+  SanitizerMask NonMergedKinds = parseSanitizeArgs(
+      D, Args, DiagnoseErrors, NonMergedDefault, AlwaysNonMerged,
+      NeverNonMerged, options::OPT_fsanitize_nonmerged_handlers_EQ,
+      options::OPT_fno_sanitize_nonmerged_handlers_EQ);
+  NonMergedKinds |= AlwaysNonMerged;
+  NonMergedKinds &= ~NeverNonMerged;
+  NonMergedKinds &= Kinds;
+
   // Setup ignorelist files.
   // Add default ignorelist from resource directory for activated sanitizers,
   // and validate special case lists format.
@@ -1113,6 +1127,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
   TrapSanitizers.Mask |= TrappingKinds;
   assert(!(RecoverableKinds & TrappingKinds) &&
          "Overlap between recoverable and trapping sanitizers");
+
+  NonMergedHandlers.Mask |= NonMergedKinds;
 }
 
 static std::string toString(const clang::SanitizerSet &Sanitizers) {
@@ -1274,6 +1290,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
     CmdArgs.push_back(
         Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
 
+  if (!NonMergedHandlers.empty())
+    CmdArgs.push_back(Args.MakeArgString("-fsanitize-nonmerged-handlers=" +
+                                         toString(NonMergedHandlers)));
+
   addSpecialCaseListOpt(Args, CmdArgs,
                         "-fsanitize-ignorelist=", UserIgnorelistFiles);
   addSpecialCaseListOpt(Args, CmdArgs,
@@ -1441,13 +1461,17 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
 
 SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
                              bool DiagnoseErrors) {
-  assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
-          A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
-          A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
-          A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
-          A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
-          A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
-         "Invalid argument in parseArgValues!");
+  assert(
+      (A->getOption().matches(options::OPT_fsanitize_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_trap_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_nonmerged_handlers_EQ) ||
+       A->getOption().matches(
+           options::OPT_fno_sanitize_nonmerged_handlers_EQ)) &&
+      "Invalid argument in parseArgValues!");
   SanitizerMask Kinds;
   for (int i = 0, n = A->getNumValues(); i != n; ++i) {
     const char *Value = A->getValue(i);
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 298fafc21588a1..7fa01292f532c0 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1792,6 +1792,10 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
   for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeTrap))
     GenerateArg(Consumer, OPT_fsanitize_trap_EQ, Sanitizer);
 
+  for (StringRef Sanitizer :
+       serializeSanitizerKinds(Opts.SanitizeNonMergedHandlers))
+    GenerateArg(Consumer, OPT_fsanitize_nonmerged_handlers_EQ, Sanitizer);
+
   if (!Opts.EmitVersionIdentMetadata)
     GenerateArg(Consumer, OPT_Qn);
 
@@ -2269,6 +2273,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   parseSanitizerKinds("-fsanitize-trap=",
                       Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags,
                       Opts.SanitizeTrap);
+  parseSanitizerKinds("-fsanitize-nonmerged-handlers=",
+                      Args.getAllArgValues(OPT_fsanitize_nonmerged_handlers_EQ),
+                      Diags, Opts.SanitizeNonMergedHandlers);
 
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c
index 412ec7b09744ef..3a5a551fa7afa6 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -1,11 +1,16 @@
 // NOTE: Assertions have mostly been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
 // The most important assertion is the attributes at the end of the file, which
-// shows whether -ubsan-unique-traps attaches 'nomerge' to each ubsan call.
+// shows whether -ubsan-unique-traps and -fsanitize-nonmerged-handlers attach
+// 'nomerge' to each ubsan call.
 //
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefix=TRAP
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o -                                         | FileCheck %s --check-prefix=HANDLER
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-minimal-runtime              | FileCheck %s --check-prefix=MINRT
 //
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow  %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefix=TRAP
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow  %s -o -                                         | FileCheck %s --check-prefix=HANDLER
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow  %s -o - -fsanitize-minimal-runtime              | FileCheck %s --check-prefix=MINRT
+//
 // REQUIRES: x86-registered-target
 
 // TRAP-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f(
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index bb692b2aeea1d3..2d34ae871b6f55 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -9,6 +9,11 @@
 // CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
 // CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
 
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-nonmerged-handlers=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NONMERGED
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-nonmerged-handlers=undefined -fno-sanitize-nonmerged-handlers=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NONMERGED2
+// CHECK-UNDEFINED-NONMERGED: "-fsanitize-nonmerged-handlers=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
+// CHECK-UNDEFINED-NONMERGED2: "-fsanitize-nonmerged-handlers=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
+
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
 // CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}}
 

@llvmbot
Copy link
Member

llvmbot commented Dec 18, 2024

@llvm/pr-subscribers-clang-driver

Author: Thurston Dang (thurstond)

Changes

'-mllvm -ubsan-unique-traps' (#65972) applies to all UBSan checks. This patch introduces -fsanitize-nonmerged-handlers and -fno-sanitize-nonmerged-handlers, which allows selectively applying non-merged handlers to a subset of UBSan checks.

N.B. we use "non-merged handlers" instead of "unique traps", since #119302 has generalized it to work for non-trap mode as well (min-rt and regular rt).

This patch does not remove the -ubsan-unique-traps flag; that will override -f(no-)sanitize-non-merged-handlers.


Full diff: https://github.com/llvm/llvm-project/pull/120464.diff

9 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.h (+4)
  • (modified) clang/include/clang/Driver/Options.td (+8)
  • (modified) clang/include/clang/Driver/SanitizerArgs.h (+1)
  • (modified) clang/lib/CodeGen/CGExpr.cpp (+17-13)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+2-1)
  • (modified) clang/lib/Driver/SanitizerArgs.cpp (+31-7)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+7)
  • (modified) clang/test/CodeGen/ubsan-trap-merge.c (+6-1)
  • (modified) clang/test/Driver/fsanitize.c (+5)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 2dcf98b465661e..9b97adce42cc2a 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -380,6 +380,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// Set of sanitizer checks that trap rather than diagnose.
   SanitizerSet SanitizeTrap;
 
+  /// Set of sanitizer checks that have non-merged handlers (better
+  /// debuggability at the expense of code size).
+  SanitizerSet SanitizeNonMergedHandlers;
+
   /// List of backend command-line options for -fembed-bitcode.
   std::vector<uint8_t> CmdArgs;
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 7b544d2534d469..e9fd59df3f9111 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2548,6 +2548,14 @@ def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Gro
 def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>,
                            Visibility<[ClangOption, CLOption]>,
                            HelpText<"Disable trapping for specified sanitizers">;
+def fsanitize_nonmerged_handlers_EQ
+    : CommaJoined<["-"], "fsanitize-nonmerged-handlers=">,
+      Group<f_clang_Group>,
+      HelpText<"Enable non-merged handlers for specified sanitizers">;
+def fno_sanitize_nonmerged_handlers_EQ
+    : CommaJoined<["-"], "fno-sanitize-nonmerged-handlers=">,
+      Group<f_clang_Group>,
+      HelpText<"Disable non-merged handlers for specified sanitizers">;
 def fsanitize_trap : Flag<["-"], "fsanitize-trap">, Group<f_clang_Group>,
                      Alias<fsanitize_trap_EQ>, AliasArgs<["all"]>,
                      HelpText<"Enable trapping for all sanitizers">;
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 4f08ea2b260179..28cfe72d6a34bd 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -25,6 +25,7 @@ class SanitizerArgs {
   SanitizerSet Sanitizers;
   SanitizerSet RecoverableSanitizers;
   SanitizerSet TrapSanitizers;
+  SanitizerSet NonMergedHandlers;
 
   std::vector<std::string> UserIgnorelistFiles;
   std::vector<std::string> SystemIgnorelistFiles;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 79955f55714164..9c0ddda2e28d9d 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3546,7 +3546,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
                                  ArrayRef<llvm::Value *> FnArgs,
                                  SanitizerHandler CheckHandler,
                                  CheckRecoverableKind RecoverKind, bool IsFatal,
-                                 llvm::BasicBlock *ContBB) {
+                                 llvm::BasicBlock *ContBB, bool NoMerge) {
   assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable);
   std::optional<ApplyDebugLocation> DL;
   if (!CGF.Builder.getCurrentDebugLocation()) {
@@ -3581,10 +3581,9 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
                                llvm::AttributeList::FunctionIndex, B),
       /*Local=*/true);
   llvm::CallInst *HandlerCall = CGF.EmitNounwindRuntimeCall(Fn, FnArgs);
-  bool NoMerge =
-      ClSanitizeDebugDeoptimization ||
-      !CGF.CGM.getCodeGenOpts().OptimizationLevel ||
-      (CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr<OptimizeNoneAttr>());
+  NoMerge = NoMerge || ClSanitizeDebugDeoptimization ||
+            !CGF.CGM.getCodeGenOpts().OptimizationLevel ||
+            (CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr<OptimizeNoneAttr>());
   if (NoMerge)
     HandlerCall->addFnAttr(llvm::Attribute::NoMerge);
   if (!MayReturn) {
@@ -3608,6 +3607,7 @@ void CodeGenFunction::EmitCheck(
   llvm::Value *FatalCond = nullptr;
   llvm::Value *RecoverableCond = nullptr;
   llvm::Value *TrapCond = nullptr;
+  bool NoMerge = false;
   for (int i = 0, n = Checked.size(); i < n; ++i) {
     llvm::Value *Check = Checked[i].first;
     // -fsanitize-trap= overrides -fsanitize-recover=.
@@ -3618,6 +3618,9 @@ void CodeGenFunction::EmitCheck(
                   ? RecoverableCond
                   : FatalCond;
     Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check;
+
+    if (CGM.getCodeGenOpts().SanitizeNonMergedHandlers.has(Checked[i].second))
+      NoMerge = true;
   }
 
   if (ClSanitizeGuardChecks) {
@@ -3632,7 +3635,7 @@ void CodeGenFunction::EmitCheck(
   }
 
   if (TrapCond)
-    EmitTrapCheck(TrapCond, CheckHandler);
+    EmitTrapCheck(TrapCond, CheckHandler, NoMerge);
   if (!FatalCond && !RecoverableCond)
     return;
 
@@ -3698,7 +3701,7 @@ void CodeGenFunction::EmitCheck(
     // Simple case: we need to generate a single handler call, either
     // fatal, or non-fatal.
     emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind,
-                         (FatalCond != nullptr), Cont);
+                         (FatalCond != nullptr), Cont, NoMerge);
   } else {
     // Emit two handler calls: first one for set of unrecoverable checks,
     // another one for recoverable.
@@ -3708,10 +3711,10 @@ void CodeGenFunction::EmitCheck(
     Builder.CreateCondBr(FatalCond, NonFatalHandlerBB, FatalHandlerBB);
     EmitBlock(FatalHandlerBB);
     emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, true,
-                         NonFatalHandlerBB);
+                         NonFatalHandlerBB, NoMerge);
     EmitBlock(NonFatalHandlerBB);
     emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, false,
-                         Cont);
+                         Cont, NoMerge);
   }
 
   EmitBlock(Cont);
@@ -3901,7 +3904,8 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {
 }
 
 void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
-                                    SanitizerHandler CheckHandlerID) {
+                                    SanitizerHandler CheckHandlerID,
+                                    bool NoMerge) {
   llvm::BasicBlock *Cont = createBasicBlock("cont");
 
   // If we're optimizing, collapse all calls to trap down to just one per
@@ -3911,9 +3915,9 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
 
   llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];
 
-  bool NoMerge = ClSanitizeDebugDeoptimization ||
-                 !CGM.getCodeGenOpts().OptimizationLevel ||
-                 (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
+  NoMerge = NoMerge || ClSanitizeDebugDeoptimization ||
+            !CGM.getCodeGenOpts().OptimizationLevel ||
+            (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
 
   if (TrapBB && !NoMerge) {
     auto Call = TrapBB->begin();
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 092d55355a0a17..99a2a44248d274 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -5166,7 +5166,8 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   /// Create a basic block that will call the trap intrinsic, and emit a
   /// conditional branch to it, for the -ftrapv checks.
-  void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID);
+  void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID,
+                     bool NoMerge = false);
 
   /// Emit a call to trap or debugtrap and attach function attribute
   /// "trap-func-name" if specified.
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 81f94f23873661..969d112e570474 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -68,6 +68,9 @@ static const SanitizerMask TrappingSupported =
     SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
     SanitizerKind::LocalBounds | SanitizerKind::CFI |
     SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
+static const SanitizerMask NonMergedDefault;
+static const SanitizerMask NonMergedSupported =
+    (SanitizerKind::Undefined & ~SanitizerKind::Vptr);
 static const SanitizerMask TrappingDefault = SanitizerKind::CFI;
 static const SanitizerMask CFIClasses =
     SanitizerKind::CFIVCall | SanitizerKind::CFINVCall |
@@ -696,6 +699,17 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
   TrappingKinds &= Kinds;
   RecoverableKinds &= ~TrappingKinds;
 
+  // Parse -f(no-)?sanitize-nonmerged-handlers flags
+  SanitizerMask AlwaysNonMerged; // Empty
+  SanitizerMask NeverNonMerged = ~(setGroupBits(NonMergedSupported));
+  SanitizerMask NonMergedKinds = parseSanitizeArgs(
+      D, Args, DiagnoseErrors, NonMergedDefault, AlwaysNonMerged,
+      NeverNonMerged, options::OPT_fsanitize_nonmerged_handlers_EQ,
+      options::OPT_fno_sanitize_nonmerged_handlers_EQ);
+  NonMergedKinds |= AlwaysNonMerged;
+  NonMergedKinds &= ~NeverNonMerged;
+  NonMergedKinds &= Kinds;
+
   // Setup ignorelist files.
   // Add default ignorelist from resource directory for activated sanitizers,
   // and validate special case lists format.
@@ -1113,6 +1127,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
   TrapSanitizers.Mask |= TrappingKinds;
   assert(!(RecoverableKinds & TrappingKinds) &&
          "Overlap between recoverable and trapping sanitizers");
+
+  NonMergedHandlers.Mask |= NonMergedKinds;
 }
 
 static std::string toString(const clang::SanitizerSet &Sanitizers) {
@@ -1274,6 +1290,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
     CmdArgs.push_back(
         Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
 
+  if (!NonMergedHandlers.empty())
+    CmdArgs.push_back(Args.MakeArgString("-fsanitize-nonmerged-handlers=" +
+                                         toString(NonMergedHandlers)));
+
   addSpecialCaseListOpt(Args, CmdArgs,
                         "-fsanitize-ignorelist=", UserIgnorelistFiles);
   addSpecialCaseListOpt(Args, CmdArgs,
@@ -1441,13 +1461,17 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
 
 SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
                              bool DiagnoseErrors) {
-  assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
-          A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
-          A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
-          A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
-          A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
-          A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
-         "Invalid argument in parseArgValues!");
+  assert(
+      (A->getOption().matches(options::OPT_fsanitize_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_trap_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_nonmerged_handlers_EQ) ||
+       A->getOption().matches(
+           options::OPT_fno_sanitize_nonmerged_handlers_EQ)) &&
+      "Invalid argument in parseArgValues!");
   SanitizerMask Kinds;
   for (int i = 0, n = A->getNumValues(); i != n; ++i) {
     const char *Value = A->getValue(i);
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 298fafc21588a1..7fa01292f532c0 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1792,6 +1792,10 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
   for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeTrap))
     GenerateArg(Consumer, OPT_fsanitize_trap_EQ, Sanitizer);
 
+  for (StringRef Sanitizer :
+       serializeSanitizerKinds(Opts.SanitizeNonMergedHandlers))
+    GenerateArg(Consumer, OPT_fsanitize_nonmerged_handlers_EQ, Sanitizer);
+
   if (!Opts.EmitVersionIdentMetadata)
     GenerateArg(Consumer, OPT_Qn);
 
@@ -2269,6 +2273,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   parseSanitizerKinds("-fsanitize-trap=",
                       Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags,
                       Opts.SanitizeTrap);
+  parseSanitizerKinds("-fsanitize-nonmerged-handlers=",
+                      Args.getAllArgValues(OPT_fsanitize_nonmerged_handlers_EQ),
+                      Diags, Opts.SanitizeNonMergedHandlers);
 
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c
index 412ec7b09744ef..3a5a551fa7afa6 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -1,11 +1,16 @@
 // NOTE: Assertions have mostly been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
 // The most important assertion is the attributes at the end of the file, which
-// shows whether -ubsan-unique-traps attaches 'nomerge' to each ubsan call.
+// shows whether -ubsan-unique-traps and -fsanitize-nonmerged-handlers attach
+// 'nomerge' to each ubsan call.
 //
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefix=TRAP
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o -                                         | FileCheck %s --check-prefix=HANDLER
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-minimal-runtime              | FileCheck %s --check-prefix=MINRT
 //
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow  %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefix=TRAP
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow  %s -o -                                         | FileCheck %s --check-prefix=HANDLER
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow  %s -o - -fsanitize-minimal-runtime              | FileCheck %s --check-prefix=MINRT
+//
 // REQUIRES: x86-registered-target
 
 // TRAP-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f(
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index bb692b2aeea1d3..2d34ae871b6f55 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -9,6 +9,11 @@
 // CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
 // CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
 
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-nonmerged-handlers=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NONMERGED
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-nonmerged-handlers=undefined -fno-sanitize-nonmerged-handlers=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NONMERGED2
+// CHECK-UNDEFINED-NONMERGED: "-fsanitize-nonmerged-handlers=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
+// CHECK-UNDEFINED-NONMERGED2: "-fsanitize-nonmerged-handlers=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
+
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
 // CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}}
 

@llvmbot
Copy link
Member

llvmbot commented Dec 18, 2024

@llvm/pr-subscribers-clang

Author: Thurston Dang (thurstond)

Changes

'-mllvm -ubsan-unique-traps' (#65972) applies to all UBSan checks. This patch introduces -fsanitize-nonmerged-handlers and -fno-sanitize-nonmerged-handlers, which allows selectively applying non-merged handlers to a subset of UBSan checks.

N.B. we use "non-merged handlers" instead of "unique traps", since #119302 has generalized it to work for non-trap mode as well (min-rt and regular rt).

This patch does not remove the -ubsan-unique-traps flag; that will override -f(no-)sanitize-non-merged-handlers.


Full diff: https://github.com/llvm/llvm-project/pull/120464.diff

9 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.h (+4)
  • (modified) clang/include/clang/Driver/Options.td (+8)
  • (modified) clang/include/clang/Driver/SanitizerArgs.h (+1)
  • (modified) clang/lib/CodeGen/CGExpr.cpp (+17-13)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+2-1)
  • (modified) clang/lib/Driver/SanitizerArgs.cpp (+31-7)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+7)
  • (modified) clang/test/CodeGen/ubsan-trap-merge.c (+6-1)
  • (modified) clang/test/Driver/fsanitize.c (+5)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 2dcf98b465661e..9b97adce42cc2a 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -380,6 +380,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// Set of sanitizer checks that trap rather than diagnose.
   SanitizerSet SanitizeTrap;
 
+  /// Set of sanitizer checks that have non-merged handlers (better
+  /// debuggability at the expense of code size).
+  SanitizerSet SanitizeNonMergedHandlers;
+
   /// List of backend command-line options for -fembed-bitcode.
   std::vector<uint8_t> CmdArgs;
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 7b544d2534d469..e9fd59df3f9111 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2548,6 +2548,14 @@ def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Gro
 def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>,
                            Visibility<[ClangOption, CLOption]>,
                            HelpText<"Disable trapping for specified sanitizers">;
+def fsanitize_nonmerged_handlers_EQ
+    : CommaJoined<["-"], "fsanitize-nonmerged-handlers=">,
+      Group<f_clang_Group>,
+      HelpText<"Enable non-merged handlers for specified sanitizers">;
+def fno_sanitize_nonmerged_handlers_EQ
+    : CommaJoined<["-"], "fno-sanitize-nonmerged-handlers=">,
+      Group<f_clang_Group>,
+      HelpText<"Disable non-merged handlers for specified sanitizers">;
 def fsanitize_trap : Flag<["-"], "fsanitize-trap">, Group<f_clang_Group>,
                      Alias<fsanitize_trap_EQ>, AliasArgs<["all"]>,
                      HelpText<"Enable trapping for all sanitizers">;
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 4f08ea2b260179..28cfe72d6a34bd 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -25,6 +25,7 @@ class SanitizerArgs {
   SanitizerSet Sanitizers;
   SanitizerSet RecoverableSanitizers;
   SanitizerSet TrapSanitizers;
+  SanitizerSet NonMergedHandlers;
 
   std::vector<std::string> UserIgnorelistFiles;
   std::vector<std::string> SystemIgnorelistFiles;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 79955f55714164..9c0ddda2e28d9d 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3546,7 +3546,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
                                  ArrayRef<llvm::Value *> FnArgs,
                                  SanitizerHandler CheckHandler,
                                  CheckRecoverableKind RecoverKind, bool IsFatal,
-                                 llvm::BasicBlock *ContBB) {
+                                 llvm::BasicBlock *ContBB, bool NoMerge) {
   assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable);
   std::optional<ApplyDebugLocation> DL;
   if (!CGF.Builder.getCurrentDebugLocation()) {
@@ -3581,10 +3581,9 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
                                llvm::AttributeList::FunctionIndex, B),
       /*Local=*/true);
   llvm::CallInst *HandlerCall = CGF.EmitNounwindRuntimeCall(Fn, FnArgs);
-  bool NoMerge =
-      ClSanitizeDebugDeoptimization ||
-      !CGF.CGM.getCodeGenOpts().OptimizationLevel ||
-      (CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr<OptimizeNoneAttr>());
+  NoMerge = NoMerge || ClSanitizeDebugDeoptimization ||
+            !CGF.CGM.getCodeGenOpts().OptimizationLevel ||
+            (CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr<OptimizeNoneAttr>());
   if (NoMerge)
     HandlerCall->addFnAttr(llvm::Attribute::NoMerge);
   if (!MayReturn) {
@@ -3608,6 +3607,7 @@ void CodeGenFunction::EmitCheck(
   llvm::Value *FatalCond = nullptr;
   llvm::Value *RecoverableCond = nullptr;
   llvm::Value *TrapCond = nullptr;
+  bool NoMerge = false;
   for (int i = 0, n = Checked.size(); i < n; ++i) {
     llvm::Value *Check = Checked[i].first;
     // -fsanitize-trap= overrides -fsanitize-recover=.
@@ -3618,6 +3618,9 @@ void CodeGenFunction::EmitCheck(
                   ? RecoverableCond
                   : FatalCond;
     Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check;
+
+    if (CGM.getCodeGenOpts().SanitizeNonMergedHandlers.has(Checked[i].second))
+      NoMerge = true;
   }
 
   if (ClSanitizeGuardChecks) {
@@ -3632,7 +3635,7 @@ void CodeGenFunction::EmitCheck(
   }
 
   if (TrapCond)
-    EmitTrapCheck(TrapCond, CheckHandler);
+    EmitTrapCheck(TrapCond, CheckHandler, NoMerge);
   if (!FatalCond && !RecoverableCond)
     return;
 
@@ -3698,7 +3701,7 @@ void CodeGenFunction::EmitCheck(
     // Simple case: we need to generate a single handler call, either
     // fatal, or non-fatal.
     emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind,
-                         (FatalCond != nullptr), Cont);
+                         (FatalCond != nullptr), Cont, NoMerge);
   } else {
     // Emit two handler calls: first one for set of unrecoverable checks,
     // another one for recoverable.
@@ -3708,10 +3711,10 @@ void CodeGenFunction::EmitCheck(
     Builder.CreateCondBr(FatalCond, NonFatalHandlerBB, FatalHandlerBB);
     EmitBlock(FatalHandlerBB);
     emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, true,
-                         NonFatalHandlerBB);
+                         NonFatalHandlerBB, NoMerge);
     EmitBlock(NonFatalHandlerBB);
     emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, false,
-                         Cont);
+                         Cont, NoMerge);
   }
 
   EmitBlock(Cont);
@@ -3901,7 +3904,8 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {
 }
 
 void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
-                                    SanitizerHandler CheckHandlerID) {
+                                    SanitizerHandler CheckHandlerID,
+                                    bool NoMerge) {
   llvm::BasicBlock *Cont = createBasicBlock("cont");
 
   // If we're optimizing, collapse all calls to trap down to just one per
@@ -3911,9 +3915,9 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
 
   llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];
 
-  bool NoMerge = ClSanitizeDebugDeoptimization ||
-                 !CGM.getCodeGenOpts().OptimizationLevel ||
-                 (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
+  NoMerge = NoMerge || ClSanitizeDebugDeoptimization ||
+            !CGM.getCodeGenOpts().OptimizationLevel ||
+            (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
 
   if (TrapBB && !NoMerge) {
     auto Call = TrapBB->begin();
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 092d55355a0a17..99a2a44248d274 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -5166,7 +5166,8 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   /// Create a basic block that will call the trap intrinsic, and emit a
   /// conditional branch to it, for the -ftrapv checks.
-  void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID);
+  void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID,
+                     bool NoMerge = false);
 
   /// Emit a call to trap or debugtrap and attach function attribute
   /// "trap-func-name" if specified.
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 81f94f23873661..969d112e570474 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -68,6 +68,9 @@ static const SanitizerMask TrappingSupported =
     SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
     SanitizerKind::LocalBounds | SanitizerKind::CFI |
     SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
+static const SanitizerMask NonMergedDefault;
+static const SanitizerMask NonMergedSupported =
+    (SanitizerKind::Undefined & ~SanitizerKind::Vptr);
 static const SanitizerMask TrappingDefault = SanitizerKind::CFI;
 static const SanitizerMask CFIClasses =
     SanitizerKind::CFIVCall | SanitizerKind::CFINVCall |
@@ -696,6 +699,17 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
   TrappingKinds &= Kinds;
   RecoverableKinds &= ~TrappingKinds;
 
+  // Parse -f(no-)?sanitize-nonmerged-handlers flags
+  SanitizerMask AlwaysNonMerged; // Empty
+  SanitizerMask NeverNonMerged = ~(setGroupBits(NonMergedSupported));
+  SanitizerMask NonMergedKinds = parseSanitizeArgs(
+      D, Args, DiagnoseErrors, NonMergedDefault, AlwaysNonMerged,
+      NeverNonMerged, options::OPT_fsanitize_nonmerged_handlers_EQ,
+      options::OPT_fno_sanitize_nonmerged_handlers_EQ);
+  NonMergedKinds |= AlwaysNonMerged;
+  NonMergedKinds &= ~NeverNonMerged;
+  NonMergedKinds &= Kinds;
+
   // Setup ignorelist files.
   // Add default ignorelist from resource directory for activated sanitizers,
   // and validate special case lists format.
@@ -1113,6 +1127,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
   TrapSanitizers.Mask |= TrappingKinds;
   assert(!(RecoverableKinds & TrappingKinds) &&
          "Overlap between recoverable and trapping sanitizers");
+
+  NonMergedHandlers.Mask |= NonMergedKinds;
 }
 
 static std::string toString(const clang::SanitizerSet &Sanitizers) {
@@ -1274,6 +1290,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
     CmdArgs.push_back(
         Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
 
+  if (!NonMergedHandlers.empty())
+    CmdArgs.push_back(Args.MakeArgString("-fsanitize-nonmerged-handlers=" +
+                                         toString(NonMergedHandlers)));
+
   addSpecialCaseListOpt(Args, CmdArgs,
                         "-fsanitize-ignorelist=", UserIgnorelistFiles);
   addSpecialCaseListOpt(Args, CmdArgs,
@@ -1441,13 +1461,17 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
 
 SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
                              bool DiagnoseErrors) {
-  assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
-          A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
-          A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
-          A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
-          A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
-          A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
-         "Invalid argument in parseArgValues!");
+  assert(
+      (A->getOption().matches(options::OPT_fsanitize_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_trap_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_nonmerged_handlers_EQ) ||
+       A->getOption().matches(
+           options::OPT_fno_sanitize_nonmerged_handlers_EQ)) &&
+      "Invalid argument in parseArgValues!");
   SanitizerMask Kinds;
   for (int i = 0, n = A->getNumValues(); i != n; ++i) {
     const char *Value = A->getValue(i);
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 298fafc21588a1..7fa01292f532c0 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1792,6 +1792,10 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
   for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeTrap))
     GenerateArg(Consumer, OPT_fsanitize_trap_EQ, Sanitizer);
 
+  for (StringRef Sanitizer :
+       serializeSanitizerKinds(Opts.SanitizeNonMergedHandlers))
+    GenerateArg(Consumer, OPT_fsanitize_nonmerged_handlers_EQ, Sanitizer);
+
   if (!Opts.EmitVersionIdentMetadata)
     GenerateArg(Consumer, OPT_Qn);
 
@@ -2269,6 +2273,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   parseSanitizerKinds("-fsanitize-trap=",
                       Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags,
                       Opts.SanitizeTrap);
+  parseSanitizerKinds("-fsanitize-nonmerged-handlers=",
+                      Args.getAllArgValues(OPT_fsanitize_nonmerged_handlers_EQ),
+                      Diags, Opts.SanitizeNonMergedHandlers);
 
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c
index 412ec7b09744ef..3a5a551fa7afa6 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -1,11 +1,16 @@
 // NOTE: Assertions have mostly been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
 // The most important assertion is the attributes at the end of the file, which
-// shows whether -ubsan-unique-traps attaches 'nomerge' to each ubsan call.
+// shows whether -ubsan-unique-traps and -fsanitize-nonmerged-handlers attach
+// 'nomerge' to each ubsan call.
 //
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefix=TRAP
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o -                                         | FileCheck %s --check-prefix=HANDLER
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-minimal-runtime              | FileCheck %s --check-prefix=MINRT
 //
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow  %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefix=TRAP
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow  %s -o -                                         | FileCheck %s --check-prefix=HANDLER
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow  %s -o - -fsanitize-minimal-runtime              | FileCheck %s --check-prefix=MINRT
+//
 // REQUIRES: x86-registered-target
 
 // TRAP-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f(
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index bb692b2aeea1d3..2d34ae871b6f55 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -9,6 +9,11 @@
 // CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
 // CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
 
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-nonmerged-handlers=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NONMERGED
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-nonmerged-handlers=undefined -fno-sanitize-nonmerged-handlers=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NONMERGED2
+// CHECK-UNDEFINED-NONMERGED: "-fsanitize-nonmerged-handlers=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
+// CHECK-UNDEFINED-NONMERGED2: "-fsanitize-nonmerged-handlers=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
+
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
 // CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}}
 

@thurstond thurstond requested a review from vitalybuka December 18, 2024 21:57
@thurstond thurstond changed the title [ubsan] Add -fsanitize-nonmerged-handlers (and -fno-sanitize-nonmerged-handlers) [ubsan] Add -fsanitize-merge (and -fno-sanitize-merge) Dec 18, 2024
@thurstond thurstond requested a review from vitalybuka December 18, 2024 22:28
@thurstond thurstond merged commit 7eaf470 into llvm:main Dec 18, 2024
5 of 7 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 18, 2024

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-sie-ubuntu-fast running on sie-linux-worker while building clang at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/144/builds/14299

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'Clang :: CodeGen/ubsan-trap-debugloc.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only | /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only
�[1m/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c:20:11: �[0m�[0;1;31merror: �[0m�[1mCHECK: expected string not found in input
�[0m// CHECK: [[LOC]] = !DILocation(line: 0
�[0;1;32m          ^
�[0m�[1m<stdin>:75:46: �[0m�[0;1;30mnote: �[0m�[1mscanning from here
�[0m call void @llvm.ubsantrap(i8 0) #4, !dbg !26, !nosanitize !9
�[0;1;32m                                             ^
�[0m�[1m<stdin>:75:46: �[0m�[0;1;30mnote: �[0m�[1mwith "LOC" equal to "!15"
�[0m call void @llvm.ubsantrap(i8 0) #4, !dbg !26, !nosanitize !9
�[0;1;32m                                             ^
�[0m�[1m<stdin>:107:3: �[0m�[0;1;30mnote: �[0m�[1mpossible intended match here
�[0m!14 = !DILocation(line: 7, column: 7, scope: !6)
�[0;1;32m  ^
�[0m
Input file: <stdin>
Check file: /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c

-dump-input=help explains the following input dump.

Input was:
<<<<<<
�[1m�[0m�[0;1;30m            1: �[0m�[1m�[0;1;46m; ModuleID = '/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c' �[0m
�[0;1;30m            2: �[0m�[1m�[0;1;46msource_filename = "/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c" �[0m
�[0;1;30m            3: �[0m�[1m�[0;1;46mtarget datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" �[0m
�[0;1;30m            4: �[0m�[1m�[0;1;46mtarget triple = "x86_64-scei-ps4" �[0m
�[0;1;30m            5: �[0m�[1m�[0;1;46m �[0m
�[0;1;30m            6: �[0m�[1m�[0;1;[email protected] = private unnamed_addr constant [117 x i8] c"/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c\00", align 1 �[0m
�[0;1;30m            7: �[0m�[1m�[0;1;46m@0 = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" } �[0m
�[0;1;30m            8: �[0m�[1m�[0;1;46m �[0m
�[0;1;30m            9: �[0m�[1m�[0;1;46m; Function Attrs: nounwind �[0m
�[0;1;30m           10: �[0m�[1m�[0;1;46mdefine dso_local void �[0m@foo�[0;1;46m(i32 noundef %a) #0 !dbg !6 { �[0m
�[0;1;32mlabel:5'0                            ^~~~
�[0m�[0;1;32mlabel:5'1                            ^~~~
�[0m�[0;1;30m           11: �[0m�[1m�[0;1;46mentry: �[0m
�[0;1;30m           12: �[0m�[1m�[0;1;46m %a.addr = alloca i32, align 4 �[0m
�[0;1;30m           13: �[0m�[1m�[0;1;46m store volatile i32 %a, ptr %a.addr, align 4, !tbaa !10 �[0m
�[0;1;30m           14: �[0m�[1m�[0;1;46m %0 = load volatile i32, ptr %a.addr, align 4, !dbg !14, !tbaa !10 �[0m
�[0;1;30m           15: �[0m�[1m�[0;1;46m %1 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %0, i32 1), !dbg !15, !nosanitize !9 �[0m
�[0;1;30m           16: �[0m�[1m�[0;1;46m %2 = extractvalue { i32, i1 } %1, 0, !dbg !15, !nosanitize !9 �[0m
�[0;1;30m           17: �[0m�[1m�[0;1;46m %3 = extractvalue { i32, i1 } %1, 1, !dbg !15, !nosanitize !9 �[0m
�[0;1;30m           18: �[0m�[1m�[0;1;46m %4 = xor i1 %3, true, !dbg !15, !nosanitize !9 �[0m
�[0;1;30m           19: �[0m�[1m�[0;1;46m br i1 %4, label %cont, label %trap, !dbg !15, !nosanitize !9 �[0m
�[0;1;30m           20: �[0m�[1m�[0;1;46m �[0m
...

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 18, 2024

LLVM Buildbot has detected a new failure on builder openmp-offload-sles-build-only running on rocm-worker-hw-04-sles while building clang at step 6 "Add check check-clang".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/140/builds/13376

Here is the relevant piece of the build log for the reference
Step 6 (Add check check-clang) failure: test (failure)
******************** TEST 'Clang :: CodeGen/ubsan-trap-debugloc.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.build/bin/clang -cc1 -internal-isystem /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only | /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.build/bin/FileCheck /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c
+ /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.build/bin/clang -cc1 -internal-isystem /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only
+ /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.build/bin/FileCheck /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c:20:11: error: CHECK: expected string not found in input
// CHECK: [[LOC]] = !DILocation(line: 0
          ^
<stdin>:75:46: note: scanning from here
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:75:46: note: with "LOC" equal to "!14"
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:106:3: note: possible intended match here
!13 = !DILocation(line: 7, column: 7, scope: !5)
  ^

Input file: <stdin>
Check file: /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            .
            .
            .
           70:  %8 = extractvalue { i32, i1 } %6, 1, !dbg !25, !nosanitize !8 
           71:  %9 = xor i1 %8, true, !dbg !25, !nosanitize !8 
           72:  br i1 %9, label %cont2, label %trap1, !dbg !25, !nosanitize !8 
           73:  
           74: trap1: ; preds = %cont 
           75:  call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8 
check:20'0                                                  X~~~~~~~~~~~~~~~~ error: no match found
check:20'1                                                                    with "LOC" equal to "!14"
           76:  unreachable, !dbg !25, !nosanitize !8 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           77:  
check:20'0     ~
           78: cont2: ; preds = %cont 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~
           79:  store volatile i32 %7, ptr %a.addr, align 4, !dbg !26, !tbaa !9 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           80:  ret void, !dbg !27 
check:20'0     ~~~~~~~~~~~~~~~~~~~~
            .
...

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 18, 2024

LLVM Buildbot has detected a new failure on builder clang-cmake-x86_64-avx512-linux running on avx512-intel64 while building clang at step 7 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/133/builds/8646

Here is the relevant piece of the build log for the reference
Step 7 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'Clang :: CodeGen/ubsan-trap-debugloc.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/stage1/bin/clang -cc1 -internal-isystem /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/stage1/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/llvm/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only | /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/stage1/bin/FileCheck /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/llvm/clang/test/CodeGen/ubsan-trap-debugloc.c
+ /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/stage1/bin/clang -cc1 -internal-isystem /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/stage1/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/llvm/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only
+ /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/stage1/bin/FileCheck /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/llvm/clang/test/CodeGen/ubsan-trap-debugloc.c
/localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/llvm/clang/test/CodeGen/ubsan-trap-debugloc.c:20:11: error: CHECK: expected string not found in input
// CHECK: [[LOC]] = !DILocation(line: 0
          ^
<stdin>:75:46: note: scanning from here
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:75:46: note: with "LOC" equal to "!14"
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:106:3: note: possible intended match here
!13 = !DILocation(line: 7, column: 7, scope: !5)
  ^

Input file: <stdin>
Check file: /localdisk2/buildbot/llvm-worker/clang-cmake-x86_64-avx512-linux/llvm/clang/test/CodeGen/ubsan-trap-debugloc.c

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            .
            .
            .
           70:  %8 = extractvalue { i32, i1 } %6, 1, !dbg !25, !nosanitize !8 
           71:  %9 = xor i1 %8, true, !dbg !25, !nosanitize !8 
           72:  br i1 %9, label %cont2, label %trap1, !dbg !25, !nosanitize !8 
           73:  
           74: trap1: ; preds = %cont 
           75:  call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8 
check:20'0                                                  X~~~~~~~~~~~~~~~~ error: no match found
check:20'1                                                                    with "LOC" equal to "!14"
           76:  unreachable, !dbg !25, !nosanitize !8 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           77:  
check:20'0     ~
           78: cont2: ; preds = %cont 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~
           79:  store volatile i32 %7, ptr %a.addr, align 4, !dbg !26, !tbaa !9 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           80:  ret void, !dbg !27 
check:20'0     ~~~~~~~~~~~~~~~~~~~~
            .
...

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 19, 2024

LLVM Buildbot has detected a new failure on builder llvm-clang-aarch64-darwin running on doug-worker-5 while building clang at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/190/builds/11649

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'Clang :: CodeGen/ubsan-trap-debugloc.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /Users/buildbot/buildbot-root/aarch64-darwin/build/bin/clang -cc1 -internal-isystem /Users/buildbot/buildbot-root/aarch64-darwin/build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /Users/buildbot/buildbot-root/aarch64-darwin/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only | /Users/buildbot/buildbot-root/aarch64-darwin/build/bin/FileCheck /Users/buildbot/buildbot-root/aarch64-darwin/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c
+ /Users/buildbot/buildbot-root/aarch64-darwin/build/bin/clang -cc1 -internal-isystem /Users/buildbot/buildbot-root/aarch64-darwin/build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /Users/buildbot/buildbot-root/aarch64-darwin/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only
+ /Users/buildbot/buildbot-root/aarch64-darwin/build/bin/FileCheck /Users/buildbot/buildbot-root/aarch64-darwin/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c
�[1m/Users/buildbot/buildbot-root/aarch64-darwin/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c:20:11: �[0m�[0;1;31merror: �[0m�[1mCHECK: expected string not found in input
�[0m// CHECK: [[LOC]] = !DILocation(line: 0
�[0;1;32m          ^
�[0m�[1m<stdin>:75:46: �[0m�[0;1;30mnote: �[0m�[1mscanning from here
�[0m call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
�[0;1;32m                                             ^
�[0m�[1m<stdin>:75:46: �[0m�[0;1;30mnote: �[0m�[1mwith "LOC" equal to "!14"
�[0m call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
�[0;1;32m                                             ^
�[0m�[1m<stdin>:106:3: �[0m�[0;1;30mnote: �[0m�[1mpossible intended match here
�[0m!13 = !DILocation(line: 7, column: 7, scope: !5)
�[0;1;32m  ^
�[0m
Input file: <stdin>
Check file: /Users/buildbot/buildbot-root/aarch64-darwin/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c

-dump-input=help explains the following input dump.

Input was:
<<<<<<
�[1m�[0m�[0;1;30m            1: �[0m�[1m�[0;1;46m; ModuleID = '/Users/buildbot/buildbot-root/aarch64-darwin/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c' �[0m
�[0;1;30m            2: �[0m�[1m�[0;1;46msource_filename = "/Users/buildbot/buildbot-root/aarch64-darwin/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c" �[0m
�[0;1;30m            3: �[0m�[1m�[0;1;46mtarget datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" �[0m
�[0;1;30m            4: �[0m�[1m�[0;1;46mtarget triple = "arm64-apple-darwin23.6.0" �[0m
�[0;1;30m            5: �[0m�[1m�[0;1;46m �[0m
�[0;1;30m            6: �[0m�[1m�[0;1;[email protected] = private unnamed_addr constant [99 x i8] c"/Users/buildbot/buildbot-root/aarch64-darwin/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c\00", align 1 �[0m
�[0;1;30m            7: �[0m�[1m�[0;1;46m@0 = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" } �[0m
�[0;1;30m            8: �[0m�[1m�[0;1;46m �[0m
�[0;1;30m            9: �[0m�[1m�[0;1;46m; Function Attrs: nounwind �[0m
�[0;1;30m           10: �[0m�[1m�[0;1;46mdefine void �[0m@foo�[0;1;46m(i32 noundef %a) #0 !dbg !5 { �[0m
�[0;1;32mlabel:5'0                  ^~~~
�[0m�[0;1;32mlabel:5'1                  ^~~~
�[0m�[0;1;30m           11: �[0m�[1m�[0;1;46mentry: �[0m
�[0;1;30m           12: �[0m�[1m�[0;1;46m %a.addr = alloca i32, align 4 �[0m
�[0;1;30m           13: �[0m�[1m�[0;1;46m store volatile i32 %a, ptr %a.addr, align 4, !tbaa !9 �[0m
�[0;1;30m           14: �[0m�[1m�[0;1;46m %0 = load volatile i32, ptr %a.addr, align 4, !dbg !13, !tbaa !9 �[0m
�[0;1;30m           15: �[0m�[1m�[0;1;46m %1 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %0, i32 1), !dbg !14, !nosanitize !8 �[0m
�[0;1;30m           16: �[0m�[1m�[0;1;46m %2 = extractvalue { i32, i1 } %1, 0, !dbg !14, !nosanitize !8 �[0m
�[0;1;30m           17: �[0m�[1m�[0;1;46m %3 = extractvalue { i32, i1 } %1, 1, !dbg !14, !nosanitize !8 �[0m
�[0;1;30m           18: �[0m�[1m�[0;1;46m %4 = xor i1 %3, true, !dbg !14, !nosanitize !8 �[0m
�[0;1;30m           19: �[0m�[1m�[0;1;46m br i1 %4, label %cont, label %trap, !dbg !14, !nosanitize !8 �[0m
�[0;1;30m           20: �[0m�[1m�[0;1;46m �[0m
...

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 19, 2024

LLVM Buildbot has detected a new failure on builder llvm-x86_64-debian-dylib running on gribozavr4 while building clang at step 6 "test-build-unified-tree-check-clang".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/60/builds/15574

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-clang) failure: test (failure)
******************** TEST 'Clang :: CodeGen/ubsan-trap-debugloc.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /b/1/llvm-x86_64-debian-dylib/build/bin/clang -cc1 -internal-isystem /b/1/llvm-x86_64-debian-dylib/build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /b/1/llvm-x86_64-debian-dylib/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only | /b/1/llvm-x86_64-debian-dylib/build/bin/FileCheck /b/1/llvm-x86_64-debian-dylib/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c
+ /b/1/llvm-x86_64-debian-dylib/build/bin/clang -cc1 -internal-isystem /b/1/llvm-x86_64-debian-dylib/build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /b/1/llvm-x86_64-debian-dylib/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only
+ /b/1/llvm-x86_64-debian-dylib/build/bin/FileCheck /b/1/llvm-x86_64-debian-dylib/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c
/b/1/llvm-x86_64-debian-dylib/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c:20:11: error: CHECK: expected string not found in input
// CHECK: [[LOC]] = !DILocation(line: 0
          ^
<stdin>:75:46: note: scanning from here
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:75:46: note: with "LOC" equal to "!14"
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:106:3: note: possible intended match here
!13 = !DILocation(line: 7, column: 7, scope: !5)
  ^

Input file: <stdin>
Check file: /b/1/llvm-x86_64-debian-dylib/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            .
            .
            .
           70:  %8 = extractvalue { i32, i1 } %6, 1, !dbg !25, !nosanitize !8 
           71:  %9 = xor i1 %8, true, !dbg !25, !nosanitize !8 
           72:  br i1 %9, label %cont2, label %trap1, !dbg !25, !nosanitize !8 
           73:  
           74: trap1: ; preds = %cont 
           75:  call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8 
check:20'0                                                  X~~~~~~~~~~~~~~~~ error: no match found
check:20'1                                                                    with "LOC" equal to "!14"
           76:  unreachable, !dbg !25, !nosanitize !8 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           77:  
check:20'0     ~
           78: cont2: ; preds = %cont 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~
           79:  store volatile i32 %7, ptr %a.addr, align 4, !dbg !26, !tbaa !9 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           80:  ret void, !dbg !27 
check:20'0     ~~~~~~~~~~~~~~~~~~~~
            .
...

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 19, 2024

LLVM Buildbot has detected a new failure on builder clang-x86_64-debian-fast running on gribozavr4 while building clang at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/56/builds/14864

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'Clang :: CodeGen/ubsan-trap-debugloc.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /b/1/clang-x86_64-debian-fast/llvm.obj/bin/clang -cc1 -internal-isystem /b/1/clang-x86_64-debian-fast/llvm.obj/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /b/1/clang-x86_64-debian-fast/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only | /b/1/clang-x86_64-debian-fast/llvm.obj/bin/FileCheck /b/1/clang-x86_64-debian-fast/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c
+ /b/1/clang-x86_64-debian-fast/llvm.obj/bin/clang -cc1 -internal-isystem /b/1/clang-x86_64-debian-fast/llvm.obj/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /b/1/clang-x86_64-debian-fast/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only
+ /b/1/clang-x86_64-debian-fast/llvm.obj/bin/FileCheck /b/1/clang-x86_64-debian-fast/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c
/b/1/clang-x86_64-debian-fast/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c:20:11: error: CHECK: expected string not found in input
// CHECK: [[LOC]] = !DILocation(line: 0
          ^
<stdin>:75:46: note: scanning from here
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:75:46: note: with "LOC" equal to "!14"
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:106:3: note: possible intended match here
!13 = !DILocation(line: 7, column: 7, scope: !5)
  ^

Input file: <stdin>
Check file: /b/1/clang-x86_64-debian-fast/llvm.src/clang/test/CodeGen/ubsan-trap-debugloc.c

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            .
            .
            .
           70:  %8 = extractvalue { i32, i1 } %6, 1, !dbg !25, !nosanitize !8 
           71:  %9 = xor i1 %8, true, !dbg !25, !nosanitize !8 
           72:  br i1 %9, label %cont2, label %trap1, !dbg !25, !nosanitize !8 
           73:  
           74: trap1: ; preds = %cont 
           75:  call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8 
check:20'0                                                  X~~~~~~~~~~~~~~~~ error: no match found
check:20'1                                                                    with "LOC" equal to "!14"
           76:  unreachable, !dbg !25, !nosanitize !8 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           77:  
check:20'0     ~
           78: cont2: ; preds = %cont 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~
           79:  store volatile i32 %7, ptr %a.addr, align 4, !dbg !26, !tbaa !9 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           80:  ret void, !dbg !27 
check:20'0     ~~~~~~~~~~~~~~~~~~~~
            .
...

thurstond added a commit to thurstond/llvm-project that referenced this pull request Dec 19, 2024
…#120464)"

This reverts commit 2691b96.
This reapply fixes the buildbot breakage of the original patch, by
updating clang/test/CodeGen/ubsan-trap-debugloc.c to specify
-fsanitize-merge (the default, which is merge, is applied by the driver
but not clang_cc1).

This reapply also expands clang/test/CodeGen/ubsan-trap-merge.c.

Original commit message:
'-mllvm -ubsan-unique-traps' (llvm#65972) applies to all UBSan checks. This patch introduces -fsanitize-merge (defaults to on, maintaining the status quo behavior) and -fno-sanitize-merge (equivalent to '-mllvm -ubsan-unique-traps'), with the option to selectively applying non-merged handlers to a subset of UBSan checks (e.g., -fno-sanitize-merge=bool,enum).

N.B. we do not use "trap" in the argument name since llvm#119302 has generalized -ubsan-unique-traps to work for non-trap modes (min-rt and regular rt).

This patch does not remove the -ubsan-unique-traps flag; that will override -f(no-)sanitize-merge.
swift-ci pushed a commit to swiftlang/llvm-project that referenced this pull request Dec 19, 2024
@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 19, 2024

LLVM Buildbot has detected a new failure on builder premerge-monolithic-linux running on premerge-linux-1 while building clang at step 7 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/153/builds/18012

Here is the relevant piece of the build log for the reference
Step 7 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'Clang :: CodeGen/ubsan-trap-debugloc.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /build/buildbot/premerge-monolithic-linux/build/bin/clang -cc1 -internal-isystem /build/buildbot/premerge-monolithic-linux/build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /build/buildbot/premerge-monolithic-linux/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only | /build/buildbot/premerge-monolithic-linux/build/bin/FileCheck /build/buildbot/premerge-monolithic-linux/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c
+ /build/buildbot/premerge-monolithic-linux/build/bin/FileCheck /build/buildbot/premerge-monolithic-linux/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c
+ /build/buildbot/premerge-monolithic-linux/build/bin/clang -cc1 -internal-isystem /build/buildbot/premerge-monolithic-linux/build/lib/clang/20/include -nostdsysteminc -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow /build/buildbot/premerge-monolithic-linux/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c -o - -debug-info-kind=line-tables-only
/build/buildbot/premerge-monolithic-linux/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c:20:11: error: CHECK: expected string not found in input
// CHECK: [[LOC]] = !DILocation(line: 0
          ^
<stdin>:75:46: note: scanning from here
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:75:46: note: with "LOC" equal to "!14"
 call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8
                                             ^
<stdin>:106:3: note: possible intended match here
!13 = !DILocation(line: 7, column: 7, scope: !5)
  ^

Input file: <stdin>
Check file: /build/buildbot/premerge-monolithic-linux/llvm-project/clang/test/CodeGen/ubsan-trap-debugloc.c

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            .
            .
            .
           70:  %8 = extractvalue { i32, i1 } %6, 1, !dbg !25, !nosanitize !8 
           71:  %9 = xor i1 %8, true, !dbg !25, !nosanitize !8 
           72:  br i1 %9, label %cont2, label %trap1, !dbg !25, !nosanitize !8 
           73:  
           74: trap1: ; preds = %cont 
           75:  call void @llvm.ubsantrap(i8 0) #4, !dbg !25, !nosanitize !8 
check:20'0                                                  X~~~~~~~~~~~~~~~~ error: no match found
check:20'1                                                                    with "LOC" equal to "!14"
           76:  unreachable, !dbg !25, !nosanitize !8 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           77:  
check:20'0     ~
           78: cont2: ; preds = %cont 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~
           79:  store volatile i32 %7, ptr %a.addr, align 4, !dbg !26, !tbaa !9 
check:20'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           80:  ret void, !dbg !27 
check:20'0     ~~~~~~~~~~~~~~~~~~~~
            .
...

swift-ci pushed a commit to swiftlang/llvm-project that referenced this pull request Dec 19, 2024
thurstond added a commit to thurstond/llvm-project that referenced this pull request Apr 10, 2025
llvm#120464 (and earlier CLs) added -fsanitize-merge functionality, which is intended to work for all "sanitizers". It is nearly correct for CFI.

This patch precommits some tests for CFI, to track the progress of
future -fsanitize-merge fixes.
thurstond added a commit that referenced this pull request Apr 10, 2025
#120464 (and earlier CLs) added -fsanitize-merge functionality, which is intended to work for all "sanitizers". It is nearly correct for CFI.

This patch precommits some tests for CFI, to track the progress of future -fsanitize-merge fixes for CFI.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Apr 10, 2025
…(#135104)

llvm/llvm-project#120464 (and earlier CLs) added -fsanitize-merge functionality, which is intended to work for all "sanitizers". It is nearly correct for CFI.

This patch precommits some tests for CFI, to track the progress of future -fsanitize-merge fixes for CFI.
AllinLeeYL pushed a commit to AllinLeeYL/llvm-project that referenced this pull request Apr 10, 2025
llvm#120464 (and earlier CLs) added -fsanitize-merge functionality, which is intended to work for all "sanitizers". It is nearly correct for CFI.

This patch precommits some tests for CFI, to track the progress of future -fsanitize-merge fixes for CFI.
thurstond added a commit to thurstond/llvm-project that referenced this pull request Apr 11, 2025
-fno-sanitize-merge (introduced in
llvm#120464) nearly works for CFI:
code that calls EmitCheck will already check the merge options. This patch fixes one EmitTrapCheck call, which did not check the merge options, and for two other EmitTrapChecks, adds two TODOs that explain why it is difficult to fix them.
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
llvm#120464 (and earlier CLs) added -fsanitize-merge functionality, which is intended to work for all "sanitizers". It is nearly correct for CFI.

This patch precommits some tests for CFI, to track the progress of future -fsanitize-merge fixes for CFI.
thurstond added a commit that referenced this pull request Apr 24, 2025
-fno-sanitize-merge (introduced in
#120464) nearly works for CFI:
code that calls EmitCheck will already check the merge options. This
patch fixes one EmitTrapCheck call, which did not check the merge
options, and for two other EmitTrapChecks, adds two TODOs that explain
why it is difficult to fix them.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 6, 2025
…(#135438)

-fno-sanitize-merge (introduced in
llvm/llvm-project#120464) nearly works for CFI:
code that calls EmitCheck will already check the merge options. This
patch fixes one EmitTrapCheck call, which did not check the merge
options, and for two other EmitTrapChecks, adds two TODOs that explain
why it is difficult to fix them.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
-fno-sanitize-merge (introduced in
llvm#120464) nearly works for CFI:
code that calls EmitCheck will already check the merge options. This
patch fixes one EmitTrapCheck call, which did not check the merge
options, and for two other EmitTrapChecks, adds two TODOs that explain
why it is difficult to fix them.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
-fno-sanitize-merge (introduced in
llvm#120464) nearly works for CFI:
code that calls EmitCheck will already check the merge options. This
patch fixes one EmitTrapCheck call, which did not check the merge
options, and for two other EmitTrapChecks, adds two TODOs that explain
why it is difficult to fix them.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
-fno-sanitize-merge (introduced in
llvm#120464) nearly works for CFI:
code that calls EmitCheck will already check the merge options. This
patch fixes one EmitTrapCheck call, which did not check the merge
options, and for two other EmitTrapChecks, adds two TODOs that explain
why it is difficult to fix them.
Ankur-0429 pushed a commit to Ankur-0429/llvm-project that referenced this pull request May 9, 2025
-fno-sanitize-merge (introduced in
llvm#120464) nearly works for CFI:
code that calls EmitCheck will already check the merge options. This
patch fixes one EmitTrapCheck call, which did not check the merge
options, and for two other EmitTrapChecks, adds two TODOs that explain
why it is difficult to fix them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants