From a00328cd78bf4243dde3e8f11b1bd4fa1ea79b63 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Mon, 14 Oct 2024 14:06:50 +0200 Subject: [PATCH] [clang] Fix segmentation fault caused by stack overflow on deeply nested expressions (#111701) 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 --- clang/lib/CodeGen/CGExpr.cpp | 7 ++++++- clang/lib/CodeGen/CodeGenModule.cpp | 14 ++++++++++++++ clang/lib/CodeGen/CodeGenModule.h | 11 +++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index ec54da0a5b25714..1e8ffb53b53a09e 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1528,7 +1528,12 @@ LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) { /// LValue CodeGenFunction::EmitLValue(const Expr *E, KnownNonNull_t IsKnownNonNull) { - LValue LV = EmitLValueHelper(E, IsKnownNonNull); + // Running with sufficient stack space to avoid deeply nested expressions + // cause a stack overflow. + LValue LV; + CGM.runWithSufficientStackSpace( + E->getExprLoc(), [&] { LV = EmitLValueHelper(E, IsKnownNonNull); }); + if (IsKnownNonNull && !LV.isKnownNonNull()) LV.setKnownNonNull(); return LV; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 7f0e0de61e477bc..b05ab3606a698ba 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" @@ -1593,6 +1594,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 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 c58bb88035ca8ab..57e06cbfac13a90 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -336,6 +336,7 @@ class CodeGenModule : public CodeGenTypeCache { std::unique_ptr PGOReader; InstrProfStats PGOStats; std::unique_ptr 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 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.