May 12, 2017
https://issues.dlang.org/show_bug.cgi?id=17393

          Issue ID: 17393
           Summary: AllocatorList leaks memory in "ouroboros mode"
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P1
         Component: phobos
          Assignee: nobody@puremagic.com
          Reporter: sludwig@outerproduct.org

The following bails out at the last assertion because there is still a DummyAllocator with allocated memory left over:

---
import std.experimental.allocator;
import std.experimental.allocator.mallocator;
import std.experimental.allocator.building_blocks.allocator_list;
import std.experimental.allocator.building_blocks.region;
import std.experimental.allocator.building_blocks.null_allocator;
import std.algorithm;

// simple region allocator that keeps track of the number of active references
struct DummyAllocator {
    import std.typecons : Ternary;

    static int cnt;
    void[] mem;
    size_t ptr;

    enum alignment = ulong.alignof;

    this(size_t sz) { mem = new void[](sz); cnt++; }
    this(this) { if (mem.ptr) cnt++; }
    ~this() { if (mem.ptr) cnt--; }

    Ternary owns(void[] slc)
    const {
        return slc.ptr >= mem.ptr && slc.ptr + slc.length <= mem.ptr +
mem.length ? Ternary.yes : Ternary.no;
    }

    void[] allocate(size_t n)
    {
        if (!mem.ptr) {
            mem = new void[](1024*1024);
            cnt++;
        }
        if (mem.length - ptr < n) return null;
        auto ret = mem[ptr .. ptr + n];
        ptr += n;
        return ret;
    }

    bool deallocateAll()
    {
        if (mem.ptr) {
            ptr = 0;
            delete mem;
            cnt--;
        }
        return true;
    }
}

void main()
{
    assert(DummyAllocator.cnt == 0);

    {
        auto a = AllocatorList!(n => DummyAllocator(max(n, 1024*1024)),
NullAllocator).init;
        a.allocate(1000);
        a.deallocateAll();
    }

    assert(DummyAllocator.cnt == 0);
}
---

The deallocateAll() call in particular doesn't get forwarded to DummyAllocator and its destructor isn't called either. If NullAllocator is exchanged for Mallocator, this issue doesn't show up.

--