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