https://github.com/unterumarmung updated 
https://github.com/llvm/llvm-project/pull/201706

>From e4842b6b99edfe46e2a2047ccc20d9f274b4dbd4 Mon Sep 17 00:00:00 2001
From: Daniil Dudkin <[email protected]>
Date: Wed, 3 Jun 2026 21:37:16 +0300
Subject: [PATCH] [clang] Avoid stack exhaustion in recursive constexpr calls

Guard constexpr function-call evaluation with runWithSufficientStackSpace so 
deep recursive constexpr calls use a fresh stack before exhausting the current 
one.

Fixes #201418
---
 clang/docs/ReleaseNotes.rst                 |  2 ++
 clang/lib/AST/ExprConstant.cpp              | 35 +++++++++++++++++----
 clang/test/SemaCXX/constexpr-call-stack.cpp | 10 ++++++
 3 files changed, 41 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/SemaCXX/constexpr-call-stack.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9e4a47a5b18fc..0f661fa1c1d73 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -716,6 +716,8 @@ Bug Fixes to C++ Support
 - Fixed an invalid rejection and assertion failure while generating 
``operator=`` for fields with the ``__restrict`` qualifier. (#GH37979)
 - Fixed a use-after-free bug when parsing default arguments containing lambdas 
in declarations with template-id declarators. (#GH196725)
 - Fixed a crash in constant evaluation using placement new on an array which 
was later initialized. (#GH196450)
+- Fixed a stack overflow crash when evaluating deeply recursive ``constexpr``
+  function calls. (#GH201418)
 - Fixed an issue where Clang incorrectly accepted invalid unqualified uses of 
local nested class names outside their declaring scope. (#GH184622)
 
 Bug Fixes to AST Handling
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 86c162cc040f9..f26340f9fac4f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -53,6 +53,7 @@
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/StackExhaustionHandler.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/APFixedPoint.h"
@@ -816,6 +817,8 @@ namespace {
     /// initialized after CurrentCall and CallStackDepth.
     CallStackFrame BottomFrame;
 
+    StackExhaustionHandler StackHandler;
+
     /// A stack of values whose lifetimes end at the end of some surrounding
     /// evaluation frame.
     llvm::SmallVector<Cleanup, 16> CleanupStack;
@@ -920,6 +923,7 @@ namespace {
           BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
                       /*This=*/nullptr,
                       /*CallExpr=*/nullptr, CallRef()),
+          StackHandler(C.getDiagnostics()),
           EvaluatingDecl((const ValueDecl *)nullptr),
           EvaluatingDeclValue(nullptr) {
       EvalMode = Mode;
@@ -1009,6 +1013,13 @@ namespace {
       return true;
     }
 
+    bool runWithSufficientStackSpace(SourceLocation Loc,
+                                     llvm::function_ref<bool()> Fn) {
+      bool Result = false;
+      StackHandler.runWithSufficientStackSpace(Loc, [&] { Result = Fn(); });
+      return Result;
+    }
+
     APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
 
     std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) {
@@ -7000,12 +7011,12 @@ static bool handleTrivialCopy(EvalInfo &Info, const 
ParmVarDecl *Param,
 }
 
 /// Evaluate a function call.
-static bool HandleFunctionCall(SourceLocation CallLoc,
-                               const FunctionDecl *Callee,
-                               const LValue *ObjectArg, const Expr *E,
-                               ArrayRef<const Expr *> Args, CallRef Call,
-                               const Stmt *Body, EvalInfo &Info,
-                               APValue &Result, const LValue *ResultSlot) {
+static bool HandleFunctionCallImpl(SourceLocation CallLoc,
+                                   const FunctionDecl *Callee,
+                                   const LValue *ObjectArg, const Expr *E,
+                                   ArrayRef<const Expr *> Args, CallRef Call,
+                                   const Stmt *Body, EvalInfo &Info,
+                                   APValue &Result, const LValue *ResultSlot) {
   if (!Info.CheckCallLimit(CallLoc))
     return false;
 
@@ -7059,6 +7070,18 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
   return ESR == ESR_Returned;
 }
 
+static bool HandleFunctionCall(SourceLocation CallLoc,
+                               const FunctionDecl *Callee,
+                               const LValue *ObjectArg, const Expr *E,
+                               ArrayRef<const Expr *> Args, CallRef Call,
+                               const Stmt *Body, EvalInfo &Info,
+                               APValue &Result, const LValue *ResultSlot) {
+  return Info.runWithSufficientStackSpace(CallLoc, [&] {
+    return HandleFunctionCallImpl(CallLoc, Callee, ObjectArg, E, Args, Call,
+                                  Body, Info, Result, ResultSlot);
+  });
+}
+
 /// Evaluate a constructor call.
 static bool HandleConstructorCall(const Expr *E, const LValue &This,
                                   CallRef Call,
diff --git a/clang/test/SemaCXX/constexpr-call-stack.cpp 
b/clang/test/SemaCXX/constexpr-call-stack.cpp
new file mode 100644
index 0000000000000..6f0434987b753
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-call-stack.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -Wno-unused-value 
-Wno-stack-exhausted -fconstexpr-depth=1024 %s
+
+int rand();
+
+constexpr int a(int) {
+  {
+    (100000000001024 ^ a(0) * 0 ? 2147483647 : rand()) ? 2147483647 : 1;
+  }
+  return 0;
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to