[clang] 3823425 - [clang][Sema] Reject oversized arrays deduced from initializer lists (#226983)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 7 19:59:23 PDT 2026
Author: Kiroo (Chanung)
Date: 2026-10-08T02:59:18Z
New Revision: 3823425f88db2b02e9d9d3ab8a7f31b24bd0b961
URL: https://github.com/llvm/llvm-project/commit/3823425f88db2b02e9d9d3ab8a7f31b24bd0b961
DIFF: https://github.com/llvm/llvm-project/commit/3823425f88db2b02e9d9d3ab8a7f31b24bd0b961.diff
LOG: [clang][Sema] Reject oversized arrays deduced from initializer lists (#226983)
When an array's size is deduced from its initializer list, Sema skips
the array size check.
On x86_64,
```cpp
typedef char B[1ULL << 60];
B e[16]; // error: array is too large
B d[] = { {0}, {0}, /* ... 16 elements */ }; // accepted, sizeof(d) == 0
```
On i386,
```cpp
struct B { char c[1 << 30]; };
struct B e[5]; // error: array is too large
struct B d[] = { {{0}}, {{0}}, {{0}}, {{0}}, {{0}} }; // accepted, sizeof(d) == 1 GiB
```
GCC rejects both.
On targets with a 16-bit size_t (msp430, avr), the element counter is
also a signed 16-bit value, so it wraps after 32767 elements:
```cpp
char a[] = { 0, 0, /* ... 40000 elements */ }; // sizeof(a) == 32767
```
So the type no longer matches the initializer, clang crashes.
Fix this by counting the elements in 64 bits and checks the deduced size
against the maximum array size.
Added:
clang/test/Sema/array-init-list-too-large.c
Modified:
clang/docs/ReleaseNotes.md
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaInit.cpp
clang/lib/Sema/SemaType.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 7134d42865b37..aa6eaa0908fe5 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -611,6 +611,8 @@ features cannot lower the translation-unit ABI level;
keyword, such as when deferring the last statement of a block; when
used as the body of a conditional; or when it immediately precedes
a `break`/`continue` statement or a `return` with no argument.
+
+- Clang now diagnoses arrays whose size is deduced from an initializer list when they exceed the maximum object size
### Improvements to Clang's time-trace
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7fbcc4aae7d6c..2c4986d56eede 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15363,6 +15363,12 @@ class Sema final : public SemaBase {
QualType BuildArrayType(QualType T, ArraySizeModifier ASM, Expr *ArraySize,
unsigned Quals, SourceRange Brackets,
DeclarationName Entity);
+
+ /// Diagnose an array of \p NumElements elements of type \p ElementType
+ /// that is too large. Returns true if a diagnostic was emitted.
+ bool checkArrayTooLarge(QualType ElementType, const llvm::APSInt &NumElements,
+ SourceLocation Loc,
+ SourceRange Range = SourceRange());
QualType BuildVectorType(QualType T, Expr *VecSize, SourceLocation AttrLoc);
/// Build an ext-vector type.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 99da07d567c69..d9bd060f7a0bf 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2414,17 +2414,9 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
<< (*ArraySize)->getSourceRange());
}
- if (!AllocType->isDependentType()) {
- unsigned ActiveSizeBits =
- ConstantArrayType::getNumAddressingBits(Context, AllocType, *Value);
- if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
- return ExprError(
- Diag((*ArraySize)->getBeginLoc(), diag::err_array_too_large)
- << toString(*Value, 10, Value->isSigned(),
- /*formatAsCLiteral=*/false, /*UpperCase=*/false,
- /*InsertSeparators=*/true)
- << (*ArraySize)->getSourceRange());
- }
+ if (checkArrayTooLarge(AllocType, *Value, (*ArraySize)->getBeginLoc(),
+ (*ArraySize)->getSourceRange()))
+ return ExprError();
KnownArraySize = Value->getZExtValue();
} else if (TypeIdParens.isValid()) {
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 3f30e94aa8976..d2aa8691102aa 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -2208,6 +2208,10 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
return;
}
+ // Count in 64 bits so that the index cannot wrap with a narrow size_t.
+ if (elementIndex.getBitWidth() < 64)
+ elementIndex = elementIndex.extend(64);
+
// We might know the maximum number of elements in advance.
llvm::APSInt maxElements(elementIndex.getBitWidth(),
elementIndex.isUnsigned());
@@ -2293,6 +2297,12 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
SemaRef.Diag(IList->getBeginLoc(), diag::ext_typecheck_zero_array_size);
}
+ if (SemaRef.checkArrayTooLarge(elementType, maxElements,
+ IList->getBeginLoc())) {
+ hadError = true;
+ return;
+ }
+
DeclType = SemaRef.Context.getConstantArrayType(
elementType, maxElements, nullptr, ArraySizeModifier::Normal, 0);
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 202bd486321f9..1cb96b556971a 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2090,6 +2090,26 @@ bool Sema::checkArrayElementAlignment(QualType EltTy, SourceLocation Loc) {
return false;
}
+bool Sema::checkArrayTooLarge(QualType ElementType,
+ const llvm::APSInt &NumElements,
+ SourceLocation Loc, SourceRange Range) {
+ unsigned ActiveSizeBits = NumElements.getActiveBits();
+ if (!ElementType->isDependentType() && !ElementType->isIncompleteType() &&
+ !ElementType->isUndeducedType() && ElementType->isConstantSizeType())
+ ActiveSizeBits =
+ std::max(ActiveSizeBits, ConstantArrayType::getNumAddressingBits(
+ Context, ElementType, NumElements));
+ if (ActiveSizeBits <= ConstantArrayType::getMaxSizeBits(Context))
+ return false;
+
+ Diag(Loc, diag::err_array_too_large)
+ << toString(NumElements, 10, NumElements.isSigned(),
+ /*formatAsCLiteral=*/false, /*UpperCase=*/false,
+ /*InsertSeparators=*/true)
+ << Range;
+ return true;
+}
+
QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM,
Expr *ArraySize, unsigned Quals,
SourceRange Brackets, DeclarationName Entity) {
@@ -2316,20 +2336,9 @@ QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM,
return QualType();
}
- // Is the array too large?
- unsigned ActiveSizeBits =
- (!T->isDependentType() && !T->isVariablyModifiedType() &&
- !T->isIncompleteType() && !T->isUndeducedType())
- ? ConstantArrayType::getNumAddressingBits(Context, T, ConstVal)
- : ConstVal.getActiveBits();
- if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
- Diag(ArraySize->getBeginLoc(), diag::err_array_too_large)
- << toString(ConstVal, 10, ConstVal.isSigned(),
- /*formatAsCLiteral=*/false, /*UpperCase=*/false,
- /*InsertSeparators=*/true)
- << ArraySize->getSourceRange();
+ if (checkArrayTooLarge(T, ConstVal, ArraySize->getBeginLoc(),
+ ArraySize->getSourceRange()))
return QualType();
- }
T = Context.getConstantArrayType(T, ConstVal, ArraySize, ASM,
IndexTypeQuals);
diff --git a/clang/test/Sema/array-init-list-too-large.c b/clang/test/Sema/array-init-list-too-large.c
new file mode 100644
index 0000000000000..4b5a5d6f01edf
--- /dev/null
+++ b/clang/test/Sema/array-init-list-too-large.c
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple msp430 -fsyntax-only -verify=expected,size16 %s
+// RUN: %clang_cc1 -triple avr -fsyntax-only -verify=expected,size16 %s
+// RUN: %clang_cc1 -triple msp430 -fsyntax-only -verify=expected,size16 -x c++ %s
+
+#if __SIZEOF_SIZE_T__ == 8
+// Array sizes are limited to 61 bits.
+typedef char Quarter[1ULL << 59];
+#else
+typedef char Quarter[__SIZE_MAX__ / 4 + 1];
+#endif
+Quarter fits[] = {{0}, {0}, {0}};
+Quarter explicit_bound[4]; // expected-error {{array is too large (4 elements)}}
+Quarter deduced_bound[] = {{0}, {0}, {0}, {0}}; // expected-error {{array is too large (4 elements)}}
+
+#define X2(x) x, x
+#define X4(x) X2(x), X2(x)
+#define X8(x) X4(x), X4(x)
+#define X16(x) X8(x), X8(x)
+#define X32(x) X16(x), X16(x)
+#define X64(x) X32(x), X32(x)
+#define X128(x) X64(x), X64(x)
+#define X256(x) X128(x), X128(x)
+#define X512(x) X256(x), X256(x)
+#define X1024(x) X512(x), X512(x)
+#define X2048(x) X1024(x), X1024(x)
+#define X4096(x) X2048(x), X2048(x)
+#define X8192(x) X4096(x), X4096(x)
+#define X16384(x) X8192(x), X8192(x)
+#define X32768(x) X16384(x), X16384(x)
+
+char past_int16_max[] = {X32768(0), 0};
+_Static_assert(sizeof(past_int16_max) == 32769, "");
+
+char past_size16_max[] = {X32768(0), X32768(0)}; // size16-error {{array is too large (65'536 elements)}}
+
+struct E {};
+struct E zero_sized[] = {X32768({}), X32768({})}; // size16-error {{array is too large (65'536 elements)}}
+
+#ifndef __cplusplus
+void pointers_to_vla(int n) {
+ int (*explicit_ptrs[32768])[n]; // size16-error {{array is too large (32'768 elements)}}
+ int (*deduced_ptrs[])[n] = {X32768(0)}; // size16-error {{array is too large (32'768 elements)}}
+}
+#endif
+
+#ifdef __cplusplus
+template <typename T> void deduced_in_template() {
+ static T a[] = {{0}, {0}, {0}, {0}}; // expected-error {{array is too large (4 elements)}}
+}
+template void deduced_in_template<Quarter>(); // expected-note {{in instantiation of}}
+#endif
More information about the cfe-commits
mailing list