From dcbfa1179d32a5762388ee079dec546d5feeeced Mon Sep 17 00:00:00 2001
From: Detlef Riekenberg <wine.dev@web.de>
Date: Sun, 19 Mar 2006 19:35:36 +0100
Subject: [PATCH] kernel: Avoid heap corruption on invalid parameter in
 GlobalFree().

---
 dlls/kernel/heap.c       | 23 ++++++++++++++++++-----
 dlls/kernel/tests/heap.c | 23 ++++++++++++++++++++++-
 2 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/dlls/kernel/heap.c b/dlls/kernel/heap.c
index 59a5e9fd7dd..a5849ede564 100644
--- a/dlls/kernel/heap.c
+++ b/dlls/kernel/heap.c
@@ -683,13 +683,19 @@ HGLOBAL WINAPI GlobalReAlloc(
  *
  * Free a global memory object.
  *
+ * PARAMS
+ *  hmem [I] Handle of the global memory object
+ *
  * RETURNS
- *      NULL: Success
- *      Handle: Failure
+ *  Success: NULL
+ *  Failure: The provided handle
+ *
+ * NOTES
+ *   When the handle is invalid, last error is set to ERROR_INVALID_HANDLE
+ *
  */
-HGLOBAL WINAPI GlobalFree(
-                 HGLOBAL hmem /* [in] Handle of global memory object */
-) {
+HGLOBAL WINAPI GlobalFree(HGLOBAL hmem)
+{
     PGLOBAL32_INTERN pintern;
     HGLOBAL hreturned;
 
@@ -707,6 +713,7 @@ HGLOBAL WINAPI GlobalFree(
 
             if(pintern->Magic==MAGIC_GLOBAL_USED)
             {
+                pintern->Magic = 0xdead;
 
                 /* WIN98 does not make this test. That is you can free a */
                 /* block you have not unlocked. Go figure!!              */
@@ -719,6 +726,12 @@ HGLOBAL WINAPI GlobalFree(
                 if(!HeapFree(GetProcessHeap(), 0, pintern))
                     hreturned=hmem;
             }
+            else
+            {
+                WARN("invalid handle %p (Magic: 0x%04x)\n", hmem, pintern->Magic);
+                SetLastError(ERROR_INVALID_HANDLE);
+                hreturned = hmem;
+            }
         }
     }
     __EXCEPT_PAGE_FAULT
diff --git a/dlls/kernel/tests/heap.c b/dlls/kernel/tests/heap.c
index a6284a0f559..e1a535cd3d6 100644
--- a/dlls/kernel/tests/heap.c
+++ b/dlls/kernel/tests/heap.c
@@ -25,6 +25,8 @@
 #include "winbase.h"
 #include "wine/test.h"
 
+#define MAGIC_DEAD 0xdeadbeef
+
 static SIZE_T resize_9x(SIZE_T size)
 {
     DWORD dwSizeAligned = (size + 3) & ~3;
@@ -35,7 +37,8 @@ START_TEST(heap)
 {
     void *mem;
     HGLOBAL gbl;
-    SIZE_T size;
+    HGLOBAL hsecond;
+    SIZE_T  size;
 
     /* Heap*() functions */
     mem = HeapAlloc(GetProcessHeap(), 0, 0);
@@ -75,6 +78,15 @@ START_TEST(heap)
     gbl = GlobalReAlloc(0, 10, GMEM_MOVEABLE);
     ok(gbl == NULL, "global realloc allocated memory\n");
 
+    /* invalid handles are catched in windows */
+    gbl = GlobalAlloc(GMEM_MOVEABLE, 256);
+    GlobalFree(gbl);
+    SetLastError(MAGIC_DEAD);
+    hsecond = GlobalFree(gbl);      /* invalid handle: free memory twice */
+    ok( (hsecond == gbl) && (GetLastError() == ERROR_INVALID_HANDLE),
+        "returned %p with 0x%08lx (expected %p with ERROR_INVALID_HANDLE)\n",
+        hsecond, GetLastError(), gbl);
+
     /* Local*() functions */
     gbl = LocalAlloc(LMEM_MOVEABLE, 0);
     ok(gbl != NULL, "local memory not allocated for size 0\n");
@@ -96,6 +108,15 @@ START_TEST(heap)
     gbl = LocalReAlloc(0, 10, LMEM_MOVEABLE);
     ok(gbl == NULL, "local realloc allocated memory\n");
 
+    /* invalid handles are catched in windows */
+    gbl = LocalAlloc(GMEM_MOVEABLE, 256);
+    LocalFree(gbl);
+    SetLastError(MAGIC_DEAD);
+    hsecond = LocalFree(gbl);       /* invalid handle: free memory twice */
+    ok( (hsecond == gbl) && (GetLastError() == ERROR_INVALID_HANDLE),
+        "returned %p with 0x%08lx (expected %p with ERROR_INVALID_HANDLE)\n",
+        hsecond, GetLastError(), gbl);
+
     /* trying to lock empty memory should give an error */
     gbl = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,0);
     ok(gbl != NULL, "returned NULL\n");
-- 
GitLab