Skip to content

Commit 1c2e7d2

Browse files
committed
[MS] Fix crash involving gnu stmt exprs and inalloca
Use a WeakTrackingVH to cope with the stmt emission logic that cleans up unreachable blocks. This invalidates the reference to the deferred replacement placeholder. Cope with it. Fixes PR25102 (from 2015!)
1 parent 9899427 commit 1c2e7d2

File tree

4 files changed

+61
-9
lines changed

4 files changed

+61
-9
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4436,7 +4436,8 @@ llvm::CallBase *CodeGenFunction::EmitCallOrInvoke(llvm::FunctionCallee Callee,
44364436

44374437
void CodeGenFunction::deferPlaceholderReplacement(llvm::Instruction *Old,
44384438
llvm::Value *New) {
4439-
DeferredReplacements.push_back(std::make_pair(Old, New));
4439+
DeferredReplacements.push_back(
4440+
std::make_pair(llvm::WeakTrackingVH(Old), New));
44404441
}
44414442

44424443
namespace {

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -452,13 +452,13 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
452452
if (CGM.getCodeGenOpts().EmitDeclMetadata)
453453
EmitDeclMetadata();
454454

455-
for (SmallVectorImpl<std::pair<llvm::Instruction *, llvm::Value *> >::iterator
456-
I = DeferredReplacements.begin(),
457-
E = DeferredReplacements.end();
458-
I != E; ++I) {
459-
I->first->replaceAllUsesWith(I->second);
460-
I->first->eraseFromParent();
455+
for (const auto &R : DeferredReplacements) {
456+
if (llvm::Value *Old = R.first) {
457+
Old->replaceAllUsesWith(R.second);
458+
cast<llvm::Instruction>(Old)->eraseFromParent();
459+
}
461460
}
461+
DeferredReplacements.clear();
462462

463463
// Eliminate CleanupDestSlot alloca by replacing it with SSA values and
464464
// PHIs if the current function is a coroutine. We don't do it for all

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4539,8 +4539,8 @@ class CodeGenFunction : public CodeGenTypeCache {
45394539

45404540
void deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New);
45414541

4542-
llvm::SmallVector<std::pair<llvm::Instruction *, llvm::Value *>, 4>
4543-
DeferredReplacements;
4542+
llvm::SmallVector<std::pair<llvm::WeakTrackingVH, llvm::Value *>, 4>
4543+
DeferredReplacements;
45444544

45454545
/// Set the address of a local variable.
45464546
void setAddrOfLocalVar(const VarDecl *VD, Address Addr) {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %clang_cc1 %s -emit-llvm -triple i686-windows-msvc -o - | FileCheck %s
2+
3+
// Statement allow the user to exit the evaluation scope of a CallExpr without
4+
// executing the call. Check that clang generates reasonable IR for that case.
5+
6+
// Not trivially copyable, subject to inalloca.
7+
struct Foo {
8+
int x;
9+
Foo();
10+
~Foo();
11+
};
12+
13+
void inalloca(Foo x, Foo y);
14+
15+
// PR25102: In this case, clang attempts to clean up unreachable blocks *during*
16+
// IR generation. inalloca defers some RAUW operations to the end of codegen,
17+
// and those references would become stale when the unreachable call to
18+
// 'inalloca' got deleted.
19+
extern "C" void pr25102() {
20+
inalloca(Foo(), ({
21+
goto out;
22+
Foo();
23+
}));
24+
out:;
25+
}
26+
27+
// CHECK-LABEL: define dso_local void @pr25102()
28+
// CHECK: br label %out
29+
// CHECK: out:
30+
// CHECK: ret void
31+
32+
bool cond();
33+
extern "C" void seqAbort() {
34+
inalloca(Foo(), ({
35+
if (cond())
36+
goto out;
37+
Foo();
38+
}));
39+
out:;
40+
}
41+
42+
// FIXME: This can cause a stack leak. We should really have a "normal" cleanup
43+
// that goto branches through.
44+
// CHECK-LABEL: define dso_local void @seqAbort()
45+
// CHECK: alloca inalloca <{ %struct.Foo, %struct.Foo }>
46+
// CHECK: call zeroext i1 @"?cond@@YA_NXZ"()
47+
// CHECK: br i1
48+
// CHECK: br label %out
49+
// CHECK: call void @"?inalloca@@YAXUFoo@@0@Z"(<{ %struct.Foo, %struct.Foo }>* inalloca %{{.*}})
50+
// CHECK: call void @llvm.stackrestore(i8* %inalloca.save)
51+
// CHECK: out:

0 commit comments

Comments
 (0)