Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[sanitizer] Add plumbing for -fsanitize-annotate-debug-info and partly replace '-mllvm -array-bounds-pseudofn' #138577

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 9 commits into from
May 7, 2025

Conversation

thurstond
Copy link
Contributor

@thurstond thurstond commented May 5, 2025

@fmayer introduced '-mllvm -array-bounds-pseudofn' (#128977) to make it easier to see why crashes occurred, and to estimate with a profiler the cycles spent on these array-bounds checks. This functionality could be usefully generalized to other checks in future work.

This patch adds the plumbing for -fsanitize-annotate-debug-info, and connects it to the existing array-bounds-pseudo-fn functionality i.e., -fsanitize-annotate-debug-info=array-bounds can be used as a replacement for '-mllvm -array-bounds-pseudofn', though we do not yet delete the latter.

Note: we replaced '-mllvm -array-bounds-pseudofn' in clang/test/CodeGen/bounds-checking-debuginfo.c, because adding test cases would modify the line numbers in the test assertions, and therefore obscure that the test output is the same between '-mllvm -array-bounds-pseudofn' and -fsanitize-annotate-debug-info=array-bounds.

…ly replace '-mllvm -array-bounds-pseudofn'

Florian1 introduced '-mllvm -array-bounds-pseudofn'
(llvm#128977) to make it easier to
see why crashes occurred, and to estimate with a profiler the cycles spent on these
array-bounds checks. This functionality could be usefully generalized to other
checks in future work.

This patch adds the plumbing for -fsanitize-add-pseudo-functions, and
connects it to the existing array-bounds-pseudo-fn functionality i.e.,
-fsanitize-add-pseudo-functions=array-bounds can be used as a
replacement for '-mllvm -array-bounds-pseudofn', though we do not yet
delete the latter.

Note: we replaced '-mllvm -array-bounds-pseudofn' in clang/test/CodeGen/bounds-checking-debuginfo.c, because adding test cases would modify the line numbers in the test assertions, and therefore obscure that the test output is the same between '-mllvm -array-bounds-pseudofn' and -fsanitize-add-pseudo-functions=array-bounds.
@thurstond thurstond requested review from fmayer and vitalybuka May 5, 2025 20:26
@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 May 5, 2025
@thurstond thurstond changed the title [sanitizer] Add plumbing for -fsanitize-add-pseudo-functions and part… [sanitizer] Add plumbing for -fsanitize-add-pseudo-functions and partly replace '-mllvm -array-bounds-pseudofn' May 5, 2025
@llvmbot
Copy link
Member

llvmbot commented May 5, 2025

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-clang-driver

Author: Thurston Dang (thurstond)

Changes

Florian1 introduced '-mllvm -array-bounds-pseudofn' (#128977) to make it easier to see why crashes occurred, and to estimate with a profiler the cycles spent on these array-bounds checks. This functionality could be usefully generalized to other checks in future work.

This patch adds the plumbing for -fsanitize-add-pseudo-functions, and connects it to the existing array-bounds-pseudo-fn functionality i.e., -fsanitize-add-pseudo-functions=array-bounds can be used as a replacement for '-mllvm -array-bounds-pseudofn', though we do not yet delete the latter.

Note: we replaced '-mllvm -array-bounds-pseudofn' in clang/test/CodeGen/bounds-checking-debuginfo.c, because adding test cases would modify the line numbers in the test assertions, and therefore obscure that the test output is the same between '-mllvm -array-bounds-pseudofn' and -fsanitize-add-pseudo-functions=array-bounds.


Patch is 23.01 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138577.diff

8 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.h (+3)
  • (modified) clang/include/clang/Driver/Options.td (+15)
  • (modified) clang/include/clang/Driver/SanitizerArgs.h (+1)
  • (modified) clang/lib/CodeGen/CGExpr.cpp (+1-1)
  • (modified) clang/lib/Driver/SanitizerArgs.cpp (+17-1)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+8)
  • (modified) clang/test/CodeGen/bounds-checking-debuginfo.c (+2-2)
  • (modified) clang/test/Driver/fsanitize.c (+58)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index e39a73bdb13ac..be17c81876ddf 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -399,6 +399,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// (0.0 [default] to skip none, 1.0 to skip all).
   SanitizerMaskCutoffs SanitizeSkipHotCutoffs;
 
+  /// Set of sanitizer checks that will be wrapped inside pseudofunctions.
+  SanitizerSet SanitizeAddPseudoFunctions;
+
   /// 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 11677626dbf1f..c06bc5cfcbfa8 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2533,6 +2533,21 @@ def fno_sanitize_merge_handlers : Flag<["-"], "fno-sanitize-merge">, Group<f_cla
                         Alias<fno_sanitize_merge_handlers_EQ>, AliasArgs<["all"]>,
                         Visibility<[ClangOption, CLOption]>,
                         HelpText<"Do not allow compiler to merge handlers for any sanitizers">;
+def fsanitize_add_pseudo_functions_EQ
+    : CommaJoined<["-"], "fsanitize-add-pseudo-functions=">,
+      Group<f_clang_Group>,
+      HelpText<"Add pseudo-functions to checks for specified sanitizers">;
+def fno_sanitize_add_pseudo_functions_EQ
+    : CommaJoined<["-"], "fno-sanitize-add-pseudo-functions=">,
+      Group<f_clang_Group>,
+      HelpText<"Do not allow compiler to add pseudo-functions to checks for specified sanitizers">;
+def fsanitize_add_pseudo_functions : Flag<["-"], "fsanitize-add-pseudo-functions">, Group<f_clang_Group>,
+                     Alias<fsanitize_add_pseudo_functions_EQ>, AliasArgs<["all"]>,
+                     HelpText<"Allow compiler to add pseudo-functions to checks for all sanitizers">;
+def fno_sanitize_add_pseudo_functions : Flag<["-"], "fno-sanitize-add-pseudo-functions">, Group<f_clang_Group>,
+                        Alias<fno_sanitize_add_pseudo_functions_EQ>, AliasArgs<["all"]>,
+                        Visibility<[ClangOption, CLOption]>,
+                        HelpText<"Do not allow compiler to add pseudo-functions to checks for any sanitizers">;
 def fsanitize_undefined_trap_on_error
     : Flag<["-"], "fsanitize-undefined-trap-on-error">, Group<f_clang_Group>,
       Alias<fsanitize_trap_EQ>, AliasArgs<["undefined"]>;
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 528e3b400f3dc..1c11706639aba 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -27,6 +27,7 @@ class SanitizerArgs {
   SanitizerSet TrapSanitizers;
   SanitizerSet MergeHandlers;
   SanitizerMaskCutoffs SkipHotCutoffs;
+  SanitizerSet AddPseudoFunctions;
 
   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 2e01adc51fdf0..4ea41662af296 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1228,7 +1228,7 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
   SanitizerScope SanScope(this);
 
   llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
-  if (ClArrayBoundsPseudoFn && CheckDI) {
+  if ((ClArrayBoundsPseudoFn || CGM.getCodeGenOpts().SanitizeAddPseudoFunctions.has(SanitizerKind::SO_ArrayBounds)) && CheckDI) {
     CheckDI = getDebugInfo()->CreateSyntheticInlineAt(
         Builder.getCurrentDebugLocation(), "__ubsan_check_array_bounds");
   }
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index ff08bffdbde1f..fd456ea0674af 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -76,6 +76,7 @@ static const SanitizerMask MergeDefault =
     SanitizerKind::Undefined | SanitizerKind::Vptr;
 static const SanitizerMask TrappingDefault =
     SanitizerKind::CFI | SanitizerKind::LocalBounds;
+static const SanitizerMask AddPseudoFunctionsDefault;
 static const SanitizerMask CFIClasses =
     SanitizerKind::CFIVCall | SanitizerKind::CFINVCall |
     SanitizerKind::CFIMFCall | SanitizerKind::CFIDerivedCast |
@@ -738,6 +739,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
   // Parse -fno-sanitize-top-hot flags
   SkipHotCutoffs = parseSanitizeSkipHotCutoffArgs(D, Args, DiagnoseErrors);
 
+  // Parse -f(no-)?sanitize-add-pseudo-functions flags
+  SanitizerMask AddPseudoFunctionsKinds =
+      parseSanitizeArgs(D, Args, DiagnoseErrors, AddPseudoFunctionsDefault, {}, {},
+                        options::OPT_fsanitize_add_pseudo_functions_EQ,
+                        options::OPT_fno_sanitize_add_pseudo_functions_EQ);
+  AddPseudoFunctionsKinds &= Kinds;
+
   // Setup ignorelist files.
   // Add default ignorelist from resource directory for activated sanitizers,
   // and validate special case lists format.
@@ -1157,6 +1165,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
 
   MergeHandlers.Mask |= MergeKinds;
 
+  AddPseudoFunctions.Mask |= AddPseudoFunctionsKinds;
+
   // Zero out SkipHotCutoffs for unused sanitizers
   SkipHotCutoffs.clear(~Sanitizers.Mask);
 }
@@ -1335,6 +1345,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
     CmdArgs.push_back(
         Args.MakeArgString("-fsanitize-skip-hot-cutoff=" + SkipHotCutoffsStr));
 
+  if (!AddPseudoFunctions.empty())
+    CmdArgs.push_back(
+        Args.MakeArgString("-fsanitize-add-pseudo-functions=" + toString(AddPseudoFunctions)));
+
   addSpecialCaseListOpt(Args, CmdArgs,
                         "-fsanitize-ignorelist=", UserIgnorelistFiles);
   addSpecialCaseListOpt(Args, CmdArgs,
@@ -1518,7 +1532,9 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
        A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
        A->getOption().matches(options::OPT_fno_sanitize_trap_EQ) ||
        A->getOption().matches(options::OPT_fsanitize_merge_handlers_EQ) ||
-       A->getOption().matches(options::OPT_fno_sanitize_merge_handlers_EQ)) &&
+       A->getOption().matches(options::OPT_fno_sanitize_merge_handlers_EQ) ||
+       A->getOption().matches(options::OPT_fsanitize_add_pseudo_functions_EQ) ||
+       A->getOption().matches(options::OPT_fno_sanitize_add_pseudo_functions_EQ)) &&
       "Invalid argument in parseArgValues!");
   SanitizerMask Kinds;
   for (int i = 0, n = A->getNumValues(); i != n; ++i) {
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index c7d11e6027ccf..d79b0546d41ce 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1838,6 +1838,10 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
   for (std::string Sanitizer : Values)
     GenerateArg(Consumer, OPT_fsanitize_skip_hot_cutoff_EQ, Sanitizer);
 
+  for (StringRef Sanitizer :
+       serializeSanitizerKinds(Opts.SanitizeAddPseudoFunctions))
+    GenerateArg(Consumer, OPT_fsanitize_add_pseudo_functions_EQ, Sanitizer);
+
   if (!Opts.EmitVersionIdentMetadata)
     GenerateArg(Consumer, OPT_Qn);
 
@@ -2332,6 +2336,10 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
       "-fsanitize-skip-hot-cutoff=",
       Args.getAllArgValues(OPT_fsanitize_skip_hot_cutoff_EQ), Diags);
 
+  parseSanitizerKinds("-fsanitize-add-pseudo-functions=",
+                      Args.getAllArgValues(OPT_fsanitize_add_pseudo_functions_EQ),
+                      Diags, Opts.SanitizeAddPseudoFunctions);
+
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
   if (!LangOpts->CUDAIsDevice)
diff --git a/clang/test/CodeGen/bounds-checking-debuginfo.c b/clang/test/CodeGen/bounds-checking-debuginfo.c
index 4f5ba2b76eeeb..f31a40d86dac4 100644
--- a/clang/test/CodeGen/bounds-checking-debuginfo.c
+++ b/clang/test/CodeGen/bounds-checking-debuginfo.c
@@ -1,7 +1,7 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
-// RUN: %clang_cc1 -mllvm -array-bounds-pseudofn -emit-llvm -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -fsanitize=array-bounds -fsanitize-trap=array-bounds -triple x86_64 -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-TRAP %s
-// RUN: %clang_cc1 -mllvm -array-bounds-pseudofn -emit-llvm -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -fsanitize=array-bounds                              -triple x86_64 -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-NOTRAP %s
 
+// RUN: %clang_cc1 -emit-llvm -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -fsanitize=array-bounds -fsanitize-trap=array-bounds -fsanitize-add-pseudo-functions=array-bounds -triple x86_64 -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-TRAP %s
+// RUN: %clang_cc1 -emit-llvm -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -fsanitize=array-bounds                              -fsanitize-add-pseudo-functions=array-bounds -triple x86_64 -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-NOTRAP %s
 
 int f();
 void d(double*);
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index eb72140fb1315..ca58d4a50bc79 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -1,3 +1,5 @@
+// * Test -fsanitize-trap */
+
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-trap=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP2
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
@@ -9,6 +11,9 @@
 // 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"
 
+
+// * Test -fsanitize-merge *
+
 // The trailing -fsanitize-merge takes precedence
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                                                                              %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                             -fsanitize-merge                                 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE
@@ -62,6 +67,59 @@
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=signed-integer-overflow -fno-sanitize-merge=undefined -fsanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE5
 // CHECK-UNDEFINED-MERGE5: "-fsanitize-merge=alignment,null"
 
+
+// * Test -fsanitize-add-pseudo-functions *
+
+// The trailing -fsanitize-add-pseudo-functions takes precedence
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                                            -fsanitize-add-pseudo-functions                                 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                                            -fsanitize-add-pseudo-functions=undefined                       %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions                         -fsanitize-add-pseudo-functions                                 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions                         -fsanitize-add-pseudo-functions=undefined                       %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions=undefined               -fsanitize-add-pseudo-functions                                 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions=undefined               -fsanitize-add-pseudo-functions=undefined                       %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions=signed-integer-overflow -fsanitize-add-pseudo-functions                                 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-add-pseudo-functions=bool                       -fsanitize-add-pseudo-functions=undefined                       %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                                            -fsanitize-add-pseudo-functions=undefined -fsanitize-add-pseudo-functions=bool %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
+// CHECK-UNDEFINED-PSEUDO: "-fsanitize-add-pseudo-functions=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"
+
+// The trailing arguments (-fsanitize-add-pseudo-functions -fno-sanitize-add-pseudo-functions=signed-integer-overflow) take precedence
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                                            -fsanitize-add-pseudo-functions           -fno-sanitize-add-pseudo-functions=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                                            -fsanitize-add-pseudo-functions=undefined -fno-sanitize-add-pseudo-functions=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions                         -fsanitize-add-pseudo-functions           -fno-sanitize-add-pseudo-functions=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions                         -fsanitize-add-pseudo-functions=undefined -fno-sanitize-add-pseudo-functions=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions=signed-integer-overflow -fsanitize-add-pseudo-functions           -fno-sanitize-add-pseudo-functions=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions=signed-integer-overflow -fsanitize-add-pseudo-functions=undefined -fno-sanitize-add-pseudo-functions=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
+// CHECK-UNDEFINED-PSEUDO2: "-fsanitize-add-pseudo-functions=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"
+
+// The trailing -fno-sanitize-add-pseudo-functions takes precedence
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                           -fno-sanitize-add-pseudo-functions                                    %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO3
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                           -fno-sanitize-add-pseudo-functions=undefined                          %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO3
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                           -fno-sanitize-add-pseudo-functions           -fno-sanitize-add-pseudo-functions=bool %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO3
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                           -fno-sanitize-add-pseudo-functions=undefined -fno-sanitize-add-pseudo-functions=bool %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO3
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-add-pseudo-functions           -fno-sanitize-add-pseudo-functions                                    %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO3
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-add-pseudo-functions           -fno-sanitize-add-pseudo-functions=undefined                          %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO3
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-add-pseudo-functions=undefined -fno-sanitize-add-pseudo-functions                                    %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO3
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-add-pseudo-functions=undefined -fno-sanitize-add-pseudo-functions=undefined                          %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO3
+// CHECK-UNDEFINED-PSEUDO3: "-fsanitize-add-pseudo-functions"
+
+// The trailing arguments (-fsanitize-add-pseudo-functions -fno-sanitize-add-pseudo-functions=alignment,null) take precedence
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                                            -fsanitize-add-pseudo-functions           -fno-sanitize-add-pseudo-functions=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO4
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined                                                            -fsanitize-add-pseudo-functions=undefined -fno-sanitize-add-pseudo-functions=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO4
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions                         -fsanitize-add-pseudo-functions           -fno-sanitize-add-pseudo-functions=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO4
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-add-pseudo-functions                         -fsanitize-add-pseudo-functions=undefined -fno-sanitize-add-pseudo-functions=alignment,null %s -### 2>&1 | FileChe...
[truncated]

@thurstond thurstond requested a review from delcypher May 5, 2025 20:27
Copy link

github-actions bot commented May 5, 2025

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

Copy link
Contributor

@fmayer fmayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

def fsanitize_add_pseudo_functions_EQ
: CommaJoined<["-"], "fsanitize-add-pseudo-functions=">,
Group<f_clang_Group>,
HelpText<"Add pseudo-functions to checks for specified sanitizers">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit confusing because we currently only support one

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added ", if supported"

@@ -1228,7 +1228,10 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
SanitizerScope SanScope(this);

llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
if (ClArrayBoundsPseudoFn && CheckDI) {
if ((ClArrayBoundsPseudoFn ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add TODO to clean up mllvm flag

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be nice to make clear that SO_ArrayBounds here is the same as on line 1252
E.g. auto CurrentCheck = SO_ArrayBounds;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added CurrentCheckKind (there is already a Check variable that contains the instructions)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would drop the Current then for symmety

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -2533,6 +2533,31 @@ def fno_sanitize_merge_handlers : Flag<["-"], "fno-sanitize-merge">, Group<f_cla
Alias<fno_sanitize_merge_handlers_EQ>, AliasArgs<["all"]>,
Visibility<[ClangOption, CLOption]>,
HelpText<"Do not allow compiler to merge handlers for any sanitizers">;
def fsanitize_add_pseudo_functions_EQ
: CommaJoined<["-"], "fsanitize-add-pseudo-functions=">,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe -fsanitize-add-pseudo-functions -> -fsanitize-pseudo-function ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-fsanitize-pseudo-function is slightly ambiguous: it sounds like it is an option to sanitize any existing pseudo-functions, rather than sanitizers adding pseudo-functions

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

convention is -fsanitize-=, so I think it's not a problem.

But unless someone step in, either name is fine to me, your call.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with vitaly.

-fsanitize-trap doesn't sanitize traps either

def fno_sanitize_add_pseudo_functions_EQ
: CommaJoined<["-"], "fno-sanitize-add-pseudo-functions=">,
Group<f_clang_Group>,
HelpText<"Do not allow compiler to add pseudo-functions to checks for "
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc mention debug info?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated name

Copy link
Collaborator

@vitalybuka vitalybuka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I'd prefer shorted name, e.g.
e.g. we have -fsanitize-trap, not -fsanitize-report-with-trap

so -add- is unnecessary
plural functions as well
maybe pseudofn is good enough

of fakefn?

@vitalybuka
Copy link
Collaborator

In description ?

Florian1

@fmayer would be nicer for cross-linking

Copy link
Contributor

@delcypher delcypher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable. My main issue is the "add pseudo functions" name which isn't clear and isn't documented.

Group<f_clang_Group>,
HelpText<"Do not allow compiler to add pseudo-functions to checks for "
"specified sanitizers">;
def fsanitize_add_pseudo_functions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit. I don't think "add pseudo functions" is very helpful name. It's not clear at all what this means. Glancing at the implementation it looks like this is adding fake inline frames in the debug info with the name __ubsan_check_array_bounds. If the intention is to always use debug info as the implementation and to it will always annotate instrumentation a name like -fsanitize-annotate-debug-info might be more descriptive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation should also really explain this too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a much better name. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks all for the reviews and naming suggestions! I will rename it.

@thurstond thurstond changed the title [sanitizer] Add plumbing for -fsanitize-add-pseudo-functions and partly replace '-mllvm -array-bounds-pseudofn' [sanitizer] Add plumbing for -fsanitize-annotate-debug-info and partly replace '-mllvm -array-bounds-pseudofn' May 5, 2025
@thurstond
Copy link
Contributor Author

In description ?

Florian1

@fmayer would be nicer for cross-linking

Done

@@ -1228,7 +1228,10 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
SanitizerScope SanScope(this);

llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
if (ClArrayBoundsPseudoFn && CheckDI) {
if ((ClArrayBoundsPseudoFn ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would drop the Current then for symmety

Copy link
Contributor

@fmayer fmayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the fsanitize test is failing now

Copy link
Contributor

@delcypher delcypher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making changes. I have some very minor suggestions but I'll approve now and you can decide if it's worth making my suggested changes.

Comment on lines 2539 to 2540
HelpText<"Annotate checks with debug info for specified sanitizers, if "
"supported">;
Copy link
Contributor

@delcypher delcypher May 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can afford to be a bit more verbose in the help text. What about something like this?

Suggested change
HelpText<"Annotate checks with debug info for specified sanitizers, if "
"supported">;
HelpText<"Annotate sanitizer instrumentation with extra debug info for the specified sanitizers, if "
"supported">;

My thinking is

  • Replace checks with instrumentation because not all instrumentation is necessarily a check. E.g. I think stack poisoning is done with instrumentation and that's not a "check".
  • Say "extra debug info" since this is additional information on top of normal debug info
  • Add missing "the"

Comment on lines 2544 to 2545
HelpText<"Do not allow compiler to annotate checks with debug info for "
"specified sanitizers">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
HelpText<"Do not allow compiler to annotate checks with debug info for "
"specified sanitizers">;
HelpText<"Do not allow compiler to annotate checks with debug info for "
"the specified sanitizers">;

@@ -399,6 +399,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// (0.0 [default] to skip none, 1.0 to skip all).
SanitizerMaskCutoffs SanitizeSkipHotCutoffs;

/// Set of sanitizer checks that will be annotated with debug info.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Set of sanitizer checks that will be annotated with debug info.
/// Set of sanitizer checks that will be annotated with extra debug info.

@thurstond
Copy link
Contributor Author

Thanks for making changes. I have some very minor suggestions but I'll approve now and you can decide if it's worth making my suggested changes.

Thanks, I like your wording improvements! I've modified the HelpText and comment.

@thurstond
Copy link
Contributor Author

Seems like the fsanitize test is failing now

Fixed

@thurstond thurstond requested a review from fmayer May 7, 2025 01:50
@thurstond
Copy link
Contributor Author

YOLO

@thurstond thurstond merged commit 6a28d8c into llvm:main May 7, 2025
11 checks passed
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.

5 participants