From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index a23ab1a4c95..85964d04a59 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -127,9 +127,6 @@ C_ASSERT( sizeof(ARENA_LARGE) % LARGE_ALIGNMENT == 0 );
#define ROUND_SIZE(size) ((((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1)) + ARENA_OFFSET)
-#define QUIET 1 /* Suppress messages */ -#define NOISY 0 /* Report all errors */ - /* minimum data size (without arenas) of an allocated block */ /* make sure that it's larger than a free list entry */ #define HEAP_MIN_DATA_SIZE ROUND_SIZE(2 * sizeof(struct list)) @@ -289,7 +286,7 @@ static inline BOOL check_subheap( const SUBHEAP *subheap ) return contains( base, subheap->size, base + subheap->headerSize, subheap->commitSize - subheap->headerSize ); }
-static BOOL heap_validate( HEAP *heap, BOOL quiet ); +static BOOL heap_validate( HEAP *heap );
/* mark a block of memory as free for debugging purposes */ static inline void mark_block_free( void *ptr, SIZE_T size, DWORD flags ) @@ -579,7 +576,7 @@ static HEAP *HEAP_GetPtr( if (heapPtr->flags & HEAP_VALIDATE_ALL) { heap_lock( heapPtr, 0 ); - valid = heap_validate( heapPtr, NOISY ); + valid = heap_validate( heapPtr ); heap_unlock( heapPtr, 0 );
if (!valid && TRACE_ON(heap)) @@ -1290,7 +1287,7 @@ static BOOL heap_validate_ptr( const HEAP *heap, const void *ptr, SUBHEAP **subh return validate_used_block( *subheap, arena ); }
-static BOOL heap_validate( HEAP *heap, BOOL quiet ) +static BOOL heap_validate( HEAP *heap ) { const ARENA_LARGE *large_arena; const SUBHEAP *subheap; @@ -1930,7 +1927,7 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, const void *ptr ) { heap_lock( heapPtr, flags ); if (ptr) ret = heap_validate_ptr( heapPtr, ptr, &subheap ); - else ret = heap_validate( heapPtr, QUIET ); + else ret = heap_validate( heapPtr ); heap_unlock( heapPtr, flags ); }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 85964d04a59..b11218bc7a6 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -286,7 +286,7 @@ static inline BOOL check_subheap( const SUBHEAP *subheap ) return contains( base, subheap->size, base + subheap->headerSize, subheap->commitSize - subheap->headerSize ); }
-static BOOL heap_validate( HEAP *heap ); +static BOOL heap_validate( const HEAP *heap );
/* mark a block of memory as free for debugging purposes */ static inline void mark_block_free( void *ptr, SIZE_T size, DWORD flags ) @@ -1287,15 +1287,14 @@ static BOOL heap_validate_ptr( const HEAP *heap, const void *ptr, SUBHEAP **subh return validate_used_block( *subheap, arena ); }
-static BOOL heap_validate( HEAP *heap ) +static BOOL heap_validate( const HEAP *heap ) { const ARENA_LARGE *large_arena; + const struct block *block; const SUBHEAP *subheap;
LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) { - char *ptr = (char *)subheap->base + subheap->headerSize; - if (!check_subheap( subheap )) { ERR( "heap %p, subheap %p corrupted sizes\n", heap, subheap ); @@ -1303,17 +1302,15 @@ static BOOL heap_validate( HEAP *heap ) return FALSE; }
- while (ptr < (char *)subheap->base + subheap->size) + for (block = first_block( subheap ); block; block = next_block( subheap, block )) { - if (*(DWORD *)ptr & ARENA_FLAG_FREE) + if (block_get_flags( block ) & ARENA_FLAG_FREE) { - if (!validate_free_block( subheap, (ARENA_INUSE *)ptr )) return FALSE; - ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK); + if (!validate_free_block( subheap, block )) return FALSE; } else { - if (!validate_used_block( subheap, (ARENA_INUSE *)ptr )) return FALSE; - ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK); + if (!validate_used_block( subheap, block )) return FALSE; } } }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index b11218bc7a6..5174fe99fc3 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1405,37 +1405,28 @@ static void heap_set_debug_flags( HANDLE handle )
if (flags & (HEAP_FREE_CHECKING_ENABLED | HEAP_TAIL_CHECKING_ENABLED)) /* fix existing blocks */ { - SUBHEAP *subheap; + struct block *block; ARENA_LARGE *large; + SUBHEAP *subheap;
LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) { - char *ptr = (char *)subheap->base + subheap->headerSize; - char *end = (char *)subheap->base + subheap->commitSize; + const char *commit_end = subheap_commit_end( subheap );
if (!check_subheap( subheap )) break;
- while (ptr < end) + for (block = first_block( subheap ); block; block = next_block( subheap, block )) { - ARENA_INUSE *arena = (ARENA_INUSE *)ptr; - SIZE_T size = arena->size & ARENA_SIZE_MASK; - if (arena->size & ARENA_FLAG_FREE) + if (block_get_flags( block ) & ARENA_FLAG_FREE) { - SIZE_T count = size; - - ptr += sizeof(ARENA_FREE) + size; - if (ptr >= end) count = end - (char *)((ARENA_FREE *)arena + 1); - else count -= sizeof(ARENA_FREE *); - mark_block_free( (ARENA_FREE *)arena + 1, count, flags ); + char *data = (char *)block + block_get_overhead( block ), *end = (char *)block + block_get_size( block ); + if (end >= commit_end) mark_block_free( data, commit_end - data, flags ); + else mark_block_free( data, end - sizeof(struct block *) - data, flags ); } else { - if (arena->magic == ARENA_PENDING_MAGIC) - mark_block_free( arena + 1, size, flags ); - else - mark_block_tail( (char *)(arena + 1) + size - arena->unused_bytes, - arena->unused_bytes, flags ); - ptr += sizeof(ARENA_INUSE) + size; + if (block_get_type( block ) == ARENA_PENDING_MAGIC) mark_block_free( block + 1, block_get_size( block ) - sizeof(*block), flags ); + else mark_block_tail( (char *)block + block_get_size( block ) - block->unused_bytes, block->unused_bytes, flags ); } } }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 5174fe99fc3..0142328e978 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -614,15 +614,17 @@ static inline void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena, BOOL la }
-static SUBHEAP *find_subheap( const HEAP *heap, const void *ptr ) +static SUBHEAP *find_subheap( const HEAP *heap, const struct block *block, BOOL heap_walk ) { SUBHEAP *subheap;
LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) { + SIZE_T blocks_size = (char *)last_block( subheap ) - (char *)first_block( subheap ); if (!check_subheap( subheap )) return NULL; - if (contains( subheap_base( subheap ), subheap_size( subheap ), ptr, sizeof(struct block) )) - return subheap; + if (contains( first_block( subheap ), blocks_size, block, sizeof(*block) )) return subheap; + /* outside of blocks region, possible corruption or heap_walk */ + if (contains( subheap_base( subheap ), subheap_size( subheap ), block, 0 )) return heap_walk ? subheap : NULL; }
return NULL; @@ -760,7 +762,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 = find_subheap( heap, pArena ); + subheap = find_subheap( heap, pArena, FALSE ); }
/* Check if we can merge with previous block */ @@ -1097,7 +1099,7 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size, sizeof(ARENA_FREE) - sizeof(ARENA_INUSE); if (arena_size >= size) { - subheap = find_subheap( heap, pArena ); + subheap = find_subheap( heap, (struct block *)pArena, FALSE ); if (!HEAP_Commit( subheap, (ARENA_INUSE *)pArena, size )) return NULL; *ppSubHeap = subheap; return pArena; @@ -1145,9 +1147,7 @@ static BOOL is_valid_free_block( const HEAP *heap, const struct block *block ) const SUBHEAP *subheap; unsigned int i;
- if (!(subheap = find_subheap( heap, block ))) return FALSE; - if ((char *)block >= (char *)subheap->base + subheap->headerSize) return TRUE; - if (subheap != &heap->subheap) return FALSE; + if ((subheap = find_subheap( heap, block, FALSE ))) return TRUE; for (i = 0; i < HEAP_NB_FREE_LISTS; i++) if (block == (struct block *)&heap->freeList[i].arena) return TRUE; return FALSE; } @@ -1155,7 +1155,6 @@ static BOOL is_valid_free_block( const HEAP *heap, const struct block *block ) static BOOL validate_free_block( const SUBHEAP *subheap, const struct block *block ) { const char *err = NULL, *base = subheap_base( subheap ), *commit_end = subheap_commit_end( subheap ); - SIZE_T blocks_size = (char *)last_block( subheap ) - (char *)first_block( subheap ); const struct entry *entry = (struct entry *)block; const struct block *prev, *next; HEAP *heap = subheap->heap; @@ -1163,8 +1162,6 @@ static BOOL validate_free_block( const SUBHEAP *subheap, const struct block *blo
if ((ULONG_PTR)(block + 1) % ALIGNMENT) err = "invalid block alignment"; - else if (!contains( first_block( subheap ), blocks_size, block, sizeof(*block) )) - err = "invalid block pointer"; else if (block_get_type( block ) != ARENA_FREE_MAGIC) err = "invalid block header"; else if (!(block_get_flags( block ) & ARENA_FLAG_FREE) || (block_get_flags( block ) & ARENA_FLAG_PREV_FREE)) @@ -1211,7 +1208,6 @@ static BOOL validate_free_block( const SUBHEAP *subheap, const struct block *blo static BOOL validate_used_block( const SUBHEAP *subheap, const struct block *block ) { const char *err = NULL, *base = subheap_base( subheap ), *commit_end = subheap_commit_end( subheap ); - SIZE_T blocks_size = (char *)last_block( subheap ) - (char *)first_block( subheap ); const HEAP *heap = subheap->heap; DWORD flags = heap->flags; const struct block *next; @@ -1219,8 +1215,6 @@ static BOOL validate_used_block( const SUBHEAP *subheap, const struct block *blo
if ((ULONG_PTR)(block + 1) % ALIGNMENT) err = "invalid block alignment"; - else if (!contains( first_block( subheap ), blocks_size, block, sizeof(*block) )) - err = "invalid block pointer"; else if (block_get_type( block ) != ARENA_INUSE_MAGIC && block_get_type( block ) != ARENA_PENDING_MAGIC) err = "invalid block header"; else if (block_get_flags( block ) & ARENA_FLAG_FREE) @@ -1272,12 +1266,11 @@ static BOOL heap_validate_ptr( const HEAP *heap, const void *ptr, SUBHEAP **subh const struct block *arena = (struct block *)ptr - 1; const ARENA_LARGE *large_arena;
- if (!(*subheap = find_subheap( heap, arena )) || - ((const char *)arena < (char *)(*subheap)->base + (*subheap)->headerSize)) + if (!(*subheap = find_subheap( heap, arena, FALSE ))) { if (!(large_arena = find_large_block( heap, ptr ))) { - if (WARN_ON(heap)) WARN("heap %p, ptr %p is not inside heap\n", heap, ptr ); + if (WARN_ON(heap)) WARN("heap %p, ptr %p: block region not found\n", heap, ptr ); return FALSE; }
@@ -1325,7 +1318,6 @@ static inline struct block *unsafe_block_from_ptr( const HEAP *heap, const void { struct block *block = (struct block *)ptr - 1; const char *err = NULL, *base, *commit_end; - SIZE_T blocks_size;
if (heap->flags & HEAP_VALIDATE) { @@ -1333,11 +1325,10 @@ static inline struct block *unsafe_block_from_ptr( const HEAP *heap, const void return block; }
- if ((*subheap = find_subheap( heap, block ))) + if ((*subheap = find_subheap( heap, block, FALSE ))) { base = subheap_base( *subheap ); commit_end = subheap_commit_end( *subheap ); - blocks_size = (char *)last_block( *subheap ) - (char *)first_block( *subheap ); }
if (!*subheap) @@ -1347,8 +1338,6 @@ static inline struct block *unsafe_block_from_ptr( const HEAP *heap, const void } else if ((ULONG_PTR)ptr % ALIGNMENT) err = "invalid ptr alignment"; - else if (!contains( first_block( *subheap ), blocks_size, block, sizeof(*block) )) - err = "invalid block pointer"; else if (block_get_type( block ) == ARENA_PENDING_MAGIC || (block_get_flags( block ) & ARENA_FLAG_FREE)) err = "already freed block"; else if (block_get_type( block ) != ARENA_INUSE_MAGIC) @@ -1975,7 +1964,7 @@ static NTSTATUS heap_walk( const HEAP *heap, struct rtl_heap_entry *entry )
if ((large = find_large_block( heap, entry->lpData ))) next = &large->entry; - else if ((subheap = find_subheap( heap, entry->lpData ))) + else if ((subheap = find_subheap( heap, entry->lpData, TRUE ))) { if (!(status = heap_walk_blocks( heap, subheap, entry ))) return STATUS_SUCCESS; else if (status != STATUS_NO_MORE_ENTRIES) return status;
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 0142328e978..374b4e1f209 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1683,7 +1683,7 @@ static NTSTATUS heap_reallocate( HEAP *heap, ULONG flags, void *ptr, SIZE_T size oldActualSize = (pArena->size & ARENA_SIZE_MASK) - pArena->unused_bytes; if (rounded_size > oldBlockSize) { - char *pNext = (char *)(pArena + 1) + oldBlockSize; + struct block *next;
if (rounded_size >= HEAP_MIN_LARGE_BLOCK_SIZE && (flags & HEAP_GROWABLE)) { @@ -1694,14 +1694,14 @@ static NTSTATUS heap_reallocate( HEAP *heap, ULONG flags, void *ptr, SIZE_T size HEAP_MakeInUseBlockFree( subheap, pArena ); return STATUS_SUCCESS; } - if ((pNext < (char *)subheap->base + subheap->size) && - (*(DWORD *)pNext & ARENA_FLAG_FREE) && - (oldBlockSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= rounded_size)) + + if ((next = next_block( subheap, pArena )) && (block_get_flags( next ) & ARENA_FLAG_FREE) && + (oldBlockSize + block_get_size( next ) >= rounded_size)) { /* The next block is free and large enough */ - ARENA_FREE *pFree = (ARENA_FREE *)pNext; - list_remove( &pFree->entry ); - pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree); + struct entry *entry = (struct entry *)next; + list_remove( &entry->entry ); + pArena->size += block_get_size( next ); if (!HEAP_Commit( subheap, pArena, rounded_size )) return STATUS_NO_MEMORY; notify_realloc( pArena + 1, oldActualSize, size ); HEAP_ShrinkBlock( subheap, pArena, rounded_size );