[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