summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-01-14 20:39:33 +0100
committerEugen Wissner <belka@caraus.de>2017-01-14 20:39:33 +0100
commitc567b88d5d3a4547c871ebb010ba96bdbb62c5a2 (patch)
treed9d74957f13bc5c9bcb77e7fbc4c5328c7076ca7
parentfe884541fc8bef9d6e0efb45ce4a92e73c5666bb (diff)
downloadtanya-c567b88d5d3a4547c871ebb010ba96bdbb62c5a2.tar.gz
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).
-rw-r--r--source/tanya/memory/mmappool.d74
-rw-r--r--source/tanya/network/socket.d116
2 files changed, 122 insertions, 68 deletions
diff --git a/source/tanya/memory/mmappool.d b/source/tanya/memory/mmappool.d
index a363219..804954b 100644
--- a/source/tanya/memory/mmappool.d
+++ b/source/tanya/memory/mmappool.d
@@ -243,7 +243,7 @@ final class MmapPool : Allocator
return true;
}
immutable dataSize = addAlignment(size);
- immutable delta = dataSize - p.length;
+ immutable delta = dataSize - addAlignment(p.length);
if (block1.next is null
|| !block1.next.free
@@ -255,21 +255,17 @@ final class MmapPool : Allocator
}
if (block1.next.size >= delta + alignment_)
{
- // We should move the start position of the next block. The order may be
- // important because the old block and the new one can overlap.
- 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;
-
+ // Move size from block2 to block1.
+ block1.next.size = block1.next.size - delta;
block1.size = block1.size + delta;
+ auto block2 = cast(Block) (p.ptr + dataSize);
if (block1.next.next !is null)
{
block1.next.next.prev = block2;
}
+ // block1.next and block2 can overlap.
+ memmove(cast(void*) block2, cast(void*) block1.next, BlockEntry.sizeof);
block1.next = block2;
}
else
@@ -574,3 +570,61 @@ final class MmapPool : Allocator
}
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);
+}
diff --git a/source/tanya/network/socket.d b/source/tanya/network/socket.d
index eb808ba..17bcfa4 100644
--- a/source/tanya/network/socket.d
+++ b/source/tanya/network/socket.d
@@ -174,13 +174,13 @@ else version (Windows)
alias WSASocket = WSASocketW;
alias LPFN_GETACCEPTEXSOCKADDRS = VOID function(PVOID,
- DWORD,
- DWORD,
- DWORD,
- SOCKADDR**,
- LPINT,
- SOCKADDR**,
- LPINT);
+ DWORD,
+ DWORD,
+ DWORD,
+ SOCKADDR**,
+ LPINT,
+ SOCKADDR**,
+ LPINT);
const GUID WSAID_GETACCEPTEXSOCKADDRS = {0xb5367df2,0xcbac,0x11cf,[0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
struct WSABUF {
@@ -248,23 +248,23 @@ else version (Windows)
* Throws: $(D_PSYMBOL SocketException) if unable to receive.
*/
bool beginReceive(ubyte[] buffer,
- SocketState overlapped,
- Flags flags = Flags(Flag.none)) @nogc @trusted
+ SocketState overlapped,
+ Flags flags = Flags(Flag.none)) @nogc @trusted
{
auto receiveFlags = cast(DWORD) flags;
overlapped.handle = cast(HANDLE) handle_;
overlapped.event = OverlappedSocketEvent.read;
- overlapped.buffer.len = buffer.length;
+ overlapped.buffer.len = cast(ULONG) buffer.length;
overlapped.buffer.buf = cast(char*) buffer.ptr;
auto result = WSARecv(handle_,
- &overlapped.buffer,
- 1u,
- NULL,
- &receiveFlags,
- &overlapped.overlapped,
- NULL);
+ &overlapped.buffer,
+ 1u,
+ NULL,
+ &receiveFlags,
+ &overlapped.overlapped,
+ NULL);
if (result == SOCKET_ERROR && !wouldHaveBlocked)
{
@@ -292,9 +292,9 @@ else version (Windows)
{
DWORD lpNumber;
BOOL result = GetOverlappedResult(overlapped.handle,
- &overlapped.overlapped,
- &lpNumber,
- FALSE);
+ &overlapped.overlapped,
+ &lpNumber,
+ FALSE);
if (result == FALSE && !wouldHaveBlocked)
{
disconnected_ = true;
@@ -321,21 +321,21 @@ else version (Windows)
* Throws: $(D_PSYMBOL SocketException) if unable to send.
*/
bool beginSend(ubyte[] buffer,
- SocketState overlapped,
- Flags flags = Flags(Flag.none)) @nogc @trusted
+ SocketState overlapped,
+ Flags flags = Flags(Flag.none)) @nogc @trusted
{
overlapped.handle = cast(HANDLE) handle_;
overlapped.event = OverlappedSocketEvent.write;
- overlapped.buffer.len = buffer.length;
+ overlapped.buffer.len = cast(ULONG) buffer.length;
overlapped.buffer.buf = cast(char*) buffer.ptr;
auto result = WSASend(handle_,
- &overlapped.buffer,
- 1u,
- NULL,
- cast(DWORD) flags,
- &overlapped.overlapped,
- NULL);
+ &overlapped.buffer,
+ 1u,
+ NULL,
+ cast(DWORD) flags,
+ &overlapped.overlapped,
+ NULL);
if (result == SOCKET_ERROR && !wouldHaveBlocked)
{
@@ -364,9 +364,9 @@ else version (Windows)
{
DWORD lpNumber;
BOOL result = GetOverlappedResult(overlapped.handle,
- &overlapped.overlapped,
- &lpNumber,
- FALSE);
+ &overlapped.overlapped,
+ &lpNumber,
+ FALSE);
if (result == FALSE && !wouldHaveBlocked)
{
disconnected_ = true;
@@ -385,7 +385,7 @@ else version (Windows)
* Create a socket.
*
* Params:
- * af = Address family.
+ * af = Address family.
*
* Throws: $(D_PSYMBOL SocketException) on errors.
*/
@@ -402,14 +402,14 @@ else version (Windows)
DWORD dwBytes;
auto result = WSAIoctl(handle_,
- SIO_GET_EXTENSION_FUNCTION_POINTER,
- &guidAcceptEx,
- guidAcceptEx.sizeof,
- &acceptExtension,
- acceptExtension.sizeof,
- &dwBytes,
- NULL,
- NULL);
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &guidAcceptEx,
+ guidAcceptEx.sizeof,
+ &acceptExtension,
+ acceptExtension.sizeof,
+ &dwBytes,
+ NULL,
+ NULL);
if (!result == SOCKET_ERROR)
{
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
BOOL result = acceptExtension(handle_,
- socket,
- overlapped.buffer.buf,
- 0u,
- sockaddr_in.sizeof + 16,
- sockaddr_in.sizeof + 16,
- &dwBytes,
- &overlapped.overlapped);
+ socket,
+ overlapped.buffer.buf,
+ 0u,
+ sockaddr_in.sizeof + 16,
+ sockaddr_in.sizeof + 16,
+ &dwBytes,
+ &overlapped.overlapped);
if (result == FALSE && !wouldHaveBlocked)
{
throw defaultAllocator.make!SocketException("Unable to accept socket connection");
@@ -478,7 +478,7 @@ else version (Windows)
{
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,
cast(socket_t) overlapped.handle,
@@ -539,9 +539,9 @@ shared static this()
auto ws2Lib = GetModuleHandle("ws2_32.dll");
getaddrinfoPointer = cast(typeof(getaddrinfoPointer))
- GetProcAddress(ws2Lib, "getaddrinfo");
+ GetProcAddress(ws2Lib, "getaddrinfo");
freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer))
- GetProcAddress(ws2Lib, "freeaddrinfo");
+ GetProcAddress(ws2Lib, "freeaddrinfo");
}
else version (Posix)
{
@@ -754,10 +754,10 @@ abstract class Socket
{
auto length = cast(socklen_t) result.length;
if (getsockopt(handle_,
- cast(int) level,
- cast(int) option,
- result.ptr,
- &length) == SOCKET_ERROR)
+ cast(int) level,
+ cast(int) option,
+ result.ptr,
+ &length) == SOCKET_ERROR)
{
throw defaultAllocator.make!SocketException("Unable to get socket option");
}
@@ -821,10 +821,10 @@ abstract class Socket
void[] value) const @trusted @nogc
{
if (setsockopt(handle_,
- cast(int)level,
- cast(int)option,
- value.ptr,
- cast(uint) value.length) == SOCKET_ERROR)
+ cast(int)level,
+ cast(int)option,
+ value.ptr,
+ cast(uint) value.length) == SOCKET_ERROR)
{
throw defaultAllocator.make!SocketException("Unable to set socket option");
}