From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/heap.c | 2 + dlls/kernel32/tests/heap.c | 11 ---- dlls/kernelbase/memory.c | 111 ++++++++++++++----------------------- 3 files changed, 45 insertions(+), 79 deletions(-)
diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index df094c94257..6a1a02c814b 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -315,6 +315,8 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr ) */ HGLOBAL WINAPI GlobalReAlloc( HGLOBAL handle, SIZE_T size, UINT flags ) { + struct mem_entry *mem; + if ((mem = unsafe_mem_from_HLOCAL( handle )) && mem->lock) return 0; return LocalReAlloc( handle, size, flags ); }
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 97f4d9c9fe3..c237d515648 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1635,9 +1635,7 @@ static void test_GlobalAlloc(void) mem = GlobalAlloc( GMEM_FIXED, 10 ); ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); tmp_mem = GlobalReAlloc( mem, 9, GMEM_MODIFY ); - todo_wine ok( !!tmp_mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); size = GlobalSize( mem ); ok( size == 10, "GlobalSize returned %Iu\n", size ); @@ -1651,9 +1649,7 @@ static void test_GlobalAlloc(void) "got error %lu\n", GetLastError() ); if (tmp_mem) mem = tmp_mem; tmp_mem = GlobalReAlloc( mem, 1024 * 1024, GMEM_MODIFY ); - todo_wine ok( !!tmp_mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); size = GlobalSize( mem ); ok( size == 10, "GlobalSize returned %Iu\n", size ); @@ -1988,9 +1984,7 @@ static void test_LocalAlloc(void) mem = LocalAlloc( LMEM_FIXED, 10 ); ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); tmp_mem = LocalReAlloc( mem, 9, LMEM_MODIFY ); - todo_wine ok( !!tmp_mem, "LocalAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); size = LocalSize( mem ); ok( size == 10, "LocalSize returned %Iu\n", size ); @@ -2004,9 +1998,7 @@ static void test_LocalAlloc(void) "got error %lu\n", GetLastError() ); if (tmp_mem) mem = tmp_mem; tmp_mem = LocalReAlloc( mem, 1024 * 1024, LMEM_MODIFY ); - todo_wine ok( !!tmp_mem, "LocalAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); size = LocalSize( mem ); ok( size == 10, "LocalSize returned %Iu\n", size ); @@ -2105,13 +2097,10 @@ static void test_LocalAlloc(void) tmp_mem = LocalHandle( ptr ); ok( tmp_mem == mem, "LocalHandle returned unexpected handle\n" ); tmp_mem = LocalDiscard( mem ); - todo_wine ok( !!tmp_mem, "LocalDiscard failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "LocalDiscard returned unexpected handle\n" ); ret = LocalUnlock( mem ); ok( !ret, "LocalUnlock succeeded, error %lu\n", GetLastError() ); - todo_wine ok( GetLastError() == ERROR_NOT_LOCKED, "got error %lu\n", GetLastError() );
tmp_mem = LocalDiscard( mem ); diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 776f0aafa18..341b859b555 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -868,6 +868,7 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) if (!size) mem->flags |= MEM_FLAG_DISCARDED; else { + if (size + HLOCAL_STORAGE < size) goto failed; if (!(ptr = HeapAlloc( heap, heap_flags, size + HLOCAL_STORAGE ))) goto failed; *(HLOCAL *)ptr = handle; mem->ptr = (char *)ptr + HLOCAL_STORAGE; @@ -967,7 +968,8 @@ LPVOID WINAPI DECLSPEC_HOTPATCH LocalLock( HLOCAL handle ) */ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL handle, SIZE_T size, UINT flags ) { - DWORD heap_flags = HEAP_ADD_USER_INFO; + DWORD heap_flags = HEAP_ADD_USER_INFO | HEAP_NO_SERIALIZE; + HANDLE heap = GetProcessHeap(); struct mem_entry *mem; HLOCAL ret = 0; void *ptr; @@ -976,90 +978,63 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL handle, SIZE_T size, UINT f
if (flags & LMEM_ZEROINIT) heap_flags |= HEAP_ZERO_MEMORY;
- RtlLockHeap( GetProcessHeap() ); - if (flags & LMEM_MODIFY) /* modify flags */ + RtlLockHeap( heap ); + if ((ptr = unsafe_ptr_from_HLOCAL( handle ))) { - if (unsafe_ptr_from_HLOCAL( handle ) && (flags & LMEM_MOVEABLE)) + if (!(flags & LMEM_MOVEABLE)) { - /* make a fixed block moveable - * actually only NT is able to do this. But it's soo simple - */ - if (handle == 0) - { - WARN_(globalmem)( "null handle\n" ); - SetLastError( ERROR_NOACCESS ); - } - else - { - size = RtlSizeHeap( GetProcessHeap(), 0, handle ); - ret = LocalAlloc( flags, size ); - ptr = LocalLock( ret ); - memcpy( ptr, handle, size ); - LocalUnlock( ret ); - LocalFree( handle ); - } + heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY; + if (!(flags & LMEM_MODIFY) || !(flags & LMEM_MOVEABLE)) ret = handle; + else ret = HeapReAlloc( heap, heap_flags, ptr, size ); } - else if ((mem = unsafe_mem_from_HLOCAL( handle )) && (flags & LMEM_DISCARDABLE)) + else if (flags & LMEM_MODIFY) { - /* change the flags to make our block "discardable" */ - mem->flags |= LMEM_DISCARDABLE >> 8; - ret = handle; + size = RtlSizeHeap( heap, 0, handle ); + ret = LocalAlloc( flags, size ); + ptr = LocalLock( ret ); + memcpy( ptr, handle, size ); + LocalUnlock( ret ); + LocalFree( handle ); } - else SetLastError( ERROR_INVALID_PARAMETER ); + else ret = HeapReAlloc( heap, heap_flags, handle, size ); } - else + else if ((mem = unsafe_mem_from_HLOCAL( handle ))) { - if ((ptr = unsafe_ptr_from_HLOCAL( handle ))) + if (!(flags & LMEM_MODIFY)) { - /* reallocate fixed memory */ - if (!(flags & LMEM_MOVEABLE)) heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY; - ret = HeapReAlloc( GetProcessHeap(), heap_flags, ptr, size ); - } - else if ((mem = unsafe_mem_from_HLOCAL( handle ))) - { - /* reallocate a moveable block */ - if (size != 0) + if (size) { - if (size <= INT_MAX - HLOCAL_STORAGE) + if (size + HLOCAL_STORAGE < size) ptr = NULL; + else if (!mem->ptr) ptr = HeapAlloc( heap, heap_flags, size + HLOCAL_STORAGE ); + else ptr = HeapReAlloc( heap, heap_flags, (char *)mem->ptr - HLOCAL_STORAGE, size + HLOCAL_STORAGE ); + + if (!ptr) SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + else { - if (mem->ptr) - { - if ((ptr = HeapReAlloc( GetProcessHeap(), heap_flags, (char *)mem->ptr - HLOCAL_STORAGE, - size + HLOCAL_STORAGE ))) - { - mem->ptr = (char *)ptr + HLOCAL_STORAGE; - ret = handle; - } - } - else - { - if ((ptr = HeapAlloc( GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE ))) - { - *(HLOCAL *)ptr = handle; - mem->ptr = (char *)ptr + HLOCAL_STORAGE; - ret = handle; - } - } + mem->flags &= ~MEM_FLAG_DISCARDED; + mem->ptr = (char *)ptr + HLOCAL_STORAGE; + ret = handle; } - else SetLastError( ERROR_OUTOFMEMORY ); } else { - if (mem->lock == 0) - { - if (mem->ptr) - { - HeapFree( GetProcessHeap(), 0, (char *)mem->ptr - HLOCAL_STORAGE ); - mem->ptr = NULL; - } - ret = handle; - } - else WARN_(globalmem)( "not freeing memory associated with locked handle\n" ); + if (mem->ptr) HeapFree( heap, heap_flags, (char *)mem->ptr - HLOCAL_STORAGE ); + mem->flags |= MEM_FLAG_DISCARDED; + mem->lock = 0; + mem->ptr = NULL; + ret = handle; } } - else SetLastError( ERROR_INVALID_HANDLE ); + else if (flags & LMEM_DISCARDABLE) + { + mem->flags |= MEM_FLAG_DISCARDABLE; + ret = handle; + } + else SetLastError( ERROR_INVALID_PARAMETER ); } - RtlUnlockHeap( GetProcessHeap() ); + else SetLastError( ERROR_INVALID_HANDLE ); + RtlUnlockHeap( heap ); + return ret; }