Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/dparse/rollback_allocator.d
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module dparse.rollback_allocator;

import core.memory : GC;

//version = debug_rollback_allocator;

/**
Expand Down Expand Up @@ -147,6 +149,7 @@ private:
ubyte[] m = cast(ubyte[]) AlignedMallocator.instance.alignedAllocate(max(size + Node.sizeof, ALLOC_SIZE), memoryAlignment);
if (m is null)
onOutOfMemoryError();
GC.addRange(m.ptr, m.length);

version (debug_rollback_allocator)
m[] = 0;
Expand All @@ -164,6 +167,7 @@ private:
ubyte[] mem = (cast(ubyte*) first)[0 .. Node.sizeof + first.mem.length];
version (debug_rollback_allocator)
mem[] = 0;
GC.removeRange(mem.ptr);
AlignedMallocator.instance.deallocate(mem);
first = next;
}
Expand Down
13 changes: 13 additions & 0 deletions src/dparse/stack_buffer.d
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module dparse.stack_buffer;

import core.memory : GC;

import std.traits;

//version = debug_stack_allocator;
Expand All @@ -20,14 +22,21 @@ struct StackBuffer
static if (is(T == class))
static assert(T.sizeof == size_t.sizeof);

static if (hasIndirections!T)
while (_length % size_t.sizeof != 0)
put(ubyte(1));

if (arr.ptr != stackSpace.ptr)
{
if (_length + T.sizeof > arr.length)
{
size_t newLength = arr.length << 1;
while (_length + T.sizeof > newLength)
newLength <<= 1;
auto oldPtr = arr.ptr;
Mallocator.instance.reallocate(arr, newLength);
GC.removeRange(oldPtr);
Copy link
Member Author

@CyberShadow CyberShadow Jul 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a race condition here, which is unavoidable with the reallocate API.

We need to call removeRange after the data is copied, and after calling addRange on the new copy, but before the old buffer is deallocated. reallocate does both the copy and the deallocation together.

A bit surprising that stdx.allocator doesn't have a layer which calls addRange/removeRange, though maybe that kind of defeats the point of using custom allocators.

Also note that we can't make this call conditional on hasIndirections!T because T is just for the value being allocated right now, we don't know what the rest of the buffer contains, nor can we know if the buffer will be completely used for types without indirections.

GC.addRange(arr.ptr, arr.length);
version (debug_stack_allocator)
(cast(ubyte[]) arr)[_length .. $] = 0;
}
Expand All @@ -38,6 +47,7 @@ struct StackBuffer
while (_length + T.sizeof > newLength)
newLength <<= 1;
arr = Mallocator.instance.allocate(newLength);
GC.addRange(arr.ptr, arr.length);
version (debug_stack_allocator)
(cast(ubyte[]) arr)[] = 0;
arr[0 .. stackSpace.length] = stackSpace[];
Expand All @@ -54,7 +64,10 @@ struct StackBuffer
version (debug_stack_allocator)
(cast(ubyte[]) arr)[] = 0;
if (arr.ptr !is stackSpace.ptr)
{
GC.removeRange(arr.ptr);
Mallocator.instance.deallocate(arr);
}
}

void[] opSlice()
Expand Down