Skip to content

[Clang] Fix segmentation fault caused by VarBypassDetector stack overflow on deeply nested expressions #124128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1533,7 +1533,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
Loading