[PATCH v2 6/8] ntdll: Improve block size rounding compatibility.
Rémi Bernon
wine at gitlab.winehq.org
Thu Jun 2 01:24:43 CDT 2022
From: Rémi Bernon <rbernon at codeweavers.com>
This also increase the default heap size to 2MiB (32bit) / 4MiB (64bit),
for the tests to pass.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/kernel32/tests/heap.c | 6 +----
dlls/ntdll/heap.c | 46 +++++++++++++++++++++++++-------------
2 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c
index bb5e57fe94e..91f582f36de 100644
--- a/dlls/kernel32/tests/heap.c
+++ b/dlls/kernel32/tests/heap.c
@@ -1055,7 +1055,6 @@ static void test_HeapCreate(void)
{
if (entries[i].wFlags != PROCESS_HEAP_ENTRY_BUSY) continue;
ok( entries[i].cbData == 0x18 + 2 * sizeof(void *), "got cbData %#lx\n", entries[i].cbData );
- todo_wine_if(sizeof(void *) == 8)
ok( entries[i].cbOverhead == 0x8, "got cbOverhead %#x\n", entries[i].cbOverhead );
}
@@ -2175,10 +2174,7 @@ static void test_block_layout( HANDLE heap, DWORD global_flags, DWORD heap_flags
expect_size = max( alloc_size, 2 * sizeof(void *) );
expect_size = ALIGN_BLOCK_SIZE( expect_size + extra_size );
diff = min( llabs( ptr2 - ptr1 ), llabs( ptr1 - ptr0 ) );
- todo_wine_if( (heap_flags & (HEAP_VALIDATE_PARAMS|HEAP_VALIDATE_ALL)) ||
- ((global_flags & ~FLG_HEAP_ENABLE_TAIL_CHECK) && alloc_size < 0x10000) ||
- (!global_flags && alloc_size < 2 * sizeof(void *)) ||
- (alloc_size == 0xfd000 && sizeof(void *) == 8) )
+ todo_wine_if( (!(global_flags & ~FLG_HEAP_ENABLE_FREE_CHECK) && alloc_size < 2 * sizeof(void *)) )
ok( diff == expect_size, "got diff %#Ix exp %#Ix\n", diff, expect_size );
ok( !memcmp( ptr0 + alloc_size, tail_buf, tail_size ), "missing block tail\n" );
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c
index 59d191ed1b3..0a6228217ff 100644
--- a/dlls/ntdll/heap.c
+++ b/dlls/ntdll/heap.c
@@ -127,20 +127,18 @@ typedef struct
/* everything is aligned on 8 byte boundaries (16 for Win64) */
#define LARGE_ALIGNMENT 16 /* large blocks have stricter alignment */
-#define ARENA_OFFSET (ALIGNMENT - sizeof(struct block))
#define COMMIT_MASK 0xffff /* bitmask for commit/decommit granularity */
C_ASSERT( sizeof(ARENA_LARGE) % LARGE_ALIGNMENT == 0 );
#define ROUND_ADDR(addr, mask) ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask)))
-#define ROUND_SIZE(size) ((((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1)) + ARENA_OFFSET)
-
-/* 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))
-#define HEAP_MIN_BLOCK_SIZE (HEAP_MIN_DATA_SIZE + sizeof(struct block))
-/* minimum size that must remain to shrink an allocated block */
-#define HEAP_MIN_SHRINK_SIZE (HEAP_MIN_DATA_SIZE+sizeof(struct entry))
+#define ROUND_SIZE(size, mask) ((((SIZE_T)(size) + (mask)) & ~(SIZE_T)(mask)))
+
+#define HEAP_MIN_BLOCK_SIZE ROUND_SIZE(sizeof(struct entry) + ALIGNMENT, ALIGNMENT - 1)
+
+C_ASSERT( sizeof(struct block) <= HEAP_MIN_BLOCK_SIZE );
+C_ASSERT( sizeof(struct entry) <= HEAP_MIN_BLOCK_SIZE );
+
/* minimum size to start allocating large blocks */
#define HEAP_MIN_LARGE_BLOCK_SIZE (0x10000 * ALIGNMENT - 0x1000)
/* extra size to add at the end of block for tail checking */
@@ -208,7 +206,7 @@ C_ASSERT( offsetof(HEAP, subheap) <= COMMIT_MASK );
#define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
-#define HEAP_DEF_SIZE 0x110000 /* Default heap size = 1Mb + 64Kb */
+#define HEAP_DEF_SIZE (0x40000 * ALIGNMENT)
#define MAX_FREE_PENDING 1024 /* max number of free requests to delay */
/* some undocumented flags (names are made up) */
@@ -217,6 +215,7 @@ C_ASSERT( offsetof(HEAP, subheap) <= COMMIT_MASK );
#define HEAP_VALIDATE 0x10000000
#define HEAP_VALIDATE_ALL 0x20000000
#define HEAP_VALIDATE_PARAMS 0x40000000
+#define HEAP_CHECKING_ENABLED 0x80000000
static HEAP *processHeap; /* main process heap */
@@ -447,7 +446,8 @@ static RTL_CRITICAL_SECTION_DEBUG process_heap_cs_debug =
static inline ULONG heap_get_flags( const HEAP *heap, ULONG flags )
{
- flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY | HEAP_REALLOC_IN_PLACE_ONLY;
+ if (flags & (HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED)) flags |= HEAP_CHECKING_ENABLED;
+ flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY | HEAP_REALLOC_IN_PLACE_ONLY | HEAP_CHECKING_ENABLED;
return heap->flags | flags;
}
@@ -760,7 +760,7 @@ static void free_used_block( SUBHEAP *subheap, struct block *block )
static inline void shrink_used_block( SUBHEAP *subheap, struct block *block, UINT flags,
SIZE_T old_block_size, SIZE_T block_size, SIZE_T size )
{
- if (old_block_size >= block_size + HEAP_MIN_SHRINK_SIZE)
+ if (old_block_size >= block_size + HEAP_MIN_BLOCK_SIZE)
{
block_set_size( block, flags, block_size );
block->unused_bytes = block_size - sizeof(*block) - size;
@@ -782,7 +782,7 @@ static inline void shrink_used_block( SUBHEAP *subheap, struct block *block, UIN
static void *allocate_large_block( HEAP *heap, DWORD flags, SIZE_T size )
{
ARENA_LARGE *arena;
- SIZE_T block_size = sizeof(*arena) + ROUND_SIZE( size );
+ SIZE_T block_size = ROUND_SIZE( sizeof(*arena) + size, COMMIT_MASK );
LPVOID address = NULL;
if (!(flags & HEAP_GROWABLE)) return NULL;
@@ -1469,13 +1469,29 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE heap )
return 0;
}
+static SIZE_T heap_get_block_size( HEAP *heap, ULONG flags, SIZE_T size )
+{
+ static const ULONG padd_flags = HEAP_VALIDATE | HEAP_VALIDATE_ALL | HEAP_VALIDATE_PARAMS;
+ static const ULONG check_flags = HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED | HEAP_CHECKING_ENABLED;
+ SIZE_T overhead;
+
+ if ((flags & check_flags)) overhead = ALIGNMENT;
+ else overhead = sizeof(struct block);
+
+ if ((flags & HEAP_TAIL_CHECKING_ENABLED) || RUNNING_ON_VALGRIND) overhead += ALIGNMENT;
+ if (flags & padd_flags) overhead += ALIGNMENT;
+
+ if (size < ALIGNMENT) size = ALIGNMENT;
+ return ROUND_SIZE( size + overhead, ALIGNMENT - 1 );
+}
+
static NTSTATUS heap_allocate( HEAP *heap, ULONG flags, SIZE_T size, void **ret )
{
SIZE_T old_block_size, block_size;
struct block *block;
SUBHEAP *subheap;
- block_size = sizeof(*block) + ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE(flags);
+ block_size = heap_get_block_size( heap, flags, size );
if (block_size < size) return STATUS_NO_MEMORY; /* overflow */
if (block_size < HEAP_MIN_BLOCK_SIZE) block_size = HEAP_MIN_BLOCK_SIZE;
@@ -1572,7 +1588,7 @@ static NTSTATUS heap_reallocate( HEAP *heap, ULONG flags, void *ptr, SIZE_T size
SUBHEAP *subheap;
NTSTATUS status;
- block_size = sizeof(*block) + ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE(flags);
+ block_size = heap_get_block_size( heap, flags, size );
if (block_size < size) return STATUS_NO_MEMORY; /* overflow */
if (block_size < HEAP_MIN_BLOCK_SIZE) block_size = HEAP_MIN_BLOCK_SIZE;
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/165
More information about the wine-devel
mailing list