Skip to content

Commit

Permalink
[Clang] Fix segmentation fault caused by VarBypassDetector stack ov…
Browse files Browse the repository at this point in the history
…erflow on deeply nested expressions (#124128)

This happens when using `-O2`.

Similarly to #111701
([test](https://github.com/bricknerb/llvm-project/blob/93e4a7386ec897e53d7330c6206d38759a858be2/clang/test/CodeGen/deeply-nested-expressions.cpp)),
not adding a test that reproduces since this test is slow and likely to
be hard to maintained as discussed here and in [previous
discussion](https://github.com/llvm/llvm-project/pull/111701/files/1a63281b6c240352653fd2e4299755c1f32a76f4#r1795518779).
Test that was reverted here:
d6b5576
  • Loading branch information
bricknerb authored Mar 10, 2025
1 parent 35f273a commit e0442bd
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 13 deletions.
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1534,7 +1534,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// Initialize helper which will detect jumps which can cause invalid
// lifetime markers.
if (ShouldEmitLifetimeMarkers)
Bypasses.Init(Body);
Bypasses.Init(CGM, Body);
}

// Emit the standard function prologue.
Expand Down
23 changes: 14 additions & 9 deletions clang/lib/CodeGen/VarBypassDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "VarBypassDetector.h"

#include "CodeGenModule.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
Expand All @@ -17,21 +18,21 @@ using namespace CodeGen;

/// Clear the object and pre-process for the given statement, usually function
/// body statement.
void VarBypassDetector::Init(const Stmt *Body) {
void VarBypassDetector::Init(CodeGenModule &CGM, const Stmt *Body) {
FromScopes.clear();
ToScopes.clear();
Bypasses.clear();
Scopes = {{~0U, nullptr}};
unsigned ParentScope = 0;
AlwaysBypassed = !BuildScopeInformation(Body, ParentScope);
AlwaysBypassed = !BuildScopeInformation(CGM, Body, ParentScope);
if (!AlwaysBypassed)
Detect();
}

/// Build scope information for a declaration that is part of a DeclStmt.
/// Returns false if we failed to build scope information and can't tell for
/// which vars are being bypassed.
bool VarBypassDetector::BuildScopeInformation(const Decl *D,
bool VarBypassDetector::BuildScopeInformation(CodeGenModule &CGM, const Decl *D,
unsigned &ParentScope) {
const VarDecl *VD = dyn_cast<VarDecl>(D);
if (VD && VD->hasLocalStorage()) {
Expand All @@ -41,7 +42,7 @@ bool VarBypassDetector::BuildScopeInformation(const Decl *D,

if (const VarDecl *VD = dyn_cast<VarDecl>(D))
if (const Expr *Init = VD->getInit())
return BuildScopeInformation(Init, ParentScope);
return BuildScopeInformation(CGM, Init, ParentScope);

return true;
}
Expand All @@ -50,7 +51,7 @@ bool VarBypassDetector::BuildScopeInformation(const Decl *D,
/// LabelAndGotoScopes and recursively walking the AST as needed.
/// Returns false if we failed to build scope information and can't tell for
/// which vars are being bypassed.
bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
bool VarBypassDetector::BuildScopeInformation(CodeGenModule &CGM, const Stmt *S,
unsigned &origParentScope) {
// If this is a statement, rather than an expression, scopes within it don't
// propagate out into the enclosing scope. Otherwise we have to worry about
Expand All @@ -68,12 +69,12 @@ bool VarBypassDetector::BuildScopeInformation(const Stmt *S,

case Stmt::SwitchStmtClass:
if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
if (!BuildScopeInformation(Init, ParentScope))
if (!BuildScopeInformation(CGM, Init, ParentScope))
return false;
++StmtsToSkip;
}
if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
if (!BuildScopeInformation(Var, ParentScope))
if (!BuildScopeInformation(CGM, Var, ParentScope))
return false;
++StmtsToSkip;
}
Expand All @@ -86,7 +87,7 @@ bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(S);
for (auto *I : DS->decls())
if (!BuildScopeInformation(I, origParentScope))
if (!BuildScopeInformation(CGM, I, origParentScope))
return false;
return true;
}
Expand Down Expand Up @@ -126,7 +127,11 @@ bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
}

// Recursively walk the AST.
if (!BuildScopeInformation(SubStmt, ParentScope))
bool Result;
CGM.runWithSufficientStackSpace(S->getEndLoc(), [&] {
Result = BuildScopeInformation(CGM, SubStmt, ParentScope);
});
if (!Result)
return false;
}
return true;
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/CodeGen/VarBypassDetector.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_VARBYPASSDETECTOR_H
#define LLVM_CLANG_LIB_CODEGEN_VARBYPASSDETECTOR_H

#include "CodeGenModule.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
Expand Down Expand Up @@ -50,7 +51,7 @@ class VarBypassDetector {
bool AlwaysBypassed = false;

public:
void Init(const Stmt *Body);
void Init(CodeGenModule &CGM, const Stmt *Body);

/// Returns true if the variable declaration was by bypassed by any goto or
/// switch statement.
Expand All @@ -59,8 +60,10 @@ class VarBypassDetector {
}

private:
bool BuildScopeInformation(const Decl *D, unsigned &ParentScope);
bool BuildScopeInformation(const Stmt *S, unsigned &origParentScope);
bool BuildScopeInformation(CodeGenModule &CGM, const Decl *D,
unsigned &ParentScope);
bool BuildScopeInformation(CodeGenModule &CGM, const Stmt *S,
unsigned &origParentScope);
void Detect();
void Detect(unsigned From, unsigned To);
};
Expand Down

0 comments on commit e0442bd

Please sign in to comment.