[clang] [sanitizer] [clang] Introduce fsanitize-bounds-strict-flex-arrays (PR #126163)

via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 6 16:51:59 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-clang

Author: Florian Mayer (fmayer)

<details>
<summary>Changes</summary>

This is the control the definition of flex arrays separately for bounds
sanitizer than for the codegen.


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


7 Files Affected:

- (modified) clang/include/clang/Basic/LangOptions.def (+3) 
- (modified) clang/include/clang/Basic/LangOptions.h (+13) 
- (modified) clang/include/clang/Driver/Options.td (+15) 
- (modified) clang/lib/CodeGen/CGExpr.cpp (+31-3) 
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+1) 
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+2) 
- (modified) clang/test/CodeGen/bounds-checking-fam.c (+10) 


``````````diff
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index cb55f09acc076c..590237eb4f40ba 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -481,6 +481,9 @@ LANGOPT(RawStringLiterals, 1, 1, "Enable or disable raw string literals")
 ENUM_LANGOPT(StrictFlexArraysLevel, StrictFlexArraysLevelKind, 2,
              StrictFlexArraysLevelKind::Default,
              "Rely on strict definition of flexible arrays")
+ENUM_LANGOPT(ArrayBoundsStrictFlexArraysLevel, ArrayBoundsStrictFlexArraysLevelKind, 3,
+             ArrayBoundsStrictFlexArraysLevelKind::None,
+             "Definition of flexible arrays for bounds checks")
 
 COMPATIBLE_VALUE_LANGOPT(MaxTokens, 32, 0, "Max number of tokens per TU or 0")
 
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index f58a719a45a84d..597165dfc24044 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -444,6 +444,19 @@ class LangOptionsBase {
     IncompleteOnly = 3,
   };
 
+  enum class ArrayBoundsStrictFlexArraysLevelKind {
+    // Use same StrictFlexArrayLevel as compiler.
+    None = 0,
+    /// Any trailing array member is a FAM.
+    Default = 1,
+    /// Any trailing array member of undefined, 0, or 1 size is a FAM.
+    OneZeroOrIncomplete = 2,
+    /// Any trailing array member of undefined or 0 size is a FAM.
+    ZeroOrIncomplete = 3,
+    /// Any trailing array member of undefined size is a FAM.
+    IncompleteOnly = 4,
+  };
+
   /// Controls the various implementations for complex multiplication and
   // division.
   enum ComplexRangeKind {
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 77ca2d2aac31be..3ae768206a34b7 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1533,6 +1533,21 @@ def fstrict_flex_arrays_EQ : Joined<["-"], "fstrict-flex-arrays=">, Group<f_Grou
   NormalizedValues<["Default", "OneZeroOrIncomplete", "ZeroOrIncomplete", "IncompleteOnly"]>,
   HelpText<"Enable optimizations based on the strict definition of flexible arrays">,
   MarshallingInfoEnum<LangOpts<"StrictFlexArraysLevel">, "Default">;
+// We might want a different (generally stricter) definition of flexible arrays
+// for sanitization than for the codegen.
+def fsanitize_array_bounds_strict_flex_arrays_EQ
+    : Joined<["-"], "fsanitize-bounds-strict-flex-arrays=">,
+      Group<f_Group>,
+      MetaVarName<"<n>">,
+      Values<"none,0,1,2,3">,
+      LangOpts<"ArrayBoundsStrictFlexArraysLevel">,
+      Visibility<[ClangOption, CC1Option]>,
+      NormalizedValuesScope<
+          "LangOptions::ArrayBoundsStrictFlexArraysLevelKind">,
+      NormalizedValues<["None", "Default", "OneZeroOrIncomplete",
+                        "ZeroOrIncomplete", "IncompleteOnly"]>,
+      HelpText<"Set definition of flexible arrays for bounds checks">,
+      MarshallingInfoEnum<LangOpts<"ArrayBoundsStrictFlexArraysLevel">, "None">;
 defm apple_pragma_pack : BoolFOption<"apple-pragma-pack",
   LangOpts<"ApplePragmaPack">, DefaultFalse,
   PosFlag<SetTrue, [], [ClangOption, CC1Option],
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 1e233c42c8782d..d2540d209f23d9 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -31,6 +31,7 @@
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/CodeGenOptions.h"
+#include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
@@ -1192,13 +1193,40 @@ llvm::Value *CodeGenFunction::EmitLoadOfCountedByField(
   return nullptr;
 }
 
+LangOptions::StrictFlexArraysLevelKind
+CodeGenFunction::effectiveArrayBoundsFlexArraysLevel() {
+  using StrictFlexArraysLevelKind = LangOptions::StrictFlexArraysLevelKind;
+  using ArrayBoundsStrictFlexArraysLevelKind =
+      LangOptions::ArrayBoundsStrictFlexArraysLevelKind;
+  StrictFlexArraysLevelKind StrictFlexArraysLevel;
+  switch (getLangOpts().getArrayBoundsStrictFlexArraysLevel()) {
+  case ArrayBoundsStrictFlexArraysLevelKind::Default:
+    StrictFlexArraysLevel = StrictFlexArraysLevelKind::Default;
+    break;
+  case ArrayBoundsStrictFlexArraysLevelKind::OneZeroOrIncomplete:
+    StrictFlexArraysLevel = StrictFlexArraysLevelKind::OneZeroOrIncomplete;
+    break;
+  case ArrayBoundsStrictFlexArraysLevelKind::ZeroOrIncomplete:
+    StrictFlexArraysLevel = StrictFlexArraysLevelKind::ZeroOrIncomplete;
+    break;
+  case ArrayBoundsStrictFlexArraysLevelKind::IncompleteOnly:
+    StrictFlexArraysLevel = StrictFlexArraysLevelKind::IncompleteOnly;
+    break;
+  case ArrayBoundsStrictFlexArraysLevelKind::None:
+    StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel();
+    break;
+  }
+  return StrictFlexArraysLevel;
+}
+
 void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
                                       llvm::Value *Index, QualType IndexType,
                                       bool Accessed) {
   assert(SanOpts.has(SanitizerKind::ArrayBounds) &&
          "should not be called unless adding bounds checks");
-  const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
-      getLangOpts().getStrictFlexArraysLevel();
+  LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
+      effectiveArrayBoundsFlexArraysLevel();
+
   QualType IndexedType;
   llvm::Value *Bound =
       getArrayIndexingBound(*this, Base, IndexedType, StrictFlexArraysLevel);
@@ -4383,7 +4411,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
       // i.e. "a.b.count", so we shouldn't need the full force of EmitLValue or
       // similar to emit the correct GEP.
       const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
-          getLangOpts().getStrictFlexArraysLevel();
+          effectiveArrayBoundsFlexArraysLevel();
 
       if (const auto *ME = dyn_cast<MemberExpr>(Array);
           ME &&
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index e7a5100a9fa294..62067c8bd9a802 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3315,6 +3315,7 @@ class CodeGenFunction : public CodeGenTypeCache {
                      SanitizerSet SkippedChecks = SanitizerSet(),
                      llvm::Value *ArraySize = nullptr);
 
+  LangOptions::StrictFlexArraysLevelKind effectiveArrayBoundsFlexArraysLevel();
   /// Emit a check that \p Base points into an array object, which
   /// we can access at index \p Index. \p Accessed should be \c false if we
   /// this expression is used as an lvalue, for instance in "&Arr[Idx]".
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index c0891d46b0a62c..ce937adcb94600 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6976,6 +6976,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                   options::OPT_fno_unroll_loops);
 
   Args.AddLastArg(CmdArgs, options::OPT_fstrict_flex_arrays_EQ);
+  Args.AddLastArg(CmdArgs,
+                  options::OPT_fsanitize_array_bounds_strict_flex_arrays_EQ);
 
   Args.AddLastArg(CmdArgs, options::OPT_pthread);
 
diff --git a/clang/test/CodeGen/bounds-checking-fam.c b/clang/test/CodeGen/bounds-checking-fam.c
index ae211c49ca1f55..dcfe99fa6ff6d9 100644
--- a/clang/test/CodeGen/bounds-checking-fam.c
+++ b/clang/test/CodeGen/bounds-checking-fam.c
@@ -7,6 +7,16 @@
 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=2 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2,CXX
 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=3 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3
 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=3 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3,CXX
+
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize-bounds-strict-flex-arrays=0 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-0,CXX,CXX-STRICT-0
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize-bounds-strict-flex-arrays=0 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-0
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize-bounds-strict-flex-arrays=1 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-1
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize-bounds-strict-flex-arrays=1 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-1,CXX
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize-bounds-strict-flex-arrays=2 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize-bounds-strict-flex-arrays=2 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2,CXX
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize-bounds-strict-flex-arrays=3 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize-bounds-strict-flex-arrays=3 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3,CXX
+
 // Before flexible array member was added to C99, many projects use a
 // one-element array as the last member of a structure as an alternative.
 // E.g. https://github.com/python/cpython/issues/84301

``````````

</details>


https://github.com/llvm/llvm-project/pull/126163


More information about the cfe-commits mailing list