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

Reply via email to