From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 96bb0d0c027..658a8bc1ab0 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1069,6 +1069,7 @@ static struct block *find_free_block( HEAP *heap, SIZE_T data_size, SUBHEAP **su while ((ptr = list_next( &heap->freeList[0].arena.entry, ptr ))) { entry = LIST_ENTRY( ptr, struct entry, entry ); + if (entry->size == (0 | ARENA_FLAG_FREE)) continue; arena_size = (entry->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE); if (arena_size >= data_size) {
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 658a8bc1ab0..302e6cc75ee 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1061,8 +1061,9 @@ static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, LPVOID address, DWORD flags, static struct block *find_free_block( HEAP *heap, SIZE_T data_size, SUBHEAP **subheap ) { struct list *ptr = &find_free_list( heap, data_size + sizeof(ARENA_INUSE), FALSE )->entry; - SIZE_T total_size, arena_size; struct entry *entry; + struct block *block; + SIZE_T total_size;
/* Find a suitable free list, and in it find a block large enough */
@@ -1070,13 +1071,13 @@ static struct block *find_free_block( HEAP *heap, SIZE_T data_size, SUBHEAP **su { entry = LIST_ENTRY( ptr, struct entry, entry ); if (entry->size == (0 | ARENA_FLAG_FREE)) continue; - arena_size = (entry->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE); - if (arena_size >= data_size) + block = (struct block *)entry; + if (block_get_size( block ) - sizeof(*block) >= data_size) { - *subheap = find_subheap( heap, (struct block *)entry, FALSE ); - if (!HEAP_Commit( *subheap, (struct block *)entry, data_size )) return NULL; + *subheap = find_subheap( heap, block, FALSE ); + if (!HEAP_Commit( *subheap, block, data_size )) return NULL; list_remove( &entry->entry ); - return (struct block *)entry; + return block; } }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 70 ++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 41 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 302e6cc75ee..0983dc9d2b4 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -676,58 +676,47 @@ static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr ) }
-/*********************************************************************** - * HEAP_CreateFreeBlock - * - * Create a free block at a specified address. 'size' is the size of the - * whole block, including the new arena. - */ -static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, SIZE_T size ) +static void create_free_block( SUBHEAP *subheap, struct block *block, SIZE_T block_size ) { - ARENA_FREE *pFree; - char *pEnd; + struct entry *entry = (struct entry *)block; + HEAP *heap = subheap->heap; + DWORD flags = heap->flags; + char *end; BOOL last; - DWORD flags = subheap->heap->flags;
- /* Create a free arena */ - mark_block_uninitialized( ptr, sizeof(ARENA_FREE) ); - pFree = ptr; - pFree->magic = ARENA_FREE_MAGIC; + mark_block_uninitialized( block, sizeof(*entry) ); + entry->magic = ARENA_FREE_MAGIC;
/* If debugging, erase the freed block content */
- pEnd = (char *)ptr + size; - if (pEnd > (char *)subheap->base + subheap->commitSize) - pEnd = (char *)subheap->base + subheap->commitSize; - if (pEnd > (char *)(pFree + 1)) mark_block_free( pFree + 1, pEnd - (char *)(pFree + 1), flags ); + end = (char *)block + block_size; + if (end > (char *)subheap->base + subheap->commitSize) + end = (char *)subheap->base + subheap->commitSize; + if (end > (char *)(entry + 1)) mark_block_free( entry + 1, end - (char *)(entry + 1), flags );
- /* Check if next block is free also */ - - if (((char *)ptr + size < (char *)subheap->base + subheap->size) && - (*(DWORD *)((char *)ptr + size) & ARENA_FLAG_FREE)) + if (((char *)block + block_size < (char *)subheap->base + subheap->size) && + (*(DWORD *)((char *)block + block_size) & ARENA_FLAG_FREE)) { - /* Remove the next arena from the free list */ - ARENA_FREE *pNext = (ARENA_FREE *)((char *)ptr + size); - list_remove( &pNext->entry ); - size += (pNext->size & ARENA_SIZE_MASK) + sizeof(*pNext); - mark_block_free( pNext, sizeof(ARENA_FREE), flags ); + /* merge with the next block if it is free */ + struct entry *next_entry = (struct entry *)((char *)block + block_size); + list_remove( &next_entry->entry ); + block_size += (next_entry->size & ARENA_SIZE_MASK) + sizeof(*next_entry); + mark_block_free( next_entry, sizeof(struct entry), flags ); }
- /* Set the next block PREV_FREE flag and pointer */
- last = ((char *)ptr + size >= (char *)subheap->base + subheap->size); + last = ((char *)block + block_size >= (char *)subheap->base + subheap->size); if (!last) { - DWORD *pNext = (DWORD *)((char *)ptr + size); - *pNext |= ARENA_FLAG_PREV_FREE; - mark_block_initialized( (ARENA_FREE **)pNext - 1, sizeof( ARENA_FREE * ) ); - *((ARENA_FREE **)pNext - 1) = pFree; + /* set the next block PREV_FREE flag and back pointer */ + DWORD *next = (DWORD *)((char *)block + block_size); + *next |= ARENA_FLAG_PREV_FREE; + mark_block_initialized( (struct block **)next - 1, sizeof(struct block *) ); + *((struct block **)next - 1) = block; }
- /* Last, insert the new block into the free list */ - - pFree->size = (size - sizeof(*pFree)) | ARENA_FLAG_FREE; - HEAP_InsertFreeBlock( subheap->heap, pFree, last ); + entry->size = (block_size - sizeof(*entry)) | ARENA_FLAG_FREE; + HEAP_InsertFreeBlock( subheap->heap, entry, last ); }
@@ -769,7 +758,7 @@ static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
/* Create a free block */
- HEAP_CreateFreeBlock( subheap, pFree, size ); + create_free_block( subheap, (struct block *)pFree, size ); size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE); if ((char *)pFree + size < (char *)subheap->base + subheap->size) return; /* Not the last block, so nothing more to do */ @@ -805,7 +794,7 @@ static void shrink_used_block( SUBHEAP *subheap, struct block *block, SIZE_T dat { block->size = data_size | block_get_flags( block ); block->unused_bytes = data_size - size; - HEAP_CreateFreeBlock( subheap, next_block( subheap, block ), old_data_size - data_size ); + create_free_block( subheap, next_block( subheap, block ), old_data_size - data_size ); } else { @@ -1051,8 +1040,7 @@ static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, LPVOID address, DWORD flags,
/* Create the first free block */
- HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap->base + subheap->headerSize, - subheap->size - subheap->headerSize ); + create_free_block( subheap, first_block( subheap ), subheap->size - subheap->headerSize );
return subheap; }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 0983dc9d2b4..7e21593cd56 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -231,6 +231,12 @@ static inline UINT block_get_type( const struct block *block ) return block->magic; }
+static inline void block_set_type( struct block *block, UINT type ) +{ + if (type >> 24) block->unused_bytes = type >> 24; + block->magic = type; +} + static inline UINT block_get_overhead( const struct block *block ) { if (block_get_flags( block ) & ARENA_FLAG_FREE) return sizeof(struct entry); @@ -685,7 +691,7 @@ static void create_free_block( SUBHEAP *subheap, struct block *block, SIZE_T blo BOOL last;
mark_block_uninitialized( block, sizeof(*entry) ); - entry->magic = ARENA_FREE_MAGIC; + block_set_type( block, ARENA_FREE_MAGIC );
/* If debugging, erase the freed block content */
@@ -737,7 +743,7 @@ static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena ) ARENA_INUSE *prev = heap->pending_free[heap->pending_pos]; heap->pending_free[heap->pending_pos] = pArena; heap->pending_pos = (heap->pending_pos + 1) % MAX_FREE_PENDING; - pArena->magic = ARENA_PENDING_MAGIC; + block_set_type( pArena, ARENA_PENDING_MAGIC ); mark_block_free( pArena + 1, pArena->size & ARENA_SIZE_MASK, heap->flags ); if (!prev) return; pArena = prev; @@ -1536,7 +1542,7 @@ static NTSTATUS heap_allocate( HEAP *heap, ULONG flags, SIZE_T size, void **ret /* in-use arena is smaller than free arena, * so we have to add the difference to the size */ block->size = (block->size & ~ARENA_FLAG_FREE) + sizeof(struct entry) - sizeof(*block); - block->magic = ARENA_INUSE_MAGIC; + block_set_type( block, ARENA_INUSE_MAGIC );
/* Shrink the block */
From: Rémi Bernon rbernon@codeweavers.com
And use them in shrink_used_block to set the block sizes.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 7e21593cd56..a22f5ec7f1e 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -253,6 +253,13 @@ static inline UINT block_get_size( const struct block *block ) return size; }
+static inline void block_set_size( struct block *block, UINT flags, UINT block_size ) +{ + if (flags & ARENA_FLAG_FREE) block_size -= sizeof(struct entry); + else block_size -= sizeof(*block); + block->size = (block_size & ARENA_SIZE_MASK) | (flags & ~ARENA_SIZE_MASK); +} + static inline void *subheap_base( const SUBHEAP *subheap ) { return subheap->base; @@ -793,18 +800,19 @@ static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena ) }
-static void shrink_used_block( SUBHEAP *subheap, struct block *block, SIZE_T data_size, SIZE_T size ) +static inline void shrink_used_block( SUBHEAP *subheap, struct block *block, UINT flags, + SIZE_T old_data_size, SIZE_T data_size, SIZE_T size ) { - SIZE_T old_data_size = block_get_size( block ) - sizeof(*block); if (old_data_size >= data_size + HEAP_MIN_SHRINK_SIZE) { - block->size = data_size | block_get_flags( block ); + block_set_size( block, flags, data_size + sizeof(*block) ); block->unused_bytes = data_size - size; create_free_block( subheap, next_block( subheap, block ), old_data_size - data_size ); } else { struct block *next; + block_set_size( block, flags, old_data_size + sizeof(*block) ); block->unused_bytes = old_data_size - size; if ((next = next_block( subheap, block ))) next->size &= ~ARENA_FLAG_PREV_FREE; } @@ -1521,8 +1529,8 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE heap )
static NTSTATUS heap_allocate( HEAP *heap, ULONG flags, SIZE_T size, void **ret ) { + SIZE_T old_data_size, data_size; struct block *block; - SIZE_T data_size; SUBHEAP *subheap;
data_size = ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE(flags); @@ -1538,15 +1546,11 @@ static NTSTATUS heap_allocate( HEAP *heap, ULONG flags, SIZE_T size, void **ret /* Locate a suitable free block */
if (!(block = find_free_block( heap, data_size, &subheap ))) return STATUS_NO_MEMORY; + /* read the free block size, changing block type or flags may alter it */ + old_data_size = block_get_size( block ) - sizeof(*block);
- /* in-use arena is smaller than free arena, - * so we have to add the difference to the size */ - block->size = (block->size & ~ARENA_FLAG_FREE) + sizeof(struct entry) - sizeof(*block); block_set_type( block, ARENA_INUSE_MAGIC ); - - /* Shrink the block */ - - shrink_used_block( subheap, block, data_size, size ); + shrink_used_block( subheap, block, 0, old_data_size, data_size, size );
notify_alloc( block + 1, size, flags & HEAP_ZERO_MEMORY ); initialize_block( block + 1, size, block->unused_bytes, flags ); @@ -1649,10 +1653,10 @@ static NTSTATUS heap_reallocate( HEAP *heap, ULONG flags, void *ptr, SIZE_T size /* The next block is free and large enough */ struct entry *entry = (struct entry *)next; list_remove( &entry->entry ); - block->size += block_get_size( next ); + old_data_size += block_get_size( next ); if (!HEAP_Commit( subheap, block, data_size )) return STATUS_NO_MEMORY; notify_realloc( block + 1, old_size, size ); - shrink_used_block( subheap, block, data_size, size ); + shrink_used_block( subheap, block, block_get_flags( block ), old_data_size, data_size, size ); } else { @@ -1668,7 +1672,7 @@ static NTSTATUS heap_reallocate( HEAP *heap, ULONG flags, void *ptr, SIZE_T size else { notify_realloc( block + 1, old_size, size ); - shrink_used_block( subheap, block, data_size, size ); + shrink_used_block( subheap, block, block_get_flags( block ), old_data_size, data_size, size ); }
/* Clear the extra bytes if needed */
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index a22f5ec7f1e..767a010d93e 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -691,45 +691,40 @@ static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr )
static void create_free_block( SUBHEAP *subheap, struct block *block, SIZE_T block_size ) { + const char *end = (char *)block + block_size, *commit_end = subheap_commit_end( subheap ); struct entry *entry = (struct entry *)block; HEAP *heap = subheap->heap; DWORD flags = heap->flags; - char *end; - BOOL last; + struct block *next;
mark_block_uninitialized( block, sizeof(*entry) ); block_set_type( block, ARENA_FREE_MAGIC ); + block_set_size( block, ARENA_FLAG_FREE, block_size );
/* If debugging, erase the freed block content */
- end = (char *)block + block_size; - if (end > (char *)subheap->base + subheap->commitSize) - end = (char *)subheap->base + subheap->commitSize; + if (end > commit_end) end = commit_end; if (end > (char *)(entry + 1)) mark_block_free( entry + 1, end - (char *)(entry + 1), flags );
- if (((char *)block + block_size < (char *)subheap->base + subheap->size) && - (*(DWORD *)((char *)block + block_size) & ARENA_FLAG_FREE)) + if ((next = next_block( subheap, block )) && (block_get_flags( next ) & ARENA_FLAG_FREE)) { /* merge with the next block if it is free */ - struct entry *next_entry = (struct entry *)((char *)block + block_size); + struct entry *next_entry = (struct entry *)next; list_remove( &next_entry->entry ); - block_size += (next_entry->size & ARENA_SIZE_MASK) + sizeof(*next_entry); - mark_block_free( next_entry, sizeof(struct entry), flags ); + block_size += block_get_size( next ); + block_set_size( block, ARENA_FLAG_FREE, block_size ); + mark_block_free( next_entry, sizeof(*next_entry), flags ); }
- - last = ((char *)block + block_size >= (char *)subheap->base + subheap->size); - if (!last) + if ((next = next_block( subheap, block ))) { /* set the next block PREV_FREE flag and back pointer */ - DWORD *next = (DWORD *)((char *)block + block_size); - *next |= ARENA_FLAG_PREV_FREE; + block_set_size( next, ARENA_FLAG_PREV_FREE, block_get_size( next ) ); mark_block_initialized( (struct block **)next - 1, sizeof(struct block *) ); *((struct block **)next - 1) = block; }
- entry->size = (block_size - sizeof(*entry)) | ARENA_FLAG_FREE; - HEAP_InsertFreeBlock( subheap->heap, entry, last ); + HEAP_InsertFreeBlock( heap, entry, !next ); }