Skip to content

Conversation

Mr-Anyone
Copy link
Contributor

Check for missing VLA size expressions (e.g. in int a[*][10]) before evaluation to avoid crashes in _Countof and constant expression checks.

fixes #152826

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:bytecode Issues for the clang bytecode constexpr interpreter labels Aug 20, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 20, 2025

@llvm/pr-subscribers-clang

Author: Vincent (Mr-Anyone)

Changes

Check for missing VLA size expressions (e.g. in int a[*][10]) before evaluation to avoid crashes in _Countof and constant expression checks.

fixes #152826


Full diff: https://github.com/llvm/llvm-project/pull/154627.diff

4 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/lib/AST/ByteCode/Compiler.cpp (+3-1)
  • (modified) clang/lib/AST/ExprConstant.cpp (+11-1)
  • (added) clang/test/Sema/gh152826.c (+6)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e88d68fa99664..df738db771e33 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -200,6 +200,8 @@ Bug Fixes in This Version
 -------------------------
 - Fix a crash when marco name is empty in ``#pragma push_macro("")`` or
   ``#pragma pop_macro("")``. (#GH149762).
+- Fix a crash in variable length array (e.g. int a[*]) function parameter type 
+  being used in `_Countof` expression. (#GH152826)
 - `-Wunreachable-code`` now diagnoses tautological or contradictory
   comparisons such as ``x != 0 || x != 1.0`` and ``x == 0 && x == 1.0`` on
   targets that treat ``_Float16``/``__fp16`` as native scalar types. Previously
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index e3235d34e230e..7881afc4bb6f5 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2248,7 +2248,9 @@ bool Compiler<Emitter>::VisitUnaryExprOrTypeTraitExpr(
     assert(VAT);
     if (VAT->getElementType()->isArrayType()) {
       std::optional<APSInt> Res =
-          VAT->getSizeExpr()->getIntegerConstantExpr(ASTCtx);
+          VAT->getSizeExpr()
+              ? VAT->getSizeExpr()->getIntegerConstantExpr(ASTCtx)
+              : std::nullopt;
       if (Res) {
         if (DiscardResult)
           return true;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 9c87a88899647..1d939cf9655d4 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15345,6 +15345,13 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
     const auto *VAT = Info.Ctx.getAsVariableArrayType(Ty);
     assert(VAT);
     if (VAT->getElementType()->isArrayType()) {
+      // Variable array size expression could be missing (e.g. int a[*][10]) In
+      // that case, it can't be a constant expression
+      if (!VAT->getSizeExpr()) {
+        Info.FFDiag(E->getBeginLoc());
+        return false;
+      }
+
       std::optional<APSInt> Res =
           VAT->getSizeExpr()->getIntegerConstantExpr(Info.Ctx);
       if (Res) {
@@ -17867,7 +17874,10 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
         // it is an ICE or not.
         const auto *VAT = Ctx.getAsVariableArrayType(ArgTy);
         if (VAT->getElementType()->isArrayType())
-          return CheckICE(VAT->getSizeExpr(), Ctx);
+          // Variable array size expression could be missing (e.g. int a[*][10])
+          // In that case, it can't be a constant expression
+          return VAT->getSizeExpr() ? CheckICE(VAT->getSizeExpr(), Ctx)
+                                    : ICEDiag(IK_NotICE, E->getBeginLoc());
 
         // Otherwise, this is a regular VLA, which is definitely not an ICE.
         return ICEDiag(IK_NotICE, E->getBeginLoc());
diff --git a/clang/test/Sema/gh152826.c b/clang/test/Sema/gh152826.c
new file mode 100644
index 0000000000000..a7d5f0138ad5d
--- /dev/null
+++ b/clang/test/Sema/gh152826.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -std=c2y -verify %s
+// RUN: %clang_cc1 -std=c2y -verify -fexperimental-new-constant-interpreter %s
+// expected-no-diagnostics
+
+void gh152826(char (*a)[*][5], int (*x)[_Countof (*a)]);
+void more_likely_in_practice(unsigned long size_one, int (*a)[*][5], int b[_Countof(*a)]);

// RUN: %clang_cc1 -std=c2y -verify -fexperimental-new-constant-interpreter %s
// expected-no-diagnostics

void gh152826(char (*a)[*][5], int (*x)[_Countof (*a)]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test for e.g.

void f(int x[*][1][*][2][*][*][3][*], int q[_Countof(*x)]);

to make sure we handle nested VLAs properly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also add a codegen test to verify that we emit the correct LLVM IR to runtime evaluate the _Countof

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to make sure we handle nested VLAs properly.

Sure.

We should also add a codegen test to verify that we emit the correct LLVM IR to runtime evaluate the _Countof

I am not sure how you would go about doing that. Because [*] seems to only appear in function prototypes and not definitions. godbolt

C23 6.7.7.4: If the function declarator is not part of a definition of that function, parameters [...] may use the [*] notation in their sequences of declarator specifiers to specify variable length array types.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there was a way we could end up having to evaluate here, but now I think you're right, that doesn't seem to be possible. So nevermind! :-)

Comment on lines 203 to 204
- Fix a crash in variable length array (e.g. int a[*]) function parameter type
being used in `_Countof` expression. (#GH152826)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Fix a crash in variable length array (e.g. int a[*]) function parameter type
being used in `_Countof` expression. (#GH152826)
- Fix a crash in variable length array (e.g. ``int a[*]``) function parameter type
being used in ``_Countof`` expression. (#GH152826)

Also, RST...

@Sirraide Sirraide requested a review from AaronBallman August 21, 2025 03:39
@@ -15345,6 +15345,13 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
const auto *VAT = Info.Ctx.getAsVariableArrayType(Ty);
assert(VAT);
if (VAT->getElementType()->isArrayType()) {
// Variable array size expression could be missing (e.g. int a[*][10]) In
// that case, it can't be a constant expression
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// that case, it can't be a constant expression
// that case, it can't be a constant expression.

// RUN: %clang_cc1 -std=c2y -verify -fexperimental-new-constant-interpreter %s
// expected-no-diagnostics

void gh152826(char (*a)[*][5], int (*x)[_Countof (*a)]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also add a codegen test to verify that we emit the correct LLVM IR to runtime evaluate the _Countof

@Mr-Anyone Mr-Anyone force-pushed the fix_ice_countof branch 2 times, most recently from a2064bc to cd9e0fb Compare August 21, 2025 19:24
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

// RUN: %clang_cc1 -std=c2y -verify -fexperimental-new-constant-interpreter %s
// expected-no-diagnostics

void gh152826(char (*a)[*][5], int (*x)[_Countof (*a)]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there was a way we could end up having to evaluate here, but now I think you're right, that doesn't seem to be possible. So nevermind! :-)

@@ -222,6 +222,8 @@ Bug Fixes in This Version
-------------------------
- Fix a crash when marco name is empty in ``#pragma push_macro("")`` or
``#pragma pop_macro("")``. (#GH149762).
- Fix a crash in variable length array (e.g. ``int a[*]``) function parameter type
being used in ``_Countof`` expression. (#GH152826)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
being used in ``_Countof`` expression. (#GH152826)
being used in ``_Countof`` expression. (#GH152826).

// RUN: %clang_cc1 -std=c2y -verify -fexperimental-new-constant-interpreter %s
// expected-no-diagnostics

void gh152826(char (*a)[*][5], int (*x)[_Countof (*a)]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void gh152826(char (*a)[*][5], int (*x)[_Countof (*a)]);
void gh152826(char (*a)[*][5], int (*x)[_Countof(*a)]);

Check for missing VLA size expressions (e.g. in int a[*][10])
before evaluation to avoid crashes in _Countof and constant
expression checks.

fixes llvm#152826
@Mr-Anyone
Copy link
Contributor Author

LGTM!

Thanks for the review. I don't have merge access. It would be nice if you can merge this for me. Thanks

@Sirraide Sirraide merged commit fefdb49 into llvm:main Aug 25, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:bytecode Issues for the clang bytecode constexpr interpreter clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Crash] clang: error: unable to execute command: Segmentation fault (core dumped); clang: error: clang frontend command failed with exit code 139
5 participants