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

Reply via email to