Skip to content

Commit e055d7f

Browse files
committed
Merging r353495:
------------------------------------------------------------------------ r353495 | jfb | 2019-02-08 02:29:17 +0100 (Fri, 08 Feb 2019) | 32 lines Variable auto-init: fix __block initialization Summary: Automatic initialization [1] of __block variables was trampling over the block's headers after they'd been initialized, which caused self-init usage to crash, such as here: typedef struct XYZ { void (^block)(); } *xyz_t; __attribute__((noinline)) xyz_t create(void (^block)()) { xyz_t myself = malloc(sizeof(struct XYZ)); myself->block = block; return myself; } int main() { __block xyz_t captured = create(^(){ (void)captured; }); } This type of code shouldn't be broken by variable auto-init, even if it's sketchy. [1] With -ftrivial-auto-var-init=pattern <rdar://problem/47798396> Reviewers: rjmccall, pcc, kcc Subscribers: jkorous, dexonsmith, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D57797 ------------------------------------------------------------------------ llvm-svn: 353807
1 parent 62ead03 commit e055d7f

File tree

2 files changed

+33
-3
lines changed

2 files changed

+33
-3
lines changed

clang/lib/CodeGen/CGDecl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,11 +1631,15 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
16311631
? LangOptions::TrivialAutoVarInitKind::Uninitialized
16321632
: getContext().getLangOpts().getTrivialAutoVarInit()));
16331633

1634-
auto initializeWhatIsTechnicallyUninitialized = [&]() {
1634+
auto initializeWhatIsTechnicallyUninitialized = [&](Address Loc) {
16351635
if (trivialAutoVarInit ==
16361636
LangOptions::TrivialAutoVarInitKind::Uninitialized)
16371637
return;
16381638

1639+
// Only initialize a __block's storage: we always initialize the header.
1640+
if (emission.IsEscapingByRef)
1641+
Loc = emitBlockByrefAddress(Loc, &D, /*follow=*/false);
1642+
16391643
CharUnits Size = getContext().getTypeSizeInChars(type);
16401644
if (!Size.isZero()) {
16411645
switch (trivialAutoVarInit) {
@@ -1713,7 +1717,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
17131717
};
17141718

17151719
if (isTrivialInitializer(Init)) {
1716-
initializeWhatIsTechnicallyUninitialized();
1720+
initializeWhatIsTechnicallyUninitialized(Loc);
17171721
return;
17181722
}
17191723

@@ -1727,7 +1731,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
17271731
}
17281732

17291733
if (!constant) {
1730-
initializeWhatIsTechnicallyUninitialized();
1734+
initializeWhatIsTechnicallyUninitialized(Loc);
17311735
LValue lv = MakeAddrLValue(Loc, type);
17321736
lv.setNonGC(true);
17331737
return EmitExprAsInit(Init, &D, lv, capturedByInit);

clang/test/CodeGenCXX/trivial-auto-var-init.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,32 @@ void test_block() {
3030
used(block);
3131
}
3232

33+
// Using the variable being initialized is typically UB in C, but for blocks we
34+
// can be nice: they imply extra book-keeping and we can do the auto-init before
35+
// any of said book-keeping.
36+
//
37+
// UNINIT-LABEL: test_block_self_init(
38+
// ZERO-LABEL: test_block_self_init(
39+
// ZERO: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
40+
// ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, i32 0, i32 4
41+
// ZERO-NEXT: store %struct.XYZ* null, %struct.XYZ** %captured1, align 8
42+
// ZERO: %call = call %struct.XYZ* @create(
43+
// PATTERN-LABEL: test_block_self_init(
44+
// PATTERN: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
45+
// PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, i32 0, i32 4
46+
// PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to %struct.XYZ*), %struct.XYZ** %captured1, align 8
47+
// PATTERN: %call = call %struct.XYZ* @create(
48+
void test_block_self_init() {
49+
using Block = void (^)();
50+
typedef struct XYZ {
51+
Block block;
52+
} * xyz_t;
53+
extern xyz_t create(Block block);
54+
__block xyz_t captured = create(^() {
55+
(void)captured;
56+
});
57+
}
58+
3359
// This type of code is currently not handled by zero / pattern initialization.
3460
// The test will break when that is fixed.
3561
// UNINIT-LABEL: test_goto_unreachable_value(

0 commit comments

Comments
 (0)