Skip to content

Commit 06bf61b

Browse files
committed
[clang] Fix segmentation fault caused by VarBypassDetector stack overflow on deeply nested expressions
This happens when using -O2. Added a test that reproduces it based on a test that was reverted in #111701: https://github.com/bricknerb/llvm-project/blob/93e4a7386ec897e53d7330c6206d38759a858be2/clang/test/CodeGen/deeply-nested-expressions.cpp However, this test is slow and likely to be hard to maintained as discussed in https://github.com/llvm/llvm-project/pull/111701/files/1a63281b6c240352653fd2e4299755c1f32a76f4#r1795518779 so unless there are objections I plan to remove this test before merging.
1 parent 0c66644 commit 06bf61b

File tree

4 files changed

+51
-13
lines changed

4 files changed

+51
-13
lines changed

clang/lib/CodeGen/CodeGenFunction.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1533,7 +1533,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
15331533
// Initialize helper which will detect jumps which can cause invalid
15341534
// lifetime markers.
15351535
if (ShouldEmitLifetimeMarkers)
1536-
Bypasses.Init(Body);
1536+
Bypasses.Init(CGM, Body);
15371537
}
15381538

15391539
// Emit the standard function prologue.

clang/lib/CodeGen/VarBypassDetector.cpp

+14-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "VarBypassDetector.h"
1010

11+
#include "CodeGenModule.h"
1112
#include "clang/AST/Decl.h"
1213
#include "clang/AST/Expr.h"
1314
#include "clang/AST/Stmt.h"
@@ -17,21 +18,21 @@ using namespace CodeGen;
1718

1819
/// Clear the object and pre-process for the given statement, usually function
1920
/// body statement.
20-
void VarBypassDetector::Init(const Stmt *Body) {
21+
void VarBypassDetector::Init(CodeGenModule &CGM, const Stmt *Body) {
2122
FromScopes.clear();
2223
ToScopes.clear();
2324
Bypasses.clear();
2425
Scopes = {{~0U, nullptr}};
2526
unsigned ParentScope = 0;
26-
AlwaysBypassed = !BuildScopeInformation(Body, ParentScope);
27+
AlwaysBypassed = !BuildScopeInformation(CGM, Body, ParentScope);
2728
if (!AlwaysBypassed)
2829
Detect();
2930
}
3031

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

4243
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
4344
if (const Expr *Init = VD->getInit())
44-
return BuildScopeInformation(Init, ParentScope);
45+
return BuildScopeInformation(CGM, Init, ParentScope);
4546

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

6970
case Stmt::SwitchStmtClass:
7071
if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
71-
if (!BuildScopeInformation(Init, ParentScope))
72+
if (!BuildScopeInformation(CGM, Init, ParentScope))
7273
return false;
7374
++StmtsToSkip;
7475
}
7576
if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
76-
if (!BuildScopeInformation(Var, ParentScope))
77+
if (!BuildScopeInformation(CGM, Var, ParentScope))
7778
return false;
7879
++StmtsToSkip;
7980
}
@@ -86,7 +87,7 @@ bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
8687
case Stmt::DeclStmtClass: {
8788
const DeclStmt *DS = cast<DeclStmt>(S);
8889
for (auto *I : DS->decls())
89-
if (!BuildScopeInformation(I, origParentScope))
90+
if (!BuildScopeInformation(CGM, I, origParentScope))
9091
return false;
9192
return true;
9293
}
@@ -126,7 +127,11 @@ bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
126127
}
127128

128129
// Recursively walk the AST.
129-
if (!BuildScopeInformation(SubStmt, ParentScope))
130+
bool Result;
131+
CGM.runWithSufficientStackSpace(S->getEndLoc(), [&] {
132+
Result = BuildScopeInformation(CGM, SubStmt, ParentScope);
133+
});
134+
if (!Result)
130135
return false;
131136
}
132137
return true;

clang/lib/CodeGen/VarBypassDetector.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_LIB_CODEGEN_VARBYPASSDETECTOR_H
1515
#define LLVM_CLANG_LIB_CODEGEN_VARBYPASSDETECTOR_H
1616

17+
#include "CodeGenModule.h"
1718
#include "clang/AST/Decl.h"
1819
#include "llvm/ADT/DenseMap.h"
1920
#include "llvm/ADT/DenseSet.h"
@@ -50,7 +51,7 @@ class VarBypassDetector {
5051
bool AlwaysBypassed = false;
5152

5253
public:
53-
void Init(const Stmt *Body);
54+
void Init(CodeGenModule &CGM, const Stmt *Body);
5455

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

6162
private:
62-
bool BuildScopeInformation(const Decl *D, unsigned &ParentScope);
63-
bool BuildScopeInformation(const Stmt *S, unsigned &origParentScope);
63+
bool BuildScopeInformation(CodeGenModule &CGM, const Decl *D,
64+
unsigned &ParentScope);
65+
bool BuildScopeInformation(CodeGenModule &CGM, const Stmt *S,
66+
unsigned &origParentScope);
6467
void Detect();
6568
void Detect(unsigned From, unsigned To);
6669
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang_cc1 %s -emit-llvm -o - -Wstack-exhausted
2+
// RUN: %clang_cc1 %s -emit-llvm -o - -Wstack-exhausted -O2
3+
4+
class AClass {
5+
public:
6+
AClass() {}
7+
AClass &f() { return *this; }
8+
};
9+
10+
#define CALLS1 f
11+
#define CALLS2 CALLS1().CALLS1
12+
#define CALLS4 CALLS2().CALLS2
13+
#define CALLS8 CALLS4().CALLS4
14+
#define CALLS16 CALLS8().CALLS8
15+
#define CALLS32 CALLS16().CALLS16
16+
#define CALLS64 CALLS32().CALLS32
17+
#define CALLS128 CALLS64().CALLS64
18+
#define CALLS256 CALLS128().CALLS128
19+
#define CALLS512 CALLS256().CALLS256
20+
#define CALLS1024 CALLS512().CALLS512
21+
#define CALLS2048 CALLS1024().CALLS1024
22+
#define CALLS4096 CALLS2048().CALLS2048
23+
#define CALLS8192 CALLS4096().CALLS4096
24+
#define CALLS16384 CALLS8192().CALLS8192
25+
#define CALLS32768 CALLS16384().CALLS16384
26+
27+
void test_bar() {
28+
AClass a;
29+
a.CALLS32768();
30+
}

0 commit comments

Comments
 (0)