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