https://github.com/zlfn updated https://github.com/llvm/llvm-project/pull/226983
>From c6ad057f6b28a3d78338e312ee6bd4d538574292 Mon Sep 17 00:00:00 2001 From: zlfn <[email protected]> Date: Mon, 28 Sep 2026 22:19:59 +0900 Subject: [PATCH 1/5] [clang][Sema] Reject oversized arrays deduced from initializer lists An array sized by its initializer list skipped the size check that arrays with an explicit bound go through. On targets with a 16-bit size_t, the element counter also wrapped and truncated the size. Count the elements in 64 bits and apply the same size limit. --- clang/docs/ReleaseNotes.md | 2 ++ clang/lib/Sema/SemaInit.cpp | 16 +++++++++ clang/test/Sema/array-init-list-too-large.c | 37 +++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 clang/test/Sema/array-init-list-too-large.c diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 3c6acf353f93f..d713fae8f3f1d 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -561,6 +561,8 @@ features cannot lower the translation-unit ABI level; - Fixed a bug where a bit-field accessed as the result of a statement expression (e.g. `({ s.b; })`) was not subject to integer promotion, unlike an ordinary bit-field access. (#GH221542) +- Clang now diagnoses arrays whose size is deduced from an initializer list + when they exceed the maximum object size. #### Bug Fixes to Compiler Builtins diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 3f30e94aa8976..99e5517720f90 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,18 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, SemaRef.Diag(IList->getBeginLoc(), diag::ext_typecheck_zero_array_size); } + if (!elementType->isDependentType() && !elementType->isIncompleteType() && + ConstantArrayType::getNumAddressingBits(SemaRef.Context, elementType, + maxElements) > + ConstantArrayType::getMaxSizeBits(SemaRef.Context)) { + SemaRef.Diag(IList->getBeginLoc(), diag::err_array_too_large) + << toString(maxElements, 10, maxElements.isSigned(), + /*formatAsCLiteral=*/false, /*UpperCase=*/false, + /*InsertSeparators=*/true); + hadError = true; + return; + } + DeclType = SemaRef.Context.getConstantArrayType( elementType, maxElements, nullptr, ArraySizeModifier::Normal, 0); } 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..705eed7ee009e --- /dev/null +++ b/clang/test/Sema/array-init-list-too-large.c @@ -0,0 +1,37 @@ +// 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 + +typedef char Quarter[__SIZE_MAX__ / 4 + 1]; +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)}} + +#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 >From 2cd8ea9d8f6901361355c428ca594714d485b3a1 Mon Sep 17 00:00:00 2001 From: zlfn <[email protected]> Date: Mon, 28 Sep 2026 22:33:58 +0900 Subject: [PATCH 2/5] Check the element count for zero-sized elements --- clang/lib/Sema/SemaInit.cpp | 10 ++++++---- clang/test/Sema/array-init-list-too-large.c | 3 +++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 99e5517720f90..3667ff280cc6e 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2297,10 +2297,12 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, SemaRef.Diag(IList->getBeginLoc(), diag::ext_typecheck_zero_array_size); } - if (!elementType->isDependentType() && !elementType->isIncompleteType() && - ConstantArrayType::getNumAddressingBits(SemaRef.Context, elementType, - maxElements) > - ConstantArrayType::getMaxSizeBits(SemaRef.Context)) { + unsigned ActiveSizeBits = maxElements.getActiveBits(); + if (!elementType->isDependentType() && !elementType->isIncompleteType()) + ActiveSizeBits = std::max(ActiveSizeBits, + ConstantArrayType::getNumAddressingBits( + SemaRef.Context, elementType, maxElements)); + if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(SemaRef.Context)) { SemaRef.Diag(IList->getBeginLoc(), diag::err_array_too_large) << toString(maxElements, 10, maxElements.isSigned(), /*formatAsCLiteral=*/false, /*UpperCase=*/false, diff --git a/clang/test/Sema/array-init-list-too-large.c b/clang/test/Sema/array-init-list-too-large.c index 705eed7ee009e..74a235a8fbd7f 100644 --- a/clang/test/Sema/array-init-list-too-large.c +++ b/clang/test/Sema/array-init-list-too-large.c @@ -29,6 +29,9 @@ _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)}} + #ifdef __cplusplus template <typename T> void deduced_in_template() { static T a[] = {{0}, {0}, {0}, {0}}; // expected-error {{array is too large (4 elements)}} >From a9fe1b0ccd09dccb006d4a4c101f04f2148d1d91 Mon Sep 17 00:00:00 2001 From: zlfn <[email protected]> Date: Mon, 28 Sep 2026 23:15:56 +0900 Subject: [PATCH 3/5] Test x86_64 as well --- clang/test/Sema/array-init-list-too-large.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/clang/test/Sema/array-init-list-too-large.c b/clang/test/Sema/array-init-list-too-large.c index 74a235a8fbd7f..08a0aba154c04 100644 --- a/clang/test/Sema/array-init-list-too-large.c +++ b/clang/test/Sema/array-init-list-too-large.c @@ -1,9 +1,15 @@ +// 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)}} >From 395a4619533025777b46af35eff779abb6ba8dbf Mon Sep 17 00:00:00 2001 From: zlfn <[email protected]> Date: Tue, 29 Sep 2026 02:33:58 +0900 Subject: [PATCH 4/5] Factor out the array size check --- clang/include/clang/Sema/Sema.h | 6 ++++++ clang/lib/Sema/SemaExprCXX.cpp | 14 +++---------- clang/lib/Sema/SemaInit.cpp | 12 ++--------- clang/lib/Sema/SemaType.cpp | 36 +++++++++++++++++++++------------ 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index eb3b908351448..f4047558d747c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -15313,6 +15313,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 deb7bdd09fdc7..d92ee2f7506de 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2406,17 +2406,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 3667ff280cc6e..d2aa8691102aa 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2297,16 +2297,8 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, SemaRef.Diag(IList->getBeginLoc(), diag::ext_typecheck_zero_array_size); } - unsigned ActiveSizeBits = maxElements.getActiveBits(); - if (!elementType->isDependentType() && !elementType->isIncompleteType()) - ActiveSizeBits = std::max(ActiveSizeBits, - ConstantArrayType::getNumAddressingBits( - SemaRef.Context, elementType, maxElements)); - if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(SemaRef.Context)) { - SemaRef.Diag(IList->getBeginLoc(), diag::err_array_too_large) - << toString(maxElements, 10, maxElements.isSigned(), - /*formatAsCLiteral=*/false, /*UpperCase=*/false, - /*InsertSeparators=*/true); + if (SemaRef.checkArrayTooLarge(elementType, maxElements, + IList->getBeginLoc())) { hadError = true; return; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index b5c71d72a23ff..543d2838c74f2 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2084,6 +2084,27 @@ 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->isVariablyModifiedType() && + !ElementType->isIncompleteType() && !ElementType->isUndeducedType()) + 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) { @@ -2307,20 +2328,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, Quals); } >From 09fdb7f9c4e9f3ad8a95929fad28c3b621f43fbc Mon Sep 17 00:00:00 2001 From: zlfn <[email protected]> Date: Tue, 29 Sep 2026 02:39:42 +0900 Subject: [PATCH 5/5] Check the size of arrays of pointers to VLAs --- clang/lib/Sema/SemaType.cpp | 5 ++--- clang/test/Sema/array-init-list-too-large.c | 7 +++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 543d2838c74f2..be7d377624f51 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2088,9 +2088,8 @@ bool Sema::checkArrayTooLarge(QualType ElementType, const llvm::APSInt &NumElements, SourceLocation Loc, SourceRange Range) { unsigned ActiveSizeBits = NumElements.getActiveBits(); - if (!ElementType->isDependentType() && - !ElementType->isVariablyModifiedType() && - !ElementType->isIncompleteType() && !ElementType->isUndeducedType()) + if (!ElementType->isDependentType() && !ElementType->isIncompleteType() && + !ElementType->isUndeducedType() && ElementType->isConstantSizeType()) ActiveSizeBits = std::max(ActiveSizeBits, ConstantArrayType::getNumAddressingBits( Context, ElementType, NumElements)); diff --git a/clang/test/Sema/array-init-list-too-large.c b/clang/test/Sema/array-init-list-too-large.c index 08a0aba154c04..4b5a5d6f01edf 100644 --- a/clang/test/Sema/array-init-list-too-large.c +++ b/clang/test/Sema/array-init-list-too-large.c @@ -38,6 +38,13 @@ char past_size16_max[] = {X32768(0), X32768(0)}; // size16-error {{array is too 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)}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
