[PATCH] D41884: Fix thread race between SectionPiece's OutputOff and Live members

Rafael Avila de Espindola via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 9 16:47:21 PST 2018


The race is in:


        if (!Sec->Pieces[I].Live)
          continue;
        size_t ShardId = getShardId(Sec->Pieces[I].Hash);
        if ((ShardId & (Concurrency - 1)) == ThreadId)
          Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I));

Where one section can be checking Live and another is setting OutputOff,
correct? If that is the case, why not just do hash check first:

        size_t ShardId = getShardId(Sec->Pieces[I].Hash);
        if ((ShardId & (Concurrency - 1)) == ThreadId && Sec->Pieces[I].Live)
          Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I));

Cheers,
Rafael

Dimitry Andric via Phabricator <reviews at reviews.llvm.org> writes:

> dim created this revision.
> dim added reviewers: ruiu, rafael.
>
> As reported in bug 35788, https://reviews.llvm.org/rL316280 reintroduces a race between two
> members of SectionPiece, which share the same 64 bit memory location.
>
> Reduce the Hash member by 1 bit, and move the Live member next to it,
> instead, while making OuputOff use the full 64 bit again.
>
> Adjust getShardId to cope with Hashes being 31 bits wide (I hope I
> interpreted that function correctly... :)
>
>
> Repository:
>   rLLD LLVM Linker
>
> https://reviews.llvm.org/D41884
>
> Files:
>   ELF/InputSection.h
>   ELF/SyntheticSections.h
>
>
> Index: ELF/SyntheticSections.h
> ===================================================================
> --- ELF/SyntheticSections.h
> +++ ELF/SyntheticSections.h
> @@ -710,7 +710,7 @@
>    // If we use lower bits, it significantly increases the probability of
>    // hash collisons.
>    size_t getShardId(uint32_t Hash) {
> -    return Hash >> (32 - llvm::countTrailingZeros(NumShards));
> +    return Hash >> (31 - llvm::countTrailingZeros(NumShards));
>    }
>  
>    // Section size
> Index: ELF/InputSection.h
> ===================================================================
> --- ELF/InputSection.h
> +++ ELF/InputSection.h
> @@ -200,13 +200,13 @@
>  // be found by looking at the next one).
>  struct SectionPiece {
>    SectionPiece(size_t Off, uint32_t Hash, bool Live)
> -      : InputOff(Off), Hash(Hash), OutputOff(-1),
> -        Live(Live || !Config->GcSections) {}
> +      : InputOff(Off), Hash(Hash), Live(Live || !Config->GcSections),
> +        OutputOff(-1) {}
>  
>    uint32_t InputOff;
> -  uint32_t Hash;
> -  int64_t OutputOff : 63;
> -  uint64_t Live : 1;
> +  uint32_t Hash : 31;
> +  uint32_t Live : 1;
> +  int64_t OutputOff;
>  };
>  
>  static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big");
>
>
> Index: ELF/SyntheticSections.h
> ===================================================================
> --- ELF/SyntheticSections.h
> +++ ELF/SyntheticSections.h
> @@ -710,7 +710,7 @@
>    // If we use lower bits, it significantly increases the probability of
>    // hash collisons.
>    size_t getShardId(uint32_t Hash) {
> -    return Hash >> (32 - llvm::countTrailingZeros(NumShards));
> +    return Hash >> (31 - llvm::countTrailingZeros(NumShards));
>    }
>  
>    // Section size
> Index: ELF/InputSection.h
> ===================================================================
> --- ELF/InputSection.h
> +++ ELF/InputSection.h
> @@ -200,13 +200,13 @@
>  // be found by looking at the next one).
>  struct SectionPiece {
>    SectionPiece(size_t Off, uint32_t Hash, bool Live)
> -      : InputOff(Off), Hash(Hash), OutputOff(-1),
> -        Live(Live || !Config->GcSections) {}
> +      : InputOff(Off), Hash(Hash), Live(Live || !Config->GcSections),
> +        OutputOff(-1) {}
>  
>    uint32_t InputOff;
> -  uint32_t Hash;
> -  int64_t OutputOff : 63;
> -  uint64_t Live : 1;
> +  uint32_t Hash : 31;
> +  uint32_t Live : 1;
> +  int64_t OutputOff;
>  };
>  
>  static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big");


More information about the llvm-commits mailing list