llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Boaz Brickner (bricknerb) <details> <summary>Changes</summary> Done by calling clang::runWithSufficientStackSpace(). Added CodeGenModule::runWithSufficientStackSpace() method similar to the one in Sema to provide a single warning when this triggers Fixes: #<!-- -->111699 --- Patch is 82.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/111701.diff 4 Files Affected: - (modified) clang/lib/CodeGen/CGExpr.cpp (+4-1) - (modified) clang/lib/CodeGen/CodeGenModule.cpp (+14) - (modified) clang/lib/CodeGen/CodeGenModule.h (+11) - (added) clang/test/CodeGen/deeply-nested-expressions.cpp (+1013) ``````````diff diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 451442765620f7..5ececf7d940520 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5817,7 +5817,10 @@ LValue CodeGenFunction::EmitHLSLArrayAssignLValue(const BinaryOperator *E) { LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E, llvm::CallBase **CallOrInvoke) { - RValue RV = EmitCallExpr(E, ReturnValueSlot(), CallOrInvoke); + RValue RV; + CGM.runWithSufficientStackSpace(E->getExprLoc(), [&] { + RV = EmitCallExpr(E, ReturnValueSlot(), CallOrInvoke); + }); if (!RV.isScalar()) return MakeAddrLValue(RV.getAggregateAddress(), E->getType(), diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 5ba098144a74e7..424455cbf4da39 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -44,6 +44,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/CodeGen/BackendUtil.h" @@ -1596,6 +1597,19 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type) { getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg; } +void CodeGenModule::warnStackExhausted(SourceLocation Loc) { + // Only warn about this once. + if (!WarnedStackExhausted) { + getDiags().Report(Loc, diag::warn_stack_exhausted); + WarnedStackExhausted = true; + } +} + +void CodeGenModule::runWithSufficientStackSpace(SourceLocation Loc, + llvm::function_ref<void()> Fn) { + clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn); +} + llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) { return llvm::ConstantInt::get(SizeTy, size.getQuantity()); } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index c58bb88035ca8a..57e06cbfac13a9 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -336,6 +336,7 @@ class CodeGenModule : public CodeGenTypeCache { std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader; InstrProfStats PGOStats; std::unique_ptr<llvm::SanitizerStatReport> SanStats; + bool WarnedStackExhausted = false; // A set of references that have only been seen via a weakref so far. This is // used to remove the weak of the reference if we ever see a direct reference @@ -1297,6 +1298,16 @@ class CodeGenModule : public CodeGenTypeCache { /// Print out an error that codegen doesn't support the specified decl yet. void ErrorUnsupported(const Decl *D, const char *Type); + /// Warn that the stack is nearly exhausted. + void warnStackExhausted(SourceLocation Loc); + + /// Run some code with "sufficient" stack space. (Currently, at least 256K is + /// guaranteed). Produces a warning if we're low on stack space and allocates + /// more in that case. Use this in code that may recurse deeply to avoid stack + /// overflow. + void runWithSufficientStackSpace(SourceLocation Loc, + llvm::function_ref<void()> Fn); + /// Set the attributes on the LLVM function for the given decl and function /// info. This applies attributes necessary for handling the ABI as well as /// user specified attributes like section. diff --git a/clang/test/CodeGen/deeply-nested-expressions.cpp b/clang/test/CodeGen/deeply-nested-expressions.cpp new file mode 100644 index 00000000000000..3f7b55d35ed76d --- /dev/null +++ b/clang/test/CodeGen/deeply-nested-expressions.cpp @@ -0,0 +1,1013 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -Wstack-exhausted -verify + +class AClass { +public: + AClass() {} + AClass &foo() { return *this; } +}; + +void test_bar() { + AClass a; + // expected-warning@* {{stack nearly exhausted; compilation time may suffer, and crashes due to stack overflow are likely}} + a.foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo().foo() + .foo().foo().f... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/111701 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits