MmapPool: Fix expand block moving.
D dereferences the pointer wrong because of missing difference between . and -> operators, if trying to write a block over another block. So use memmove first to move the memory and then update the fields that should be changed (only size).
This commit is contained in:
parent
fe884541fc
commit
c567b88d5d
@ -243,7 +243,7 @@ final class MmapPool : Allocator
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
immutable dataSize = addAlignment(size);
|
immutable dataSize = addAlignment(size);
|
||||||
immutable delta = dataSize - p.length;
|
immutable delta = dataSize - addAlignment(p.length);
|
||||||
|
|
||||||
if (block1.next is null
|
if (block1.next is null
|
||||||
|| !block1.next.free
|
|| !block1.next.free
|
||||||
@ -255,21 +255,17 @@ final class MmapPool : Allocator
|
|||||||
}
|
}
|
||||||
if (block1.next.size >= delta + alignment_)
|
if (block1.next.size >= delta + alignment_)
|
||||||
{
|
{
|
||||||
// We should move the start position of the next block. The order may be
|
// Move size from block2 to block1.
|
||||||
// important because the old block and the new one can overlap.
|
block1.next.size = block1.next.size - delta;
|
||||||
auto block2 = cast(Block) (p.ptr + dataSize);
|
|
||||||
block2.size = block1.next.size - delta;
|
|
||||||
block2.free = true;
|
|
||||||
block2.region = block1.region;
|
|
||||||
block2.next = block1.next.next;
|
|
||||||
block2.prev = block1;
|
|
||||||
|
|
||||||
block1.size = block1.size + delta;
|
block1.size = block1.size + delta;
|
||||||
|
|
||||||
|
auto block2 = cast(Block) (p.ptr + dataSize);
|
||||||
if (block1.next.next !is null)
|
if (block1.next.next !is null)
|
||||||
{
|
{
|
||||||
block1.next.next.prev = block2;
|
block1.next.next.prev = block2;
|
||||||
}
|
}
|
||||||
|
// block1.next and block2 can overlap.
|
||||||
|
memmove(cast(void*) block2, cast(void*) block1.next, BlockEntry.sizeof);
|
||||||
block1.next = block2;
|
block1.next = block2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -574,3 +570,61 @@ final class MmapPool : Allocator
|
|||||||
}
|
}
|
||||||
private alias Block = shared BlockEntry*;
|
private alias Block = shared BlockEntry*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A lot of allocations/deallocations, but it is the minimum caused a
|
||||||
|
// segmentation fault because MmapPool expand moves a block wrong.
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto a = MmapPool.instance.allocate(16);
|
||||||
|
auto d = MmapPool.instance.allocate(16);
|
||||||
|
auto b = MmapPool.instance.allocate(16);
|
||||||
|
auto e = MmapPool.instance.allocate(16);
|
||||||
|
auto c = MmapPool.instance.allocate(16);
|
||||||
|
auto f = MmapPool.instance.allocate(16);
|
||||||
|
|
||||||
|
MmapPool.instance.deallocate(a);
|
||||||
|
MmapPool.instance.deallocate(b);
|
||||||
|
MmapPool.instance.deallocate(c);
|
||||||
|
|
||||||
|
a = MmapPool.instance.allocate(50);
|
||||||
|
MmapPool.instance.expand(a, 64);
|
||||||
|
MmapPool.instance.deallocate(a);
|
||||||
|
|
||||||
|
a = MmapPool.instance.allocate(1);
|
||||||
|
auto tmp1 = MmapPool.instance.allocate(1);
|
||||||
|
auto h1 = MmapPool.instance.allocate(1);
|
||||||
|
auto tmp2 = cast(ubyte[]) MmapPool.instance.allocate(1);
|
||||||
|
|
||||||
|
auto h2 = MmapPool.instance.allocate(2);
|
||||||
|
tmp1 = MmapPool.instance.allocate(1);
|
||||||
|
MmapPool.instance.deallocate(h2);
|
||||||
|
MmapPool.instance.deallocate(h1);
|
||||||
|
|
||||||
|
h2 = MmapPool.instance.allocate(2);
|
||||||
|
h1 = MmapPool.instance.allocate(1);
|
||||||
|
MmapPool.instance.deallocate(h2);
|
||||||
|
|
||||||
|
auto rep = cast(void[]) tmp2;
|
||||||
|
MmapPool.instance.reallocate(rep, tmp1.length);
|
||||||
|
tmp2 = cast(ubyte[]) rep;
|
||||||
|
|
||||||
|
MmapPool.instance.reallocate(tmp1, 9);
|
||||||
|
|
||||||
|
rep = cast(void[]) tmp2;
|
||||||
|
MmapPool.instance.reallocate(rep, tmp1.length);
|
||||||
|
tmp2 = cast(ubyte[]) rep;
|
||||||
|
MmapPool.instance.reallocate(tmp1, 17);
|
||||||
|
|
||||||
|
tmp2[$ - 1] = 0;
|
||||||
|
|
||||||
|
MmapPool.instance.deallocate(tmp1);
|
||||||
|
|
||||||
|
b = MmapPool.instance.allocate(16);
|
||||||
|
|
||||||
|
MmapPool.instance.deallocate(h1);
|
||||||
|
MmapPool.instance.deallocate(a);
|
||||||
|
MmapPool.instance.deallocate(b);
|
||||||
|
MmapPool.instance.deallocate(d);
|
||||||
|
MmapPool.instance.deallocate(e);
|
||||||
|
MmapPool.instance.deallocate(f);
|
||||||
|
}
|
||||||
|
@ -174,13 +174,13 @@ else version (Windows)
|
|||||||
alias WSASocket = WSASocketW;
|
alias WSASocket = WSASocketW;
|
||||||
|
|
||||||
alias LPFN_GETACCEPTEXSOCKADDRS = VOID function(PVOID,
|
alias LPFN_GETACCEPTEXSOCKADDRS = VOID function(PVOID,
|
||||||
DWORD,
|
DWORD,
|
||||||
DWORD,
|
DWORD,
|
||||||
DWORD,
|
DWORD,
|
||||||
SOCKADDR**,
|
SOCKADDR**,
|
||||||
LPINT,
|
LPINT,
|
||||||
SOCKADDR**,
|
SOCKADDR**,
|
||||||
LPINT);
|
LPINT);
|
||||||
const GUID WSAID_GETACCEPTEXSOCKADDRS = {0xb5367df2,0xcbac,0x11cf,[0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
|
const GUID WSAID_GETACCEPTEXSOCKADDRS = {0xb5367df2,0xcbac,0x11cf,[0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
|
||||||
|
|
||||||
struct WSABUF {
|
struct WSABUF {
|
||||||
@ -248,23 +248,23 @@ else version (Windows)
|
|||||||
* Throws: $(D_PSYMBOL SocketException) if unable to receive.
|
* Throws: $(D_PSYMBOL SocketException) if unable to receive.
|
||||||
*/
|
*/
|
||||||
bool beginReceive(ubyte[] buffer,
|
bool beginReceive(ubyte[] buffer,
|
||||||
SocketState overlapped,
|
SocketState overlapped,
|
||||||
Flags flags = Flags(Flag.none)) @nogc @trusted
|
Flags flags = Flags(Flag.none)) @nogc @trusted
|
||||||
{
|
{
|
||||||
auto receiveFlags = cast(DWORD) flags;
|
auto receiveFlags = cast(DWORD) flags;
|
||||||
|
|
||||||
overlapped.handle = cast(HANDLE) handle_;
|
overlapped.handle = cast(HANDLE) handle_;
|
||||||
overlapped.event = OverlappedSocketEvent.read;
|
overlapped.event = OverlappedSocketEvent.read;
|
||||||
overlapped.buffer.len = buffer.length;
|
overlapped.buffer.len = cast(ULONG) buffer.length;
|
||||||
overlapped.buffer.buf = cast(char*) buffer.ptr;
|
overlapped.buffer.buf = cast(char*) buffer.ptr;
|
||||||
|
|
||||||
auto result = WSARecv(handle_,
|
auto result = WSARecv(handle_,
|
||||||
&overlapped.buffer,
|
&overlapped.buffer,
|
||||||
1u,
|
1u,
|
||||||
NULL,
|
NULL,
|
||||||
&receiveFlags,
|
&receiveFlags,
|
||||||
&overlapped.overlapped,
|
&overlapped.overlapped,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (result == SOCKET_ERROR && !wouldHaveBlocked)
|
if (result == SOCKET_ERROR && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
@ -292,9 +292,9 @@ else version (Windows)
|
|||||||
{
|
{
|
||||||
DWORD lpNumber;
|
DWORD lpNumber;
|
||||||
BOOL result = GetOverlappedResult(overlapped.handle,
|
BOOL result = GetOverlappedResult(overlapped.handle,
|
||||||
&overlapped.overlapped,
|
&overlapped.overlapped,
|
||||||
&lpNumber,
|
&lpNumber,
|
||||||
FALSE);
|
FALSE);
|
||||||
if (result == FALSE && !wouldHaveBlocked)
|
if (result == FALSE && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
disconnected_ = true;
|
disconnected_ = true;
|
||||||
@ -321,21 +321,21 @@ else version (Windows)
|
|||||||
* Throws: $(D_PSYMBOL SocketException) if unable to send.
|
* Throws: $(D_PSYMBOL SocketException) if unable to send.
|
||||||
*/
|
*/
|
||||||
bool beginSend(ubyte[] buffer,
|
bool beginSend(ubyte[] buffer,
|
||||||
SocketState overlapped,
|
SocketState overlapped,
|
||||||
Flags flags = Flags(Flag.none)) @nogc @trusted
|
Flags flags = Flags(Flag.none)) @nogc @trusted
|
||||||
{
|
{
|
||||||
overlapped.handle = cast(HANDLE) handle_;
|
overlapped.handle = cast(HANDLE) handle_;
|
||||||
overlapped.event = OverlappedSocketEvent.write;
|
overlapped.event = OverlappedSocketEvent.write;
|
||||||
overlapped.buffer.len = buffer.length;
|
overlapped.buffer.len = cast(ULONG) buffer.length;
|
||||||
overlapped.buffer.buf = cast(char*) buffer.ptr;
|
overlapped.buffer.buf = cast(char*) buffer.ptr;
|
||||||
|
|
||||||
auto result = WSASend(handle_,
|
auto result = WSASend(handle_,
|
||||||
&overlapped.buffer,
|
&overlapped.buffer,
|
||||||
1u,
|
1u,
|
||||||
NULL,
|
NULL,
|
||||||
cast(DWORD) flags,
|
cast(DWORD) flags,
|
||||||
&overlapped.overlapped,
|
&overlapped.overlapped,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (result == SOCKET_ERROR && !wouldHaveBlocked)
|
if (result == SOCKET_ERROR && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
@ -364,9 +364,9 @@ else version (Windows)
|
|||||||
{
|
{
|
||||||
DWORD lpNumber;
|
DWORD lpNumber;
|
||||||
BOOL result = GetOverlappedResult(overlapped.handle,
|
BOOL result = GetOverlappedResult(overlapped.handle,
|
||||||
&overlapped.overlapped,
|
&overlapped.overlapped,
|
||||||
&lpNumber,
|
&lpNumber,
|
||||||
FALSE);
|
FALSE);
|
||||||
if (result == FALSE && !wouldHaveBlocked)
|
if (result == FALSE && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
disconnected_ = true;
|
disconnected_ = true;
|
||||||
@ -385,7 +385,7 @@ else version (Windows)
|
|||||||
* Create a socket.
|
* Create a socket.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* af = Address family.
|
* af = Address family.
|
||||||
*
|
*
|
||||||
* Throws: $(D_PSYMBOL SocketException) on errors.
|
* Throws: $(D_PSYMBOL SocketException) on errors.
|
||||||
*/
|
*/
|
||||||
@ -402,14 +402,14 @@ else version (Windows)
|
|||||||
DWORD dwBytes;
|
DWORD dwBytes;
|
||||||
|
|
||||||
auto result = WSAIoctl(handle_,
|
auto result = WSAIoctl(handle_,
|
||||||
SIO_GET_EXTENSION_FUNCTION_POINTER,
|
SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||||
&guidAcceptEx,
|
&guidAcceptEx,
|
||||||
guidAcceptEx.sizeof,
|
guidAcceptEx.sizeof,
|
||||||
&acceptExtension,
|
&acceptExtension,
|
||||||
acceptExtension.sizeof,
|
acceptExtension.sizeof,
|
||||||
&dwBytes,
|
&dwBytes,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
if (!result == SOCKET_ERROR)
|
if (!result == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw make!SocketException(defaultAllocator,
|
throw make!SocketException(defaultAllocator,
|
||||||
@ -449,13 +449,13 @@ else version (Windows)
|
|||||||
|
|
||||||
// We don't want to get any data now, but only start to accept the connections
|
// We don't want to get any data now, but only start to accept the connections
|
||||||
BOOL result = acceptExtension(handle_,
|
BOOL result = acceptExtension(handle_,
|
||||||
socket,
|
socket,
|
||||||
overlapped.buffer.buf,
|
overlapped.buffer.buf,
|
||||||
0u,
|
0u,
|
||||||
sockaddr_in.sizeof + 16,
|
sockaddr_in.sizeof + 16,
|
||||||
sockaddr_in.sizeof + 16,
|
sockaddr_in.sizeof + 16,
|
||||||
&dwBytes,
|
&dwBytes,
|
||||||
&overlapped.overlapped);
|
&overlapped.overlapped);
|
||||||
if (result == FALSE && !wouldHaveBlocked)
|
if (result == FALSE && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to accept socket connection");
|
throw defaultAllocator.make!SocketException("Unable to accept socket connection");
|
||||||
@ -478,7 +478,7 @@ else version (Windows)
|
|||||||
{
|
{
|
||||||
scope (exit)
|
scope (exit)
|
||||||
{
|
{
|
||||||
defaultAllocator.dispose(overlapped.buffer.buf[0..overlapped.buffer.len]);
|
defaultAllocator.dispose(overlapped.buffer.buf[0 .. overlapped.buffer.len]);
|
||||||
}
|
}
|
||||||
auto socket = make!OverlappedConnectedSocket(defaultAllocator,
|
auto socket = make!OverlappedConnectedSocket(defaultAllocator,
|
||||||
cast(socket_t) overlapped.handle,
|
cast(socket_t) overlapped.handle,
|
||||||
@ -539,9 +539,9 @@ shared static this()
|
|||||||
auto ws2Lib = GetModuleHandle("ws2_32.dll");
|
auto ws2Lib = GetModuleHandle("ws2_32.dll");
|
||||||
|
|
||||||
getaddrinfoPointer = cast(typeof(getaddrinfoPointer))
|
getaddrinfoPointer = cast(typeof(getaddrinfoPointer))
|
||||||
GetProcAddress(ws2Lib, "getaddrinfo");
|
GetProcAddress(ws2Lib, "getaddrinfo");
|
||||||
freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer))
|
freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer))
|
||||||
GetProcAddress(ws2Lib, "freeaddrinfo");
|
GetProcAddress(ws2Lib, "freeaddrinfo");
|
||||||
}
|
}
|
||||||
else version (Posix)
|
else version (Posix)
|
||||||
{
|
{
|
||||||
@ -754,10 +754,10 @@ abstract class Socket
|
|||||||
{
|
{
|
||||||
auto length = cast(socklen_t) result.length;
|
auto length = cast(socklen_t) result.length;
|
||||||
if (getsockopt(handle_,
|
if (getsockopt(handle_,
|
||||||
cast(int) level,
|
cast(int) level,
|
||||||
cast(int) option,
|
cast(int) option,
|
||||||
result.ptr,
|
result.ptr,
|
||||||
&length) == SOCKET_ERROR)
|
&length) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to get socket option");
|
throw defaultAllocator.make!SocketException("Unable to get socket option");
|
||||||
}
|
}
|
||||||
@ -821,10 +821,10 @@ abstract class Socket
|
|||||||
void[] value) const @trusted @nogc
|
void[] value) const @trusted @nogc
|
||||||
{
|
{
|
||||||
if (setsockopt(handle_,
|
if (setsockopt(handle_,
|
||||||
cast(int)level,
|
cast(int)level,
|
||||||
cast(int)option,
|
cast(int)option,
|
||||||
value.ptr,
|
value.ptr,
|
||||||
cast(uint) value.length) == SOCKET_ERROR)
|
cast(uint) value.length) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to set socket option");
|
throw defaultAllocator.make!SocketException("Unable to set socket option");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user