[PATCH 4/5] ntdll: Move validation helpers around and rename them more consistently.

Rémi Bernon rbernon at codeweavers.com
Thu Apr 28 05:31:48 CDT 2022


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/ntdll/heap.c | 912 ++++++++++++++++++++++------------------------
 1 file changed, 428 insertions(+), 484 deletions(-)

diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c
index 37e77cf1d23..b84fa8dd42c 100644
--- a/dlls/ntdll/heap.c
+++ b/dlls/ntdll/heap.c
@@ -181,8 +181,6 @@ typedef struct tagHEAP
 
 static HEAP *processHeap;  /* main process heap */
 
-static BOOL HEAP_IsRealArena( HEAP *heapPtr, DWORD flags, LPCVOID block, BOOL quiet );
-
 /* mark a block of memory as free for debugging purposes */
 static inline void mark_block_free( void *ptr, SIZE_T size, DWORD flags )
 {
@@ -343,10 +341,7 @@ static void heap_unlock( HEAP *heap, DWORD flags )
     RtlLeaveCriticalSection( &heap->cs );
 }
 
-/***********************************************************************
- *           HEAP_Dump
- */
-static void HEAP_Dump( HEAP *heap )
+static void heap_dump( HEAP *heap )
 {
     unsigned int i;
     SUBHEAP *subheap;
@@ -412,8 +407,7 @@ static void HEAP_Dump( HEAP *heap )
     }
 }
 
-
-static void HEAP_DumpEntry( LPPROCESS_HEAP_ENTRY entry )
+static void heap_dump_entry( PROCESS_HEAP_ENTRY *entry )
 {
     WORD rem_flags;
     TRACE( "Dumping entry %p\n", entry );
@@ -454,6 +448,426 @@ static void HEAP_DumpEntry( LPPROCESS_HEAP_ENTRY entry )
     }
 }
 
+static SUBHEAP *find_subheap( const HEAP *heap, const void *ptr )
+{
+    SUBHEAP *sub;
+
+    LIST_FOR_EACH_ENTRY( sub, &heap->subheap_list, SUBHEAP, entry )
+        if ((ptr >= sub->base) && ((const char *)ptr < (const char *)sub->base + sub->size - sizeof(ARENA_INUSE)))
+            return sub;
+
+    return NULL;
+}
+
+static ARENA_LARGE *find_large_block( HEAP *heap, const void *ptr )
+{
+    ARENA_LARGE *arena;
+
+    LIST_FOR_EACH_ENTRY( arena, &heap->large_list, ARENA_LARGE, entry )
+        if (ptr == arena + 1) return arena;
+
+    return NULL;
+}
+
+static BOOL validate_large_arena( HEAP *heap, const ARENA_LARGE *arena, BOOL quiet )
+{
+    DWORD flags = heap->flags;
+
+    if ((ULONG_PTR)arena % page_size)
+    {
+        if (quiet == NOISY)
+        {
+            ERR( "Heap %p: invalid large arena pointer %p\n", heap, arena );
+            if (TRACE_ON(heap)) heap_dump( heap );
+        }
+        else if (WARN_ON(heap))
+        {
+            WARN( "Heap %p: unaligned arena pointer %p\n", heap, arena );
+            if (TRACE_ON(heap)) heap_dump( heap );
+        }
+        return FALSE;
+    }
+    if (arena->size != ARENA_LARGE_SIZE || arena->magic != ARENA_LARGE_MAGIC)
+    {
+        if (quiet == NOISY)
+        {
+            ERR( "Heap %p: invalid large arena %p values %x/%x\n",
+                 heap, arena, arena->size, arena->magic );
+            if (TRACE_ON(heap)) heap_dump( heap );
+        }
+        else if (WARN_ON(heap))
+        {
+            WARN( "Heap %p: invalid large arena %p values %x/%x\n",
+                  heap, arena, arena->size, arena->magic );
+            if (TRACE_ON(heap)) heap_dump( heap );
+        }
+        return FALSE;
+    }
+    if (arena->data_size > arena->block_size - sizeof(*arena))
+    {
+        ERR( "Heap %p: invalid large arena %p size %lx/%lx\n",
+             heap, arena, arena->data_size, arena->block_size );
+        return FALSE;
+    }
+    if (flags & HEAP_TAIL_CHECKING_ENABLED)
+    {
+        SIZE_T i, unused = arena->block_size - sizeof(*arena) - arena->data_size;
+        const unsigned char *data = (const unsigned char *)(arena + 1) + arena->data_size;
+
+        for (i = 0; i < unused; i++)
+        {
+            if (data[i] == ARENA_TAIL_FILLER) continue;
+            ERR("Heap %p: block %p tail overwritten at %p (byte %lu/%lu == 0x%02x)\n",
+                heap, arena + 1, data + i, i, unused, data[i] );
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static BOOL HEAP_IsValidArenaPtr( const HEAP *heap, const ARENA_FREE *ptr )
+{
+    unsigned int i;
+    const SUBHEAP *subheap = find_subheap( heap, ptr );
+    if (!subheap) return FALSE;
+    if ((const char *)ptr >= (const char *)subheap->base + subheap->headerSize) return TRUE;
+    if (subheap != &heap->subheap) return FALSE;
+    for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
+        if (ptr == &heap->freeList[i].arena) return TRUE;
+    return FALSE;
+}
+
+static BOOL validate_used_block( const SUBHEAP *subheap, const ARENA_INUSE *pArena, BOOL quiet )
+{
+    SIZE_T size;
+    DWORD i, flags = subheap->heap->flags;
+    const char *heapEnd = (const char *)subheap->base + subheap->size;
+
+    /* Check for unaligned pointers */
+    if ((ULONG_PTR)pArena % ALIGNMENT != ARENA_OFFSET)
+    {
+        if (quiet == NOISY)
+        {
+            ERR( "Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena );
+            if (TRACE_ON(heap)) heap_dump( subheap->heap );
+        }
+        else if (WARN_ON(heap))
+        {
+            WARN( "Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena );
+            if (TRACE_ON(heap)) heap_dump( subheap->heap );
+        }
+        return FALSE;
+    }
+
+    /* Check magic number */
+    if (pArena->magic != ARENA_INUSE_MAGIC && pArena->magic != ARENA_PENDING_MAGIC)
+    {
+        if (quiet == NOISY)
+        {
+            ERR("Heap %p: invalid in-use arena magic %08x for %p\n", subheap->heap, pArena->magic, pArena );
+            if (TRACE_ON(heap)) heap_dump( subheap->heap );
+        }
+        else if (WARN_ON(heap))
+        {
+            WARN("Heap %p: invalid in-use arena magic %08x for %p\n", subheap->heap, pArena->magic, pArena );
+            if (TRACE_ON(heap)) heap_dump( subheap->heap );
+        }
+        return FALSE;
+    }
+    /* Check size flags */
+    if (pArena->size & ARENA_FLAG_FREE)
+    {
+        ERR("Heap %p: bad flags %08x for in-use arena %p\n",
+            subheap->heap, pArena->size & ~ARENA_SIZE_MASK, pArena );
+        return FALSE;
+    }
+    /* Check arena size */
+    size = pArena->size & ARENA_SIZE_MASK;
+    if ((const char *)(pArena + 1) + size > heapEnd ||
+        (const char *)(pArena + 1) + size < (const char *)(pArena + 1))
+    {
+        ERR("Heap %p: bad size %08lx for in-use arena %p\n", subheap->heap, size, pArena );
+        return FALSE;
+    }
+    /* Check next arena PREV_FREE flag */
+    if (((const char *)(pArena + 1) + size < heapEnd) &&
+        (*(const DWORD *)((const char *)(pArena + 1) + size) & ARENA_FLAG_PREV_FREE))
+    {
+        ERR("Heap %p: in-use arena %p next block %p has PREV_FREE flag %x\n",
+            subheap->heap, pArena, (const char *)(pArena + 1) + size,*(const DWORD *)((const char *)(pArena + 1) + size) );
+        return FALSE;
+    }
+    /* Check prev free arena */
+    if (pArena->size & ARENA_FLAG_PREV_FREE)
+    {
+        const ARENA_FREE *pPrev = *((const ARENA_FREE * const*)pArena - 1);
+        /* Check prev pointer */
+        if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev ))
+        {
+            ERR("Heap %p: bad back ptr %p for arena %p\n",
+                subheap->heap, pPrev, pArena );
+            return FALSE;
+        }
+        /* Check that prev arena is free */
+        if (!(pPrev->size & ARENA_FLAG_FREE) ||
+            (pPrev->magic != ARENA_FREE_MAGIC))
+        {
+            ERR("Heap %p: prev arena %p invalid for in-use %p\n",
+                subheap->heap, pPrev, pArena );
+            return FALSE;
+        }
+        /* Check that prev arena is really the previous block */
+        if ((const char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (const char *)pArena)
+        {
+            ERR("Heap %p: prev arena %p is not prev for in-use %p\n",
+                subheap->heap, pPrev, pArena );
+            return FALSE;
+        }
+    }
+    /* Check unused size */
+    if (pArena->unused_bytes > size)
+    {
+        ERR("Heap %p: invalid unused size %08x/%08lx\n", subheap->heap, pArena->unused_bytes, size );
+        return FALSE;
+    }
+    /* Check unused bytes */
+    if (pArena->magic == ARENA_PENDING_MAGIC)
+    {
+        const DWORD *ptr = (const DWORD *)(pArena + 1);
+        const DWORD *end = (const DWORD *)((const char *)ptr + size);
+
+        while (ptr < end)
+        {
+            if (*ptr != ARENA_FREE_FILLER)
+            {
+                ERR("Heap %p: free block %p overwritten at %p by %08x\n",
+                    subheap->heap, pArena + 1, ptr, *ptr );
+                if (!*ptr) { heap_dump( subheap->heap ); DbgBreakPoint(); }
+                return FALSE;
+            }
+            ptr++;
+        }
+    }
+    else if (flags & HEAP_TAIL_CHECKING_ENABLED)
+    {
+        const unsigned char *data = (const unsigned char *)(pArena + 1) + size - pArena->unused_bytes;
+
+        for (i = 0; i < pArena->unused_bytes; i++)
+        {
+            if (data[i] == ARENA_TAIL_FILLER) continue;
+            ERR("Heap %p: block %p tail overwritten at %p (byte %u/%u == 0x%02x)\n",
+                subheap->heap, pArena + 1, data + i, i, pArena->unused_bytes, data[i] );
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static BOOL validate_free_block( SUBHEAP *subheap, ARENA_FREE *pArena )
+{
+    DWORD flags = subheap->heap->flags;
+    SIZE_T size;
+    ARENA_FREE *prev, *next;
+    char *heapEnd = (char *)subheap->base + subheap->size;
+
+    /* Check for unaligned pointers */
+    if ((ULONG_PTR)pArena % ALIGNMENT != ARENA_OFFSET)
+    {
+        ERR("Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena );
+        return FALSE;
+    }
+
+    /* Check magic number */
+    if (pArena->magic != ARENA_FREE_MAGIC)
+    {
+        ERR("Heap %p: invalid free arena magic %08x for %p\n", subheap->heap, pArena->magic, pArena );
+        return FALSE;
+    }
+    /* Check size flags */
+    if (!(pArena->size & ARENA_FLAG_FREE) ||
+        (pArena->size & ARENA_FLAG_PREV_FREE))
+    {
+        ERR("Heap %p: bad flags %08x for free arena %p\n",
+            subheap->heap, pArena->size & ~ARENA_SIZE_MASK, pArena );
+        return FALSE;
+    }
+    /* Check arena size */
+    size = pArena->size & ARENA_SIZE_MASK;
+    if ((char *)(pArena + 1) + size > heapEnd)
+    {
+        ERR("Heap %p: bad size %08lx for free arena %p\n", subheap->heap, size, pArena );
+        return FALSE;
+    }
+    /* Check that next pointer is valid */
+    next = LIST_ENTRY( pArena->entry.next, ARENA_FREE, entry );
+    if (!HEAP_IsValidArenaPtr( subheap->heap, next ))
+    {
+        ERR("Heap %p: bad next ptr %p for arena %p\n",
+            subheap->heap, next, pArena );
+        return FALSE;
+    }
+    /* Check that next arena is free */
+    if (!(next->size & ARENA_FLAG_FREE) || (next->magic != ARENA_FREE_MAGIC))
+    {
+        ERR("Heap %p: next arena %p invalid for %p\n",
+            subheap->heap, next, pArena );
+        return FALSE;
+    }
+    /* Check that prev pointer is valid */
+    prev = LIST_ENTRY( pArena->entry.prev, ARENA_FREE, entry );
+    if (!HEAP_IsValidArenaPtr( subheap->heap, prev ))
+    {
+        ERR("Heap %p: bad prev ptr %p for arena %p\n",
+            subheap->heap, prev, pArena );
+        return FALSE;
+    }
+    /* Check that prev arena is free */
+    if (!(prev->size & ARENA_FLAG_FREE) || (prev->magic != ARENA_FREE_MAGIC))
+    {
+    /* this often means that the prev arena got overwritten
+     * by a memory write before that prev arena */
+        ERR("Heap %p: prev arena %p invalid for %p\n",
+            subheap->heap, prev, pArena );
+        return FALSE;
+    }
+    /* Check that next block has PREV_FREE flag */
+    if ((char *)(pArena + 1) + size < heapEnd)
+    {
+        if (!(*(DWORD *)((char *)(pArena + 1) + size) & ARENA_FLAG_PREV_FREE))
+        {
+            ERR("Heap %p: free arena %p next block has no PREV_FREE flag\n",
+                subheap->heap, pArena );
+            return FALSE;
+        }
+        /* Check next block back pointer */
+        if (*((ARENA_FREE **)((char *)(pArena + 1) + size) - 1) != pArena)
+        {
+            ERR("Heap %p: arena %p has wrong back ptr %p\n",
+                subheap->heap, pArena,
+                *((ARENA_FREE **)((char *)(pArena+1) + size) - 1));
+            return FALSE;
+        }
+    }
+    if (flags & HEAP_FREE_CHECKING_ENABLED)
+    {
+        DWORD *ptr = (DWORD *)(pArena + 1);
+        char *end = (char *)(pArena + 1) + size;
+
+        if (end >= heapEnd) end = (char *)subheap->base + subheap->commitSize;
+        else end -= sizeof(ARENA_FREE *);
+        while (ptr < (DWORD *)end)
+        {
+            if (*ptr != ARENA_FREE_FILLER)
+            {
+                ERR("Heap %p: free block %p overwritten at %p by %08x\n",
+                    subheap->heap, (ARENA_INUSE *)pArena + 1, ptr, *ptr );
+                return FALSE;
+            }
+            ptr++;
+        }
+    }
+    return TRUE;
+}
+
+static BOOL validate_block_pointer( HEAP *heap, SUBHEAP **ret_subheap, const ARENA_INUSE *arena )
+{
+    SUBHEAP *subheap;
+    BOOL ret = FALSE;
+
+    if (!(*ret_subheap = subheap = find_subheap( heap, arena )))
+    {
+        ARENA_LARGE *large_arena = find_large_block( heap, arena + 1 );
+
+        if (!large_arena)
+        {
+            WARN( "Heap %p: pointer %p is not inside heap\n", heap, arena + 1 );
+            return FALSE;
+        }
+        if ((heap->flags & HEAP_VALIDATE) && !validate_large_arena( heap, large_arena, QUIET ))
+            return FALSE;
+        return TRUE;
+    }
+
+    if ((const char *)arena < (char *)subheap->base + subheap->headerSize)
+        WARN( "Heap %p: pointer %p is inside subheap %p header\n", subheap->heap, arena + 1, subheap );
+    else if (subheap->heap->flags & HEAP_VALIDATE)  /* do the full validation */
+        ret = validate_used_block( subheap, arena, QUIET );
+    else if ((ULONG_PTR)arena % ALIGNMENT != ARENA_OFFSET)
+        WARN( "Heap %p: unaligned arena pointer %p\n", subheap->heap, arena );
+    else if (arena->magic == ARENA_PENDING_MAGIC)
+        WARN( "Heap %p: block %p used after free\n", subheap->heap, arena + 1 );
+    else if (arena->magic != ARENA_INUSE_MAGIC)
+        WARN( "Heap %p: invalid in-use arena magic %08x for %p\n", subheap->heap, arena->magic, arena );
+    else if (arena->size & ARENA_FLAG_FREE)
+        ERR( "Heap %p: bad flags %08x for in-use arena %p\n",
+             subheap->heap, arena->size & ~ARENA_SIZE_MASK, arena );
+    else if ((const char *)(arena + 1) + (arena->size & ARENA_SIZE_MASK) > (const char *)subheap->base + subheap->size ||
+             (const char *)(arena + 1) + (arena->size & ARENA_SIZE_MASK) < (const char *)(arena + 1))
+        ERR( "Heap %p: bad size %08x for in-use arena %p\n",
+             subheap->heap, arena->size & ARENA_SIZE_MASK, arena );
+    else
+        ret = TRUE;
+
+    return ret;
+}
+
+static BOOL heap_validate( HEAP *heapPtr, DWORD flags, LPCVOID block, BOOL quiet )
+{
+    SUBHEAP *subheap;
+    BOOL ret = FALSE;
+    const ARENA_LARGE *large_arena;
+
+    heap_lock( heapPtr, flags );
+
+    if (block)  /* only check this single memory block */
+    {
+        const ARENA_INUSE *arena = (const ARENA_INUSE *)block - 1;
+
+        if (!(subheap = find_subheap( heapPtr, arena )) ||
+            ((const char *)arena < (char *)subheap->base + subheap->headerSize))
+        {
+            if (!(large_arena = find_large_block( heapPtr, block )))
+            {
+                if (quiet == NOISY)
+                    ERR("Heap %p: block %p is not inside heap\n", heapPtr, block );
+                else if (WARN_ON(heap))
+                    WARN("Heap %p: block %p is not inside heap\n", heapPtr, block );
+            }
+            else ret = validate_large_arena( heapPtr, large_arena, quiet );
+        }
+        else ret = validate_used_block( subheap, arena, quiet );
+        goto done;
+    }
+
+    LIST_FOR_EACH_ENTRY( subheap, &heapPtr->subheap_list, SUBHEAP, entry )
+    {
+        char *ptr = (char *)subheap->base + subheap->headerSize;
+        while (ptr < (char *)subheap->base + subheap->size)
+        {
+            if (*(DWORD *)ptr & ARENA_FLAG_FREE)
+            {
+                if (!validate_free_block( subheap, (ARENA_FREE *)ptr )) goto done;
+                ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
+            }
+            else
+            {
+                if (!validate_used_block( subheap, (ARENA_INUSE *)ptr, NOISY )) goto done;
+                ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
+            }
+        }
+    }
+
+    LIST_FOR_EACH_ENTRY( large_arena, &heapPtr->large_list, ARENA_LARGE, entry )
+        if (!validate_large_arena( heapPtr, large_arena, quiet )) goto done;
+
+    ret = TRUE;
+
+done:
+    heap_unlock( heapPtr, flags );
+    return ret;
+}
+
+
 /***********************************************************************
  *           HEAP_GetPtr
  * RETURNS
@@ -469,11 +883,11 @@ static HEAP *HEAP_GetPtr(
         ERR("Invalid heap %p!\n", heap );
         return NULL;
     }
-    if ((heapPtr->flags & HEAP_VALIDATE_ALL) && !HEAP_IsRealArena( heapPtr, 0, NULL, NOISY ))
+    if ((heapPtr->flags & HEAP_VALIDATE_ALL) && !heap_validate( heapPtr, 0, NULL, NOISY ))
     {
         if (TRACE_ON(heap))
         {
-            HEAP_Dump( heapPtr );
+            heap_dump( heapPtr );
             assert( FALSE );
         }
         return NULL;
@@ -506,27 +920,6 @@ static inline void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena, BOOL la
 }
 
 
-/***********************************************************************
- *           HEAP_FindSubHeap
- * Find the sub-heap containing a given address.
- *
- * RETURNS
- *	Pointer: Success
- *	NULL: Failure
- */
-static SUBHEAP *HEAP_FindSubHeap(
-                const HEAP *heap, /* [in] Heap pointer */
-                LPCVOID ptr ) /* [in] Address */
-{
-    SUBHEAP *sub;
-    LIST_FOR_EACH_ENTRY( sub, &heap->subheap_list, SUBHEAP, entry )
-        if ((ptr >= sub->base) &&
-            ((const char *)ptr < (const char *)sub->base + sub->size - sizeof(ARENA_INUSE)))
-            return sub;
-    return NULL;
-}
-
-
 /***********************************************************************
  *           HEAP_Commit
  *
@@ -658,7 +1051,7 @@ static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
         mark_block_free( pArena + 1, pArena->size & ARENA_SIZE_MASK, heap->flags );
         if (!prev) return;
         pArena = prev;
-        subheap = HEAP_FindSubHeap( heap, pArena );
+        subheap = find_subheap( heap, pArena );
     }
 
     /* Check if we can merge with previous block */
@@ -808,79 +1201,6 @@ static void *realloc_large_block( HEAP *heap, DWORD flags, void *ptr, SIZE_T siz
 }
 
 
-/***********************************************************************
- *           find_large_block
- */
-static ARENA_LARGE *find_large_block( HEAP *heap, const void *ptr )
-{
-    ARENA_LARGE *arena;
-
-    LIST_FOR_EACH_ENTRY( arena, &heap->large_list, ARENA_LARGE, entry )
-        if (ptr == arena + 1) return arena;
-
-    return NULL;
-}
-
-
-/***********************************************************************
- *           validate_large_arena
- */
-static BOOL validate_large_arena( HEAP *heap, const ARENA_LARGE *arena, BOOL quiet )
-{
-    DWORD flags = heap->flags;
-
-    if ((ULONG_PTR)arena % page_size)
-    {
-        if (quiet == NOISY)
-        {
-            ERR( "Heap %p: invalid large arena pointer %p\n", heap, arena );
-            if (TRACE_ON(heap)) HEAP_Dump( heap );
-        }
-        else if (WARN_ON(heap))
-        {
-            WARN( "Heap %p: unaligned arena pointer %p\n", heap, arena );
-            if (TRACE_ON(heap)) HEAP_Dump( heap );
-        }
-        return FALSE;
-    }
-    if (arena->size != ARENA_LARGE_SIZE || arena->magic != ARENA_LARGE_MAGIC)
-    {
-        if (quiet == NOISY)
-        {
-            ERR( "Heap %p: invalid large arena %p values %x/%x\n",
-                 heap, arena, arena->size, arena->magic );
-            if (TRACE_ON(heap)) HEAP_Dump( heap );
-        }
-        else if (WARN_ON(heap))
-        {
-            WARN( "Heap %p: invalid large arena %p values %x/%x\n",
-                  heap, arena, arena->size, arena->magic );
-            if (TRACE_ON(heap)) HEAP_Dump( heap );
-        }
-        return FALSE;
-    }
-    if (arena->data_size > arena->block_size - sizeof(*arena))
-    {
-        ERR( "Heap %p: invalid large arena %p size %lx/%lx\n",
-             heap, arena, arena->data_size, arena->block_size );
-        return FALSE;
-    }
-    if (flags & HEAP_TAIL_CHECKING_ENABLED)
-    {
-        SIZE_T i, unused = arena->block_size - sizeof(*arena) - arena->data_size;
-        const unsigned char *data = (const unsigned char *)(arena + 1) + arena->data_size;
-
-        for (i = 0; i < unused; i++)
-        {
-            if (data[i] == ARENA_TAIL_FILLER) continue;
-            ERR("Heap %p: block %p tail overwritten at %p (byte %lu/%lu == 0x%02x)\n",
-                heap, arena + 1, data + i, i, unused, data[i] );
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
 
 /***********************************************************************
  *           HEAP_CreateSubHeap
@@ -1030,7 +1350,7 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size,
                             sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
         if (arena_size >= size)
         {
-            subheap = HEAP_FindSubHeap( heap, pArena );
+            subheap = find_subheap( heap, pArena );
             if (!HEAP_Commit( subheap, (ARENA_INUSE *)pArena, size )) return NULL;
             *ppSubHeap = subheap;
             return pArena;
@@ -1072,382 +1392,6 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size,
     return (ARENA_FREE *)((char *)subheap->base + subheap->headerSize);
 }
 
-
-/***********************************************************************
- *           HEAP_IsValidArenaPtr
- *
- * Check that the pointer is inside the range possible for arenas.
- */
-static BOOL HEAP_IsValidArenaPtr( const HEAP *heap, const ARENA_FREE *ptr )
-{
-    unsigned int i;
-    const SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr );
-    if (!subheap) return FALSE;
-    if ((const char *)ptr >= (const char *)subheap->base + subheap->headerSize) return TRUE;
-    if (subheap != &heap->subheap) return FALSE;
-    for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
-        if (ptr == &heap->freeList[i].arena) return TRUE;
-    return FALSE;
-}
-
-
-/***********************************************************************
- *           HEAP_ValidateFreeArena
- */
-static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
-{
-    DWORD flags = subheap->heap->flags;
-    SIZE_T size;
-    ARENA_FREE *prev, *next;
-    char *heapEnd = (char *)subheap->base + subheap->size;
-
-    /* Check for unaligned pointers */
-    if ((ULONG_PTR)pArena % ALIGNMENT != ARENA_OFFSET)
-    {
-        ERR("Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena );
-        return FALSE;
-    }
-
-    /* Check magic number */
-    if (pArena->magic != ARENA_FREE_MAGIC)
-    {
-        ERR("Heap %p: invalid free arena magic %08x for %p\n", subheap->heap, pArena->magic, pArena );
-        return FALSE;
-    }
-    /* Check size flags */
-    if (!(pArena->size & ARENA_FLAG_FREE) ||
-        (pArena->size & ARENA_FLAG_PREV_FREE))
-    {
-        ERR("Heap %p: bad flags %08x for free arena %p\n",
-            subheap->heap, pArena->size & ~ARENA_SIZE_MASK, pArena );
-        return FALSE;
-    }
-    /* Check arena size */
-    size = pArena->size & ARENA_SIZE_MASK;
-    if ((char *)(pArena + 1) + size > heapEnd)
-    {
-        ERR("Heap %p: bad size %08lx for free arena %p\n", subheap->heap, size, pArena );
-        return FALSE;
-    }
-    /* Check that next pointer is valid */
-    next = LIST_ENTRY( pArena->entry.next, ARENA_FREE, entry );
-    if (!HEAP_IsValidArenaPtr( subheap->heap, next ))
-    {
-        ERR("Heap %p: bad next ptr %p for arena %p\n",
-            subheap->heap, next, pArena );
-        return FALSE;
-    }
-    /* Check that next arena is free */
-    if (!(next->size & ARENA_FLAG_FREE) || (next->magic != ARENA_FREE_MAGIC))
-    {
-        ERR("Heap %p: next arena %p invalid for %p\n",
-            subheap->heap, next, pArena );
-        return FALSE;
-    }
-    /* Check that prev pointer is valid */
-    prev = LIST_ENTRY( pArena->entry.prev, ARENA_FREE, entry );
-    if (!HEAP_IsValidArenaPtr( subheap->heap, prev ))
-    {
-        ERR("Heap %p: bad prev ptr %p for arena %p\n",
-            subheap->heap, prev, pArena );
-        return FALSE;
-    }
-    /* Check that prev arena is free */
-    if (!(prev->size & ARENA_FLAG_FREE) || (prev->magic != ARENA_FREE_MAGIC))
-    {
-	/* this often means that the prev arena got overwritten
-	 * by a memory write before that prev arena */
-        ERR("Heap %p: prev arena %p invalid for %p\n",
-            subheap->heap, prev, pArena );
-        return FALSE;
-    }
-    /* Check that next block has PREV_FREE flag */
-    if ((char *)(pArena + 1) + size < heapEnd)
-    {
-        if (!(*(DWORD *)((char *)(pArena + 1) + size) & ARENA_FLAG_PREV_FREE))
-        {
-            ERR("Heap %p: free arena %p next block has no PREV_FREE flag\n",
-                subheap->heap, pArena );
-            return FALSE;
-        }
-        /* Check next block back pointer */
-        if (*((ARENA_FREE **)((char *)(pArena + 1) + size) - 1) != pArena)
-        {
-            ERR("Heap %p: arena %p has wrong back ptr %p\n",
-                subheap->heap, pArena,
-                *((ARENA_FREE **)((char *)(pArena+1) + size) - 1));
-            return FALSE;
-        }
-    }
-    if (flags & HEAP_FREE_CHECKING_ENABLED)
-    {
-        DWORD *ptr = (DWORD *)(pArena + 1);
-        char *end = (char *)(pArena + 1) + size;
-
-        if (end >= heapEnd) end = (char *)subheap->base + subheap->commitSize;
-        else end -= sizeof(ARENA_FREE *);
-        while (ptr < (DWORD *)end)
-        {
-            if (*ptr != ARENA_FREE_FILLER)
-            {
-                ERR("Heap %p: free block %p overwritten at %p by %08x\n",
-                    subheap->heap, (ARENA_INUSE *)pArena + 1, ptr, *ptr );
-                return FALSE;
-            }
-            ptr++;
-        }
-    }
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HEAP_ValidateInUseArena
- */
-static BOOL HEAP_ValidateInUseArena( const SUBHEAP *subheap, const ARENA_INUSE *pArena, BOOL quiet )
-{
-    SIZE_T size;
-    DWORD i, flags = subheap->heap->flags;
-    const char *heapEnd = (const char *)subheap->base + subheap->size;
-
-    /* Check for unaligned pointers */
-    if ((ULONG_PTR)pArena % ALIGNMENT != ARENA_OFFSET)
-    {
-        if ( quiet == NOISY )
-        {
-            ERR( "Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena );
-            if ( TRACE_ON(heap) )
-                HEAP_Dump( subheap->heap );
-        }
-        else if ( WARN_ON(heap) )
-        {
-            WARN( "Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena );
-            if ( TRACE_ON(heap) )
-                HEAP_Dump( subheap->heap );
-        }
-        return FALSE;
-    }
-
-    /* Check magic number */
-    if (pArena->magic != ARENA_INUSE_MAGIC && pArena->magic != ARENA_PENDING_MAGIC)
-    {
-        if (quiet == NOISY) {
-            ERR("Heap %p: invalid in-use arena magic %08x for %p\n", subheap->heap, pArena->magic, pArena );
-            if (TRACE_ON(heap))
-               HEAP_Dump( subheap->heap );
-        }  else if (WARN_ON(heap)) {
-            WARN("Heap %p: invalid in-use arena magic %08x for %p\n", subheap->heap, pArena->magic, pArena );
-            if (TRACE_ON(heap))
-               HEAP_Dump( subheap->heap );
-        }
-        return FALSE;
-    }
-    /* Check size flags */
-    if (pArena->size & ARENA_FLAG_FREE)
-    {
-        ERR("Heap %p: bad flags %08x for in-use arena %p\n",
-            subheap->heap, pArena->size & ~ARENA_SIZE_MASK, pArena );
-        return FALSE;
-    }
-    /* Check arena size */
-    size = pArena->size & ARENA_SIZE_MASK;
-    if ((const char *)(pArena + 1) + size > heapEnd ||
-        (const char *)(pArena + 1) + size < (const char *)(pArena + 1))
-    {
-        ERR("Heap %p: bad size %08lx for in-use arena %p\n", subheap->heap, size, pArena );
-        return FALSE;
-    }
-    /* Check next arena PREV_FREE flag */
-    if (((const char *)(pArena + 1) + size < heapEnd) &&
-        (*(const DWORD *)((const char *)(pArena + 1) + size) & ARENA_FLAG_PREV_FREE))
-    {
-        ERR("Heap %p: in-use arena %p next block %p has PREV_FREE flag %x\n",
-            subheap->heap, pArena, (const char *)(pArena + 1) + size,*(const DWORD *)((const char *)(pArena + 1) + size) );
-        return FALSE;
-    }
-    /* Check prev free arena */
-    if (pArena->size & ARENA_FLAG_PREV_FREE)
-    {
-        const ARENA_FREE *pPrev = *((const ARENA_FREE * const*)pArena - 1);
-        /* Check prev pointer */
-        if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev ))
-        {
-            ERR("Heap %p: bad back ptr %p for arena %p\n",
-                subheap->heap, pPrev, pArena );
-            return FALSE;
-        }
-        /* Check that prev arena is free */
-        if (!(pPrev->size & ARENA_FLAG_FREE) ||
-            (pPrev->magic != ARENA_FREE_MAGIC))
-        {
-            ERR("Heap %p: prev arena %p invalid for in-use %p\n",
-                subheap->heap, pPrev, pArena );
-            return FALSE;
-        }
-        /* Check that prev arena is really the previous block */
-        if ((const char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (const char *)pArena)
-        {
-            ERR("Heap %p: prev arena %p is not prev for in-use %p\n",
-                subheap->heap, pPrev, pArena );
-            return FALSE;
-        }
-    }
-    /* Check unused size */
-    if (pArena->unused_bytes > size)
-    {
-        ERR("Heap %p: invalid unused size %08x/%08lx\n", subheap->heap, pArena->unused_bytes, size );
-        return FALSE;
-    }
-    /* Check unused bytes */
-    if (pArena->magic == ARENA_PENDING_MAGIC)
-    {
-        const DWORD *ptr = (const DWORD *)(pArena + 1);
-        const DWORD *end = (const DWORD *)((const char *)ptr + size);
-
-        while (ptr < end)
-        {
-            if (*ptr != ARENA_FREE_FILLER)
-            {
-                ERR("Heap %p: free block %p overwritten at %p by %08x\n",
-                    subheap->heap, pArena + 1, ptr, *ptr );
-                if (!*ptr) { HEAP_Dump( subheap->heap ); DbgBreakPoint(); }
-                return FALSE;
-            }
-            ptr++;
-        }
-    }
-    else if (flags & HEAP_TAIL_CHECKING_ENABLED)
-    {
-        const unsigned char *data = (const unsigned char *)(pArena + 1) + size - pArena->unused_bytes;
-
-        for (i = 0; i < pArena->unused_bytes; i++)
-        {
-            if (data[i] == ARENA_TAIL_FILLER) continue;
-            ERR("Heap %p: block %p tail overwritten at %p (byte %u/%u == 0x%02x)\n",
-                subheap->heap, pArena + 1, data + i, i, pArena->unused_bytes, data[i] );
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HEAP_IsRealArena  [Internal]
- * Validates a block is a valid arena.
- *
- * RETURNS
- *	TRUE: Success
- *	FALSE: Failure
- */
-static BOOL HEAP_IsRealArena( HEAP *heapPtr,   /* [in] ptr to the heap */
-              DWORD flags,   /* [in] Bit flags that control access during operation */
-              LPCVOID block, /* [in] Optional pointer to memory block to validate */
-              BOOL quiet )   /* [in] Flag - if true, HEAP_ValidateInUseArena
-                              *             does not complain    */
-{
-    SUBHEAP *subheap;
-    BOOL ret = FALSE;
-    const ARENA_LARGE *large_arena;
-
-    heap_lock( heapPtr, flags );
-
-    if (block)  /* only check this single memory block */
-    {
-        const ARENA_INUSE *arena = (const ARENA_INUSE *)block - 1;
-
-        if (!(subheap = HEAP_FindSubHeap( heapPtr, arena )) ||
-            ((const char *)arena < (char *)subheap->base + subheap->headerSize))
-        {
-            if (!(large_arena = find_large_block( heapPtr, block )))
-            {
-                if (quiet == NOISY)
-                    ERR("Heap %p: block %p is not inside heap\n", heapPtr, block );
-                else if (WARN_ON(heap))
-                    WARN("Heap %p: block %p is not inside heap\n", heapPtr, block );
-            }
-            else ret = validate_large_arena( heapPtr, large_arena, quiet );
-        }
-        else ret = HEAP_ValidateInUseArena( subheap, arena, quiet );
-        goto done;
-    }
-
-    LIST_FOR_EACH_ENTRY( subheap, &heapPtr->subheap_list, SUBHEAP, entry )
-    {
-        char *ptr = (char *)subheap->base + subheap->headerSize;
-        while (ptr < (char *)subheap->base + subheap->size)
-        {
-            if (*(DWORD *)ptr & ARENA_FLAG_FREE)
-            {
-                if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) goto done;
-                ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
-            }
-            else
-            {
-                if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr, NOISY )) goto done;
-                ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
-            }
-        }
-    }
-
-    LIST_FOR_EACH_ENTRY( large_arena, &heapPtr->large_list, ARENA_LARGE, entry )
-        if (!validate_large_arena( heapPtr, large_arena, quiet )) goto done;
-
-    ret = TRUE;
-
-done:
-    heap_unlock( heapPtr, flags );
-    return ret;
-}
-
-
-/***********************************************************************
- *           validate_block_pointer
- *
- * Minimum validation needed to catch bad parameters in heap functions.
- */
-static BOOL validate_block_pointer( HEAP *heap, SUBHEAP **ret_subheap, const ARENA_INUSE *arena )
-{
-    SUBHEAP *subheap;
-    BOOL ret = FALSE;
-
-    if (!(*ret_subheap = subheap = HEAP_FindSubHeap( heap, arena )))
-    {
-        ARENA_LARGE *large_arena = find_large_block( heap, arena + 1 );
-
-        if (!large_arena)
-        {
-            WARN( "Heap %p: pointer %p is not inside heap\n", heap, arena + 1 );
-            return FALSE;
-        }
-        if ((heap->flags & HEAP_VALIDATE) && !validate_large_arena( heap, large_arena, QUIET ))
-            return FALSE;
-        return TRUE;
-    }
-
-    if ((const char *)arena < (char *)subheap->base + subheap->headerSize)
-        WARN( "Heap %p: pointer %p is inside subheap %p header\n", subheap->heap, arena + 1, subheap );
-    else if (subheap->heap->flags & HEAP_VALIDATE)  /* do the full validation */
-        ret = HEAP_ValidateInUseArena( subheap, arena, QUIET );
-    else if ((ULONG_PTR)arena % ALIGNMENT != ARENA_OFFSET)
-        WARN( "Heap %p: unaligned arena pointer %p\n", subheap->heap, arena );
-    else if (arena->magic == ARENA_PENDING_MAGIC)
-        WARN( "Heap %p: block %p used after free\n", subheap->heap, arena + 1 );
-    else if (arena->magic != ARENA_INUSE_MAGIC)
-        WARN( "Heap %p: invalid in-use arena magic %08x for %p\n", subheap->heap, arena->magic, arena );
-    else if (arena->size & ARENA_FLAG_FREE)
-        ERR( "Heap %p: bad flags %08x for in-use arena %p\n",
-             subheap->heap, arena->size & ~ARENA_SIZE_MASK, arena );
-    else if ((const char *)(arena + 1) + (arena->size & ARENA_SIZE_MASK) > (const char *)subheap->base + subheap->size ||
-             (const char *)(arena + 1) + (arena->size & ARENA_SIZE_MASK) < (const char *)(arena + 1))
-        ERR( "Heap %p: bad size %08x for in-use arena %p\n",
-             subheap->heap, arena->size & ARENA_SIZE_MASK, arena );
-    else
-        ret = TRUE;
-
-    return ret;
-}
-
 static DWORD heap_flags_from_global_flag( DWORD flag )
 {
     DWORD ret = 0;
@@ -2085,7 +2029,7 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, LPCVOID ptr )
 {
     HEAP *heapPtr = HEAP_GetPtr( heap );
     if (!heapPtr) return FALSE;
-    return HEAP_IsRealArena( heapPtr, flags, ptr, QUIET );
+    return heap_validate( heapPtr, flags, ptr, QUIET );
 }
 
 
@@ -2209,7 +2153,7 @@ NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr )
                 (char *)currentheap->base + currentheap->size;
     }
     ret = STATUS_SUCCESS;
-    if (TRACE_ON(heap)) HEAP_DumpEntry(entry);
+    if (TRACE_ON(heap)) heap_dump_entry(entry);
 
 HW_end:
     heap_unlock( heapPtr, 0 );
-- 
2.35.1




More information about the wine-devel mailing list