[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