[clang] [sanitizer] [clang] Introduce fsanitize-bounds-strict-flex-arrays (PR #126163)
Florian Mayer via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 7 17:15:19 PST 2025
https://github.com/fmayer updated https://github.com/llvm/llvm-project/pull/126163
>From e9f2dbecb2b4836100a565b4c741fc3425d08966 Mon Sep 17 00:00:00 2001
From: Florian Mayer <fmayer at google.com>
Date: Thu, 6 Feb 2025 16:50:02 -0800
Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
=?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.4
---
clang/include/clang/Basic/LangOptions.def | 3 ++
clang/include/clang/Basic/LangOptions.h | 13 +++++++++
clang/include/clang/Driver/Options.td | 15 ++++++++++
clang/lib/CodeGen/CGExpr.cpp | 34 +++++++++++++++++++++--
clang/lib/CodeGen/CodeGenFunction.h | 1 +
clang/lib/Driver/ToolChains/Clang.cpp | 2 ++
clang/test/CodeGen/bounds-checking-fam.c | 10 +++++++
7 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index cb55f09acc076cf..590237eb4f40baf 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 f58a719a45a84de..597165dfc24044c 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 77ca2d2aac31be1..3ae768206a34b71 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 1e233c42c8782df..d2540d209f23d9c 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 e7a5100a9fa2946..62067c8bd9a802b 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 c0891d46b0a62cd..ce937adcb946004 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 ae211c49ca1f552..dcfe99fa6ff6d91 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
>From cde09da532846cce988a6ce68b16b441e369db11 Mon Sep 17 00:00:00 2001
From: Florian Mayer <fmayer at google.com>
Date: Fri, 7 Feb 2025 17:15:05 -0800
Subject: [PATCH 2/2] nit
Created using spr 1.3.4
---
clang/lib/CodeGen/CGExpr.cpp | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index d2540d209f23d9c..3f04d0393bf9c6e 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1198,25 +1198,18 @@ CodeGenFunction::effectiveArrayBoundsFlexArraysLevel() {
using StrictFlexArraysLevelKind = LangOptions::StrictFlexArraysLevelKind;
using ArrayBoundsStrictFlexArraysLevelKind =
LangOptions::ArrayBoundsStrictFlexArraysLevelKind;
- StrictFlexArraysLevelKind StrictFlexArraysLevel;
switch (getLangOpts().getArrayBoundsStrictFlexArraysLevel()) {
case ArrayBoundsStrictFlexArraysLevelKind::Default:
- StrictFlexArraysLevel = StrictFlexArraysLevelKind::Default;
- break;
+ return StrictFlexArraysLevelKind::Default;
case ArrayBoundsStrictFlexArraysLevelKind::OneZeroOrIncomplete:
- StrictFlexArraysLevel = StrictFlexArraysLevelKind::OneZeroOrIncomplete;
- break;
+ return StrictFlexArraysLevelKind::OneZeroOrIncomplete;
case ArrayBoundsStrictFlexArraysLevelKind::ZeroOrIncomplete:
- StrictFlexArraysLevel = StrictFlexArraysLevelKind::ZeroOrIncomplete;
- break;
+ return StrictFlexArraysLevelKind::ZeroOrIncomplete;
case ArrayBoundsStrictFlexArraysLevelKind::IncompleteOnly:
- StrictFlexArraysLevel = StrictFlexArraysLevelKind::IncompleteOnly;
- break;
+ return StrictFlexArraysLevelKind::IncompleteOnly;
case ArrayBoundsStrictFlexArraysLevelKind::None:
- StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel();
- break;
+ return getLangOpts().getStrictFlexArraysLevel();
}
- return StrictFlexArraysLevel;
}
void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
More information about the cfe-commits
mailing list