diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index 86c16ef9b49..dbb240d89fc 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -151,10 +151,17 @@ BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ ) struct mem_entry { - WORD magic; - void *ptr; - BYTE flags; - BYTE lock; + union + { + struct + { + WORD magic; + void *ptr; + BYTE flags; + BYTE lock; + }; + void *next_free; + }; }; #include "poppack.h" @@ -173,7 +180,9 @@ struct kernelbase_global_data *kernelbase_global_data; static inline struct mem_entry *unsafe_mem_from_HLOCAL( HLOCAL handle ) { struct mem_entry *mem = CONTAINING_RECORD( handle, struct mem_entry, ptr ); + struct kernelbase_global_data *data = kernelbase_global_data; if (!((ULONG_PTR)handle & 2)) return NULL; + if (mem < data->mem_entries || mem >= data->mem_entries_end) return NULL; if (mem->magic != MAGIC_LOCAL_USED) return NULL; return mem; } @@ -276,8 +285,7 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr ) if ((mem = unsafe_mem_from_HLOCAL( handle ))) { test = mem->ptr; - if (HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, (const char *)test - HLOCAL_STORAGE ) && /* obj(-handle) valid arena? */ - HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, mem )) /* intern valid arena? */ + if (HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, (const char *)test - HLOCAL_STORAGE )) /* obj(-handle) valid arena? */ break; /* valid moveable block */ } handle = 0; diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index f6fb95cdddd..476be96cea8 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -290,15 +290,11 @@ static void test_GlobalAlloc(void) SetLastError( 0xdeadbeef ); mem = GlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 0 ); - todo_wine ok( !mem, "GlobalAlloc succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); mem = LocalAlloc( LMEM_MOVEABLE | LMEM_DISCARDABLE, 0 ); - todo_wine ok( !mem, "LocalAlloc succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); mem = GlobalAlloc( GMEM_DISCARDABLE, 0 ); @@ -417,7 +413,6 @@ static void test_GlobalAlloc(void) tmp_mem = GlobalFree( mem ); ok( !tmp_mem, "GlobalFree failed, error %lu\n", GetLastError() ); ok( !!entry->flags, "got unexpected flags %#Ix\n", entry->flags ); - todo_wine_if(sizeof(void *) == 4) ok( !((UINT_PTR)entry->flags & sizeof(void *)), "got unexpected ptr align\n" ); todo_wine_if(sizeof(void *) == 4) ok( !((UINT_PTR)entry->flags & (sizeof(void *) - 1)), "got unexpected ptr align\n" ); @@ -787,15 +782,11 @@ static void test_LocalAlloc(void) SetLastError( 0xdeadbeef ); mem = LocalAlloc( LMEM_MOVEABLE | LMEM_DISCARDABLE, 0 ); - todo_wine ok( !mem, "LocalAlloc succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); mem = GlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 0 ); - todo_wine ok( !mem, "GlobalAlloc succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); mem = LocalAlloc( LMEM_DISCARDABLE, 0 ); diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 6d42316760b..5bdab31589d 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -589,15 +589,30 @@ struct kernelbase_global_data struct mem_entry { - WORD magic; - void *ptr; - BYTE flags; - BYTE lock; + union + { + struct + { + WORD magic; + void *ptr; + BYTE flags; + BYTE lock; + }; + void *next_free; + }; }; #include "poppack.h" -static struct kernelbase_global_data kernelbase_global_data = {0}; +#define MAX_MEM_HANDLES 0x10000 +static struct mem_entry mem_entries[MAX_MEM_HANDLES]; +static struct mem_entry *next_free_mem = mem_entries; + +static struct kernelbase_global_data kernelbase_global_data = +{ + .mem_entries = mem_entries, + .mem_entries_end = mem_entries + MAX_MEM_HANDLES, +}; #define MAGIC_LOCAL_USED 0x5342 /* align the storage needed for the HLOCAL on an 8-byte boundary thus @@ -610,7 +625,9 @@ static struct kernelbase_global_data kernelbase_global_data = {0}; static inline struct mem_entry *unsafe_mem_from_HLOCAL( HLOCAL handle ) { struct mem_entry *mem = CONTAINING_RECORD( handle, struct mem_entry, ptr ); + struct kernelbase_global_data *data = &kernelbase_global_data; if (!((ULONG_PTR)handle & 2)) return NULL; + if (mem < data->mem_entries || mem >= data->mem_entries_end) return NULL; if (mem->magic != MAGIC_LOCAL_USED) return NULL; return mem; } @@ -666,8 +683,10 @@ HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalFree( HLOCAL handle ) */ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) { + HANDLE heap = GetProcessHeap(); struct mem_entry *mem; DWORD heap_flags = 0; + HLOCAL handle; void *ptr; TRACE_(globalmem)( "flags %#x, size %#Ix\n", flags, size ); @@ -676,36 +695,44 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) if (!(flags & LMEM_MOVEABLE)) /* pointer */ { - ptr = HeapAlloc( GetProcessHeap(), heap_flags, size ); + ptr = HeapAlloc( heap, heap_flags, size ); TRACE_(globalmem)( "return %p\n", ptr ); return ptr; } - if (size > INT_MAX - HLOCAL_STORAGE) + RtlLockHeap( heap ); + if ((mem = next_free_mem) < mem_entries || mem >= mem_entries + MAX_MEM_HANDLES) + mem = NULL; + else { - SetLastError( ERROR_OUTOFMEMORY ); - return 0; + if (!mem->next_free) next_free_mem++; + else next_free_mem = mem->next_free; + mem->next_free = NULL; } - if (!(mem = HeapAlloc( GetProcessHeap(), 0, sizeof(*mem) ))) return 0; + RtlUnlockHeap( heap ); + + if (!mem) goto failed; + handle = HLOCAL_from_mem( mem ); mem->magic = MAGIC_LOCAL_USED; mem->flags = flags >> 8; mem->lock = 0; + mem->ptr = NULL; if (size) { - if (!(ptr = HeapAlloc(GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE ))) - { - HeapFree( GetProcessHeap(), 0, mem ); - return 0; - } - *(HLOCAL *)ptr = HLOCAL_from_mem( mem ); + if (!(ptr = HeapAlloc( heap, heap_flags, size + HLOCAL_STORAGE ))) goto failed; + *(HLOCAL *)ptr = handle; mem->ptr = (char *)ptr + HLOCAL_STORAGE; } - else mem->ptr = NULL; - TRACE_(globalmem)( "return handle %p, ptr %p\n", HLOCAL_from_mem( mem ), mem->ptr ); - return HLOCAL_from_mem( mem ); + TRACE_(globalmem)( "return handle %p, ptr %p\n", handle, mem->ptr ); + return handle; + +failed: + if (mem) LocalFree( handle ); + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return 0; } @@ -714,52 +741,32 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) */ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalFree( HLOCAL handle ) { + HANDLE heap = GetProcessHeap(); struct mem_entry *mem; - HLOCAL ret; + HLOCAL ret = handle; void *ptr; TRACE_(globalmem)( "handle %p\n", handle ); - RtlLockHeap( GetProcessHeap() ); - __TRY + RtlLockHeap( heap ); + if ((ptr = unsafe_ptr_from_HLOCAL( handle ))) { - ret = 0; - if ((ptr = unsafe_ptr_from_HLOCAL( handle ))) - { - if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, ptr )) - { - SetLastError( ERROR_INVALID_HANDLE ); - ret = handle; - } - } - else /* HANDLE */ - { - if ((mem = unsafe_mem_from_HLOCAL( handle ))) - { - mem->magic = 0xdead; - if (mem->ptr) - { - if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, (char *)mem->ptr - HLOCAL_STORAGE )) - ret = handle; - } - if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, mem )) ret = handle; - } - else - { - WARN_(globalmem)( "invalid handle %p\n", handle ); - SetLastError( ERROR_INVALID_HANDLE ); - ret = handle; - } - } + if (HeapFree( heap, HEAP_NO_SERIALIZE, ptr )) ret = 0; } - __EXCEPT_PAGE_FAULT + else if ((mem = unsafe_mem_from_HLOCAL( handle ))) + { + if (!mem->ptr || HeapFree( heap, HEAP_NO_SERIALIZE, (char *)mem->ptr - HLOCAL_STORAGE )) ret = 0; + mem->ptr = NULL; + mem->next_free = next_free_mem; + next_free_mem = mem; + } + RtlUnlockHeap( heap ); + + if (ret) { WARN_(globalmem)( "invalid handle %p\n", handle ); SetLastError( ERROR_INVALID_HANDLE ); - ret = handle; } - __ENDTRY - RtlUnlockHeap( GetProcessHeap() ); return ret; }