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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
