r353495 - Variable auto-init: fix __block initialization
Hans Wennborg via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 12 00:35:12 PST 2019
Merged to release_80 in r353807.
On Fri, Feb 8, 2019 at 2:28 AM JF Bastien via cfe-commits
<cfe-commits at 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 at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list