GC and void[N] in struct

Steven Schveighoffer schveiguy at gmail.com
Mon Aug 6 19:56:03 UTC 2018


On 8/6/18 3:43 PM, Steven Schveighoffer wrote:
> On 8/6/18 2:59 PM, vit wrote:
>> On Monday, 6 August 2018 at 18:28:11 UTC, Steven Schveighoffer wrote:
>>> On 8/6/18 2:22 PM, vit wrote:
>>>> Hello,
>>>> I have this struct:
>>>>
>>>> struct S{
>>>>      uint kind;
>>>>      void[N] data_;
>>>
>>> define "N"
>>>
>>>>
>>>> }
>>>>
>>>> Instances of struct S are allocated by standard GC new and S.data_ 
>>>> can contain pointers/ranges to GC allocated data.
>>>> If is GC disabled then  program run fine. But when is GC enabled 
>>>> then it fail randomly.
>>>
>>> how does it fail?
>>>
>>
>>
>> private auto sizeOf(T)(){return T.sizeof;}
> 
> Hm... wouldn't enum sizeOf(T) = T.sizeof work better?
> 
>>
>> struct ExprImpl(Ts...){
>>      enum N = max(staticMap!(sizeOf, Ts));
> 
> This is clever!
> 
>>
>>      invariant(kind_ != 0);
>>      uint kind_ = 0;
>>      void[N] data_;
>>
>>      this(T)(auto ref T x){/+emplace T to data_ and change kind_ to 
>> something != 0+/}
>> }
>>
>> Ts == structs
>>
>>
>>
>> data change without triggering invariant after allocation in other 
>> part of program.
> 
> Most definitely this is alignment problem.
> 
> Here is what I *think* is happening:
> 
> 1. You are constructing one of these structs, and storing a pointer as 
> the T type.
> 2. You are on a 64-bit CPU.
> 3. The pointer is misaligned on the CPU, so when the GC scans this 
> struct to see if it's pointing at anything, it sees one half as the 
> kind_ value, and the other half is half of the pointer.
> 4. It misses the object being pointed at by the T inside the struct, and 
> collects it, leaving a dangling pointer.
> 5. Memory corruption.
> 
> when you put the void[N] member *first*, it can properly align the item 
> (most cases where the compiler is placing data, it starts out aligned) 
> but this does not guarantee you have proper alignment, as void[N] has no 
> alignment constraints.
> 
> I'd recommend instead, changing the uint kind_ to a size_t. This not 
> only aligns the void[N] to size_t size, which should put any pointers in 
> the right place, but it also makes sure the entire struct is aligned.

BTW, is there a reason you aren't just using Algebraic?

https://dlang.org/phobos/std_variant.html#.Algebraic

-Steve


More information about the Digitalmars-d-learn mailing list