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
