[Issue 15790] New: The GC frees managed members made w/ allocator.make, causing memory corruption
    via Digitalmars-d-bugs 
    digitalmars-d-bugs at puremagic.com
       
    Fri Mar 11 19:50:05 PST 2016
    
    
  
https://issues.dlang.org/show_bug.cgi?id=15790
          Issue ID: 15790
           Summary: The GC frees managed members made w/ allocator.make,
                    causing memory corruption
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P1
         Component: phobos
          Assignee: nobody at puremagic.com
          Reporter: b2.temp at gmx.com
The managed members of an aggregate instanciated with
std.experimental.allocator can be freed during a GC pass, and even if the
allocator used is not GCAllocator.
The following program illustrates the issue:
import core.memory;
import std.experimental.allocator.mallocator;
import std.experimental.allocator.common;
enum fill = "azertyuiopqsdfghjklm";
auto make(T, Allocator, A...)(auto ref Allocator alloc, auto ref A args)
{
    import std.algorithm : max;
    import std.conv : emplace;
    auto m = alloc.allocate(max(stateSize!T, 1));
    version(none) GC.addRange(m.ptr, m.length); // activate this to fix the
error
    if (!m.ptr) return null;
    scope(failure) alloc.deallocate(m);
    static if (is(T == class)) return emplace!T(m, args);
    else return emplace(cast(T*) m.ptr, args);
}
struct Node
{
    this(string c){content = c;}
    string content;
    Node*[] nodes;
}
void main()
{
    Node* root = make!Node(Mallocator.instance, fill);
    foreach(immutable i; 0 .. 10000)
    {
        root.nodes ~= make!Node(Mallocator.instance, fill);
        foreach(immutable j; 0 .. 100)
            root.nodes[i].nodes ~= make!Node(Mallocator.instance, fill);
    }
    assert(root.content == fill);
    foreach(immutable i; 0 .. root.nodes.length)
    {
        assert(root.nodes[i].content == fill);
        foreach(immutable j; 0 .. root.nodes[i].nodes.length)
            assert(root.nodes[i].nodes[j].content == fill);
    }
} 
Because "content" is a managed type, it's corrupted during a GC pass.
While the tree structure is OK, checking the content reveals the corruption
(.ptr or .length or both points to invalid mem location). When the LOC that
declares the aggregate to the GC is activated, the error disapears.
Either make() documentation should explicitly warn about this or a template
parameter could indicate if the content of the aggregate has to be declared to
the GC.
--
    
    
More information about the Digitalmars-d-bugs
mailing list