* Remove postcondition for functions calculating alignment
* Put MmapPool invariant into version (none) block
* Check that alignment doesn't overflow
This commit is contained in:
Eugen Wissner 2017-07-11 10:27:24 +02:00
parent 7bdc778390
commit fc53779d3f

View File

@ -52,18 +52,21 @@ else version (Windows)
*/ */
final class MmapPool : Allocator final class MmapPool : Allocator
{ {
invariant version (none)
{ {
for (auto r = &head; *r !is null; r = &((*r).next)) pure nothrow @nogc invariant
{ {
auto block = cast(Block) (cast(void*) *r + RegionEntry.sizeof); for (auto r = &head; *r !is null; r = &((*r).next))
do
{ {
assert(block.prev is null || block.prev.next is block); auto block = cast(Block) (cast(void*) *r + RegionEntry.sizeof);
assert(block.next is null || block.next.prev is block); do
assert(block.region is *r); {
assert(block.prev is null || block.prev.next is block);
assert(block.next is null || block.next.prev is block);
assert(block.region is *r);
}
while ((block = block.next) !is null);
} }
while ((block = block.next) !is null);
} }
} }
@ -77,11 +80,15 @@ final class MmapPool : Allocator
*/ */
void[] allocate(const size_t size) shared nothrow @nogc void[] allocate(const size_t size) shared nothrow @nogc
{ {
if (!size) if (size == 0)
{ {
return null; return null;
} }
const dataSize = addAlignment(size); const dataSize = addAlignment(size);
if (dataSize < size)
{
return null;
}
void* data = findBlock(dataSize); void* data = findBlock(dataSize);
if (data is null) if (data is null)
@ -103,6 +110,24 @@ final class MmapPool : Allocator
assert(p.length == 0); assert(p.length == 0);
} }
// Issue 245: https://issues.caraus.io/issues/245.
private @nogc unittest
{
// allocate() check.
size_t tooMuchMemory = size_t.max
- MmapPool.alignment_
- BlockEntry.sizeof * 2
- RegionEntry.sizeof
- pageSize;
assert(MmapPool.instance.allocate(tooMuchMemory) is null);
assert(MmapPool.instance.allocate(size_t.max) is null);
// initializeRegion() check.
tooMuchMemory = size_t.max - MmapPool.alignment_;
assert(MmapPool.instance.allocate(tooMuchMemory) is null);
}
/* /*
* Search for a block large enough to keep $(D_PARAM size) and split it * Search for a block large enough to keep $(D_PARAM size) and split it
* into two blocks if the block is too large. * into two blocks if the block is too large.
@ -262,19 +287,25 @@ final class MmapPool : Allocator
if (block1.size >= size) if (block1.size >= size)
{ {
// Enough space in the current block. Can happen because of the alignment. // Enough space in the current block.
p = p.ptr[0 .. size]; p = p.ptr[0 .. size];
return true; return true;
} }
const dataSize = addAlignment(size); const dataSize = addAlignment(size);
const delta = dataSize - addAlignment(p.length); const pAlignment = addAlignment(p.length);
assert(pAlignment >= p.length, "Invalid memory chunk length");
const delta = dataSize - pAlignment;
if (block1.next is null if (block1.next is null
|| !block1.next.free || !block1.next.free
|| dataSize < size
|| block1.next.size + BlockEntry.sizeof < delta) || block1.next.size + BlockEntry.sizeof < delta)
{ {
// It is the last block in the region or the next block is too small or not /* * It is the last block in the region
// free. * * The next block is too small
* * The next block isn't free
* * Requested size is too large
*/
return false; return false;
} }
if (block1.next.size >= delta + alignment_) if (block1.next.size >= delta + alignment_)
@ -453,11 +484,14 @@ final class MmapPool : Allocator
* *
* Returns: A pointer to the data. * Returns: A pointer to the data.
*/ */
private static void* initializeRegion(size_t size, ref Region head) private static void* initializeRegion(const size_t size, ref Region head)
nothrow @nogc nothrow @nogc
{ {
const regionSize = calculateRegionSize(size); const regionSize = calculateRegionSize(size);
if (regionSize < size)
{
return null;
}
version (Posix) version (Posix)
{ {
void* p = mmap(null, void* p = mmap(null,
@ -518,7 +552,7 @@ final class MmapPool : Allocator
return data; return data;
} }
private void* initializeRegion(size_t size) shared nothrow @nogc private void* initializeRegion(const size_t size) shared nothrow @nogc
{ {
return initializeRegion(size, head); return initializeRegion(size, head);
} }
@ -529,12 +563,7 @@ final class MmapPool : Allocator
* *
* Returns: Aligned size of $(D_PARAM x). * Returns: Aligned size of $(D_PARAM x).
*/ */
private static size_t addAlignment(size_t x) pure nothrow @safe @nogc private static size_t addAlignment(const size_t x) pure nothrow @safe @nogc
out (result)
{
assert(result > 0);
}
body
{ {
return (x - 1) / alignment_ * alignment_ + alignment_; return (x - 1) / alignment_ * alignment_ + alignment_;
} }
@ -545,15 +574,11 @@ final class MmapPool : Allocator
* *
* Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)). * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
*/ */
private static size_t calculateRegionSize(size_t x) nothrow @safe @nogc private static size_t calculateRegionSize(const size_t x)
out (result) nothrow @safe @nogc
{ {
assert(result > 0); return (x + RegionEntry.sizeof + BlockEntry.sizeof * 2)
} / pageSize * pageSize + pageSize;
body
{
x += RegionEntry.sizeof + BlockEntry.sizeof * 2;
return x / pageSize * pageSize + pageSize;
} }
/** /**
@ -597,7 +622,7 @@ final class MmapPool : Allocator
// A lot of allocations/deallocations, but it is the minimum caused a // A lot of allocations/deallocations, but it is the minimum caused a
// segmentation fault because MmapPool reallocateInPlace moves a block wrong. // segmentation fault because MmapPool reallocateInPlace moves a block wrong.
unittest private @nogc unittest
{ {
auto a = MmapPool.instance.allocate(16); auto a = MmapPool.instance.allocate(16);
auto d = MmapPool.instance.allocate(16); auto d = MmapPool.instance.allocate(16);