www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 15637] New: Region allocator assert failure when expanding

https://issues.dlang.org/show_bug.cgi?id=15637

          Issue ID: 15637
           Summary: Region allocator assert failure when expanding the
                    last allocation
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: phobos
          Assignee: nobody puremagic.com
          Reporter: mark mnetcs.com

The following code crashes with an assert failure at
std/experimental/allocator/building_blocks/region.d:235 on 64-bit Linux and
32-/64-bit Windows, using DMD version 2.070.0:

import std.experimental.allocator;
import std.experimental.allocator.building_blocks;

void main(string[] args) {
    ubyte[1024] memory;
    auto alloc = Region!NullAllocator(memory);

    auto result = alloc.allocate(20);
    alloc.expand(result, 20);
}


The region allocator's expand function doesn't take into account any existing
alignment padding when calculating the new allocation size, which pushes the
_current pointer past the expected value.

This could probably be fixed with something like:

    static if (growDownwards == No.growDownwards)
    bool expand(ref void[] b, size_t delta)
    {
        assert(owns(b) == Ternary.yes || b.ptr is null);
        assert(b.ptr + b.length <= _current || b.ptr is null);
        if (!b.ptr)
        {
            b = allocate(delta);
            return b.length == delta;
        }
        auto newLength = b.length + delta;
        if (_current < b.ptr + b.length + alignment)
        {
            immutable currentAllocSize = this.goodAllocSize(b.length);
            immutable requiredAllocSize = this.goodAllocSize(newLength);
            immutable allocDelta = requiredAllocSize - currentAllocSize;
            // This was the last allocation! Allocate some more and we're done.
            if (currentAllocSize == requiredAllocSize
                || allocate(allocDelta).length == allocDelta)
            {
                b = b.ptr[0 .. newLength];
                assert(_current < b.ptr + b.length + alignment);
                return true;
            }
        }
        return false;
    }

--
Feb 01 2016