Signed-off-by: Rémi Bernon rbernon@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 );