Skip to content

Commit

Permalink
fix issue 16564
Browse files Browse the repository at this point in the history
  • Loading branch information
somzzz committed Jan 16, 2017
1 parent 40bae5d commit 8a69b10
Showing 1 changed file with 110 additions and 3 deletions.
113 changes: 110 additions & 3 deletions std/experimental/allocator/building_blocks/kernighan_ritchie.d
Expand Up @@ -117,13 +117,21 @@ struct KRRegion(ParentAllocator = NullAllocator)
{
assert(right);
auto p = payload;
return p.ptr + p.length == right;
return p.ptr < right && right < p.ptr + p.length + Node.sizeof;
}

bool coalesce()
bool coalesce(void* memoryEnd = null)
{
// Coalesce the last node before the memory end with any possible gap
if (memoryEnd
&& memoryEnd < payload.ptr + payload.length + Node.sizeof)
{
size += memoryEnd - (payload.ptr + payload.length);
return true;
}

if (!adjacent(next)) return false;
size += next.size;
size = (cast(ubyte*) next + next.size) - cast(ubyte*) &this;
next = next.next;
return true;
}
Expand All @@ -137,6 +145,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
if (size < bytes) return typeof(return)();
assert(size >= bytes);
immutable leftover = size - bytes;

if (leftover >= Node.sizeof)
{
// There's room for another node
Expand All @@ -146,6 +155,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
assert(next);
return tuple(payload, newNode);
}

// No slack space, just return next node
return tuple(payload, next == &this ? null : next);
}
Expand Down Expand Up @@ -400,6 +410,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
}
return result[0 .. n];
}

// Not enough memory, switch to freelist mode and fall through
switchToFreeList;
}
Expand All @@ -417,6 +428,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
pnode.next = k[1];
return k[0][0 .. n];
}

pnode = pnode.next;
if (pnode == root) break;
}
Expand All @@ -443,6 +455,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
// coalesce at this time. Instead, do it lazily during allocation.
auto n = cast(Node*) b.ptr;
n.size = goodAllocSize(b.length);
auto memoryEnd = payload.ptr + payload.length;

if (regionMode)
{
Expand All @@ -458,6 +471,10 @@ struct KRRegion(ParentAllocator = NullAllocator)
// What a sight for sore eyes
root = n;
root.next = root;

// If the first block freed is the last one allocated,
// maybe there's a gap after it.
root.coalesce(memoryEnd);
return true;
}

Expand Down Expand Up @@ -486,8 +503,10 @@ struct KRRegion(ParentAllocator = NullAllocator)
else if (pnode < n)
{
// Insert at the end of the list
// Add any possible gap at the end of n to the length of n
n.next = pnode.next;
pnode.next = n;
n.coalesce(memoryEnd);
pnode.coalesce;
root = pnode;
return true;
Expand Down Expand Up @@ -771,3 +790,91 @@ unittest
p = alloc.allocateAll();
assert(p.length == 1024 * 1024);
}

unittest
{
import std.experimental.allocator.building_blocks;
import std.random;
import std.typecons : Ternary;

// Both sequences must work on either system

// A sequence of allocs which generates the error described in issue 16564
// that is a gap at the end of buf from the perspective of the allocator

// for 64 bit systems (leftover balance = 8 bytes < 16)
int[] sizes64 = [18904, 2008, 74904, 224, 111904, 1904, 52288, 8];

// for 32 bit systems (leftover balance < 8)
int[] sizes32 = [81412, 107068, 49892, 23768];


void test(int[] sizes)
{
ubyte[256 * 1024] buf;
auto a = KRRegion!()(buf);

void[][] bufs;

foreach (size; sizes)
{
bufs ~= a.allocate(size);
}

foreach (b; bufs.randomCover)
{
a.deallocate(b);
}

assert(a.empty == Ternary.yes);
}

test(sizes64);
test(sizes32);
}

unittest
{
import std.experimental.allocator.building_blocks;
import std.random;
import std.typecons : Ternary;

// For 64 bits, we allocate in multiples of 8, but the minimum alloc size is 16.
// This can create gaps.
// This test is an example of such a case. The gap is formed between the block
// allocated for the second value in sizes and the third. There is also a gap
// at the very end. (total lost 2 * word)

int[] sizes64 = [2008, 18904, 74904, 224, 111904, 1904, 52288, 8];
int[] sizes32 = [81412, 107068, 49892, 23768];

int word64 = 8;
int word32 = 4;

void test(int[] sizes, int word)
{
ubyte[256 * 1024] buf;
auto a = KRRegion!()(buf);

void[][] bufs;

foreach (size; sizes)
{
bufs ~= a.allocate(size);
}

a.deallocate(bufs[1]);
bufs ~= a.allocate(sizes[1] - word);

a.deallocate(bufs[0]);
foreach (i; 2..bufs.length)
{
a.deallocate(bufs[i]);
}

assert(a.empty == Ternary.yes);
}

test(sizes64, word64);
test(sizes32, word32);
}

0 comments on commit 8a69b10

Please sign in to comment.