Commit 279a6b1e authored by Rémi Bernon's avatar Rémi Bernon Committed by Alexandre Julliard

ntdll: Simplify validate_free_block.

parent 12d611a0
...@@ -1143,131 +1143,71 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size, ...@@ -1143,131 +1143,71 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size,
} }
/*********************************************************************** static BOOL is_valid_free_block( const HEAP *heap, const struct block *block )
* HEAP_IsValidArenaPtr
*
* Check that the pointer is inside the range possible for arenas.
*/
static BOOL HEAP_IsValidArenaPtr( const HEAP *heap, const ARENA_FREE *ptr )
{ {
const SUBHEAP *subheap;
unsigned int i; unsigned int i;
const SUBHEAP *subheap = find_subheap( heap, ptr );
if (!subheap) return FALSE; if (!(subheap = find_subheap( heap, block ))) return FALSE;
if ((const char *)ptr >= (const char *)subheap->base + subheap->headerSize) return TRUE; if ((char *)block >= (char *)subheap->base + subheap->headerSize) return TRUE;
if (subheap != &heap->subheap) return FALSE; if (subheap != &heap->subheap) return FALSE;
for (i = 0; i < HEAP_NB_FREE_LISTS; i++) for (i = 0; i < HEAP_NB_FREE_LISTS; i++) if (block == (struct block *)&heap->freeList[i].arena) return TRUE;
if (ptr == &heap->freeList[i].arena) return TRUE;
return FALSE; return FALSE;
} }
static BOOL validate_free_block( const SUBHEAP *subheap, const struct block *block )
/***********************************************************************
* HEAP_ValidateFreeArena
*/
static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
{ {
DWORD flags = subheap->heap->flags; const char *err = NULL, *base = subheap_base( subheap ), *commit_end = subheap_commit_end( subheap );
SIZE_T size; SIZE_T blocks_size = (char *)last_block( subheap ) - (char *)first_block( subheap );
ARENA_FREE *prev, *next; const struct entry *entry = (struct entry *)block;
char *heapEnd = (char *)subheap->base + subheap->size; const struct block *prev, *next;
HEAP *heap = subheap->heap;
/* Check for unaligned pointers */ DWORD flags = heap->flags;
if ((ULONG_PTR)pArena % ALIGNMENT != ARENA_OFFSET)
{
ERR("Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena );
return FALSE;
}
/* Check magic number */ if ((ULONG_PTR)(block + 1) % ALIGNMENT)
if (pArena->magic != ARENA_FREE_MAGIC) err = "invalid block alignment";
{ else if (!contains( first_block( subheap ), blocks_size, block, sizeof(*block) ))
ERR("Heap %p: invalid free arena magic %08x for %p\n", subheap->heap, pArena->magic, pArena ); err = "invalid block pointer";
return FALSE; else if (block_get_type( block ) != ARENA_FREE_MAGIC)
} err = "invalid block header";
/* Check size flags */ else if (!(block_get_flags( block ) & ARENA_FLAG_FREE) || (block_get_flags( block ) & ARENA_FLAG_PREV_FREE))
if (!(pArena->size & ARENA_FLAG_FREE) || err = "invalid block flags";
(pArena->size & ARENA_FLAG_PREV_FREE)) else if (!contains( base, subheap_size( subheap ), block, block_get_size( block ) ))
{ err = "invalid block size";
ERR("Heap %p: bad flags %08x for free arena %p\n", else if (!is_valid_free_block( heap, (next = (struct block *)LIST_ENTRY( entry->entry.next, struct entry, entry )) ))
subheap->heap, pArena->size & ~ARENA_SIZE_MASK, pArena ); err = "invalid next free block pointer";
return FALSE; else if (!(block_get_flags( next ) & ARENA_FLAG_FREE) || block_get_type( next ) != ARENA_FREE_MAGIC)
} err = "invalid next free block header";
/* Check arena size */ else if (!is_valid_free_block( heap, (prev = (struct block *)LIST_ENTRY( entry->entry.prev, struct entry, entry )) ))
size = pArena->size & ARENA_SIZE_MASK; err = "invalid previous free block pointer";
if ((char *)(pArena + 1) + size > heapEnd) else if (!(block_get_flags( prev ) & ARENA_FLAG_FREE) || block_get_type( prev ) != ARENA_FREE_MAGIC)
{ err = "invalid previous free block header";
ERR("Heap %p: bad size %08lx for free arena %p\n", subheap->heap, size, pArena ); else if ((next = next_block( subheap, (struct block *)block )))
return FALSE; {
} if (!(block_get_flags( next ) & ARENA_FLAG_PREV_FREE))
/* Check that next pointer is valid */ err = "invalid next block flags";
next = LIST_ENTRY( pArena->entry.next, ARENA_FREE, entry ); if (*((struct block **)next - 1) != block)
if (!HEAP_IsValidArenaPtr( subheap->heap, next )) err = "invalid next block back pointer";
{ }
ERR("Heap %p: bad next ptr %p for arena %p\n",
subheap->heap, next, pArena ); if (!err && (flags & HEAP_FREE_CHECKING_ENABLED))
return FALSE; {
} const char *ptr = (char *)(entry + 1), *end = (char *)block + block_get_size( block );
/* Check that next arena is free */ if (end > commit_end) end = commit_end;
if (!(next->size & ARENA_FLAG_FREE) || (next->magic != ARENA_FREE_MAGIC)) while (!err && ptr < end)
{
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", if (*(DWORD *)ptr != ARENA_FREE_FILLER) err = "free block overwritten";
subheap->heap, pArena, ptr += sizeof(DWORD);
*((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; if (err)
else end -= sizeof(ARENA_FREE *); {
while (ptr < (DWORD *)end) ERR( "heap %p, block %p: %s\n", heap, block, err );
{ if (TRACE_ON(heap)) heap_dump( heap );
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;
return !err;
} }
...@@ -1297,7 +1237,7 @@ static BOOL validate_used_block( const SUBHEAP *subheap, const struct block *blo ...@@ -1297,7 +1237,7 @@ static BOOL validate_used_block( const SUBHEAP *subheap, const struct block *blo
else if (block_get_flags( block ) & ARENA_FLAG_PREV_FREE) else if (block_get_flags( block ) & ARENA_FLAG_PREV_FREE)
{ {
const struct block *prev = *((struct block **)block - 1); const struct block *prev = *((struct block **)block - 1);
if (!HEAP_IsValidArenaPtr( heap, (struct entry *)prev )) if (!is_valid_free_block( heap, prev ))
err = "invalid previous block pointer"; err = "invalid previous block pointer";
else if (!(block_get_flags( prev ) & ARENA_FLAG_FREE) || block_get_type( prev ) != ARENA_FREE_MAGIC) else if (!(block_get_flags( prev ) & ARENA_FLAG_FREE) || block_get_type( prev ) != ARENA_FREE_MAGIC)
err = "invalid previous block flags"; err = "invalid previous block flags";
...@@ -1353,7 +1293,7 @@ static BOOL heap_validate_ptr( const HEAP *heap, const void *ptr, SUBHEAP **subh ...@@ -1353,7 +1293,7 @@ static BOOL heap_validate_ptr( const HEAP *heap, const void *ptr, SUBHEAP **subh
static BOOL heap_validate( HEAP *heap, BOOL quiet ) static BOOL heap_validate( HEAP *heap, BOOL quiet )
{ {
const ARENA_LARGE *large_arena; const ARENA_LARGE *large_arena;
SUBHEAP *subheap; const SUBHEAP *subheap;
LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry )
{ {
...@@ -1370,7 +1310,7 @@ static BOOL heap_validate( HEAP *heap, BOOL quiet ) ...@@ -1370,7 +1310,7 @@ static BOOL heap_validate( HEAP *heap, BOOL quiet )
{ {
if (*(DWORD *)ptr & ARENA_FLAG_FREE) if (*(DWORD *)ptr & ARENA_FLAG_FREE)
{ {
if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) return FALSE; if (!validate_free_block( subheap, (ARENA_INUSE *)ptr )) return FALSE;
ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK); ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
} }
else else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment