[PATCH v2 5/5] kernelbase: Allocate HLOCAL / HGLOBAL from a static handle table.
Rémi Bernon
rbernon at codeweavers.com
Thu Mar 31 05:06:41 CDT 2022
Sharing the table pointers through KernelBaseGetGlobalData to check for
handle validity in kernel32, and as native does it.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/kernel32/heap.c | 20 +++++--
dlls/kernel32/tests/heap.c | 9 ---
dlls/kernelbase/memory.c | 115 ++++++++++++++++++++-----------------
3 files changed, 75 insertions(+), 69 deletions(-)
diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c
index cf8af2bd0c6..50b877111c3 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;
}
@@ -281,8 +290,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;
}
--
2.35.1
More information about the wine-devel
mailing list