Merged to release_80 in r353807.
On Fri, Feb 8, 2019 at 2:28 AM JF Bastien via cfe-commits <cfe-commits@lists.llvm.org> wrote: > > Author: jfb > Date: Thu Feb 7 17:29:17 2019 > New Revision: 353495 > > URL: http://llvm.org/viewvc/llvm-project?rev=353495&view=rev > Log: > 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 > > Modified: > cfe/trunk/lib/CodeGen/CGDecl.cpp > cfe/trunk/test/CodeGenCXX/trivial-auto-var-init.cpp > > Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=353495&r1=353494&r2=353495&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Thu Feb 7 17:29:17 2019 > @@ -1633,11 +1633,15 @@ void CodeGenFunction::EmitAutoVarInit(co > ? LangOptions::TrivialAutoVarInitKind::Uninitialized > : getContext().getLangOpts().getTrivialAutoVarInit())); > > - auto initializeWhatIsTechnicallyUninitialized = [&]() { > + auto initializeWhatIsTechnicallyUninitialized = [&](Address Loc) { > if (trivialAutoVarInit == > LangOptions::TrivialAutoVarInitKind::Uninitialized) > return; > > + // Only initialize a __block's storage: we always initialize the header. > + if (emission.IsEscapingByRef) > + Loc = emitBlockByrefAddress(Loc, &D, /*follow=*/false); > + > CharUnits Size = getContext().getTypeSizeInChars(type); > if (!Size.isZero()) { > switch (trivialAutoVarInit) { > @@ -1714,7 +1718,7 @@ void CodeGenFunction::EmitAutoVarInit(co > }; > > if (isTrivialInitializer(Init)) { > - initializeWhatIsTechnicallyUninitialized(); > + initializeWhatIsTechnicallyUninitialized(Loc); > return; > } > > @@ -1728,7 +1732,7 @@ void CodeGenFunction::EmitAutoVarInit(co > } > > if (!constant) { > - initializeWhatIsTechnicallyUninitialized(); > + initializeWhatIsTechnicallyUninitialized(Loc); > LValue lv = MakeAddrLValue(Loc, type); > lv.setNonGC(true); > return EmitExprAsInit(Init, &D, lv, capturedByInit); > > Modified: cfe/trunk/test/CodeGenCXX/trivial-auto-var-init.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/trivial-auto-var-init.cpp?rev=353495&r1=353494&r2=353495&view=diff > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/trivial-auto-var-init.cpp (original) > +++ cfe/trunk/test/CodeGenCXX/trivial-auto-var-init.cpp Thu Feb 7 17:29:17 > 2019 > @@ -30,6 +30,32 @@ void test_block() { > used(block); > } > > +// Using the variable being initialized is typically UB in C, but for blocks > we > +// can be nice: they imply extra book-keeping and we can do the auto-init > before > +// any of said book-keeping. > +// > +// UNINIT-LABEL: test_block_self_init( > +// ZERO-LABEL: test_block_self_init( > +// ZERO: %block = alloca <{ i8*, i32, i32, i8*, > %struct.__block_descriptor*, i8* }>, align 8 > +// ZERO: %captured1 = getelementptr inbounds > %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, > i32 0, i32 4 > +// ZERO-NEXT: store %struct.XYZ* null, %struct.XYZ** %captured1, align 8 > +// ZERO: %call = call %struct.XYZ* @create( > +// PATTERN-LABEL: test_block_self_init( > +// PATTERN: %block = alloca <{ i8*, i32, i32, i8*, > %struct.__block_descriptor*, i8* }>, align 8 > +// PATTERN: %captured1 = getelementptr inbounds > %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, > i32 0, i32 4 > +// PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to > %struct.XYZ*), %struct.XYZ** %captured1, align 8 > +// PATTERN: %call = call %struct.XYZ* @create( > +void test_block_self_init() { > + using Block = void (^)(); > + typedef struct XYZ { > + Block block; > + } * xyz_t; > + extern xyz_t create(Block block); > + __block xyz_t captured = create(^() { > + (void)captured; > + }); > +} > + > // This type of code is currently not handled by zero / pattern > initialization. > // The test will break when that is fixed. > // UNINIT-LABEL: test_goto_unreachable_value( > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits