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"); }