AA vs __gshared

Steven Schveighoffer schveiguy at gmail.com
Fri Jul 28 21:22:01 UTC 2023


On 7/28/23 11:15 AM, IchorDev wrote:
> On Friday, 28 July 2023 at 11:15:31 UTC, Steven Schveighoffer wrote:
>> All `__gshared` does is give you storage that is accessible from all 
>> threads,
> 
> "All __gshared does is give you [a live bomb, ready to go off at any 
> moment]"
> !!

It seems like it's not __gshared at all, but misusing malloc with GC 
pointers.

> 
> On Friday, 28 July 2023 at 14:10:16 UTC, Kagamin wrote:
>> Your error is using allocating the object with malloc. Since gc 
>> doesn't see your AA, the AA is freed and you get UAF.
> 
> Friend, I think you nailed it. After adding this I haven't been able to 
> reproduce the segfault again:
> ```d
> this(long n){
>      (){
>          cache = new typeof(cache);
>          assert(cache);
>          import core.memory;
>          core.memory.GC.addRoot(cast(void*)cache);
>      }();
>      // ...
> ```
> It did always happen at random, so perhaps I haven't spent enough time 
> testing it yet, but I've gone far longer without it segfaulting than 
> ever before.

This is the wrong approach, it's the allocating call that should add the 
root (actually a range).

For instance, the mutex is not added, that might be collected. Or if you 
add more GC-pointing things into the class, that could be a problem.

What I'd do is:

```d
T alloc(T, A...)(auto ref A args){
     enum classSize = __traits(classInstanceSize, T);
     void* mem = core.stdc.stdlib.malloc(classSize);
     assert(mem !is null, "Out of memory");
     core.memory.GC.addRange(mem[0 .. classSize]);
     scope(failure) {
        core.memory.GC.removeRange(mem[0 .. classSize]);
        core.stdc.stdlib.free(mem);
     }
     T inst = cast(T)mem;
     inst.emplace(__traits(parameters));
     return inst;
}
```

And of course, a `dealloc` that removes the range should also be added.

-Steve


More information about the Digitalmars-d-learn mailing list