Commit 38ba5fe0 authored by Robert Shearman's avatar Robert Shearman Committed by Alexandre Julliard

- Make the value returned from HeapSize always match the requested

size passed into HeapAllocate/HeapReAllocate. - Add a test for this behaviour.
parent 28dc5a8a
...@@ -38,6 +38,15 @@ START_TEST(heap) ...@@ -38,6 +38,15 @@ START_TEST(heap)
mem = HeapReAlloc(GetProcessHeap(), 0, NULL, 10); mem = HeapReAlloc(GetProcessHeap(), 0, NULL, 10);
ok(mem == NULL, "memory allocated by HeapReAlloc\n"); ok(mem == NULL, "memory allocated by HeapReAlloc\n");
for (size = 0; size <= 256; size++)
{
SIZE_T heap_size;
mem = HeapAlloc(GetProcessHeap(), 0, size);
heap_size = HeapSize(GetProcessHeap(), 0, mem);
ok(size == heap_size, "HeapSize returned %lu instead of %lu\n", heap_size, size);
HeapFree(GetProcessHeap(), 0, mem);
}
/* Global*() functions */ /* Global*() functions */
gbl = GlobalAlloc(GMEM_MOVEABLE, 0); gbl = GlobalAlloc(GMEM_MOVEABLE, 0);
ok(gbl != NULL, "global memory not allocated for size 0\n"); ok(gbl != NULL, "global memory not allocated for size 0\n");
......
...@@ -51,7 +51,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(heap); ...@@ -51,7 +51,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(heap);
typedef struct tagARENA_INUSE typedef struct tagARENA_INUSE
{ {
DWORD size; /* Block size; must be the first field */ DWORD size; /* Block size; must be the first field */
DWORD magic; /* Magic number */ DWORD magic : 27; /* Magic number */
DWORD unused_bytes : 5; /* Number of bytes in the block not used by user data (max value is HEAP_MIN_BLOCK_SIZE+ALIGNMENT) */
} ARENA_INUSE; } ARENA_INUSE;
typedef struct tagARENA_FREE typedef struct tagARENA_FREE
...@@ -65,7 +66,7 @@ typedef struct tagARENA_FREE ...@@ -65,7 +66,7 @@ typedef struct tagARENA_FREE
#define ARENA_FLAG_FREE 0x00000001 /* flags OR'ed with arena size */ #define ARENA_FLAG_FREE 0x00000001 /* flags OR'ed with arena size */
#define ARENA_FLAG_PREV_FREE 0x00000002 #define ARENA_FLAG_PREV_FREE 0x00000002
#define ARENA_SIZE_MASK (~3) #define ARENA_SIZE_MASK (~3)
#define ARENA_INUSE_MAGIC 0x44455355 /* Value for arena 'magic' field */ #define ARENA_INUSE_MAGIC 0x4455355 /* Value for arena 'magic' field */
#define ARENA_FREE_MAGIC 0x45455246 /* Value for arena 'magic' field */ #define ARENA_FREE_MAGIC 0x45455246 /* Value for arena 'magic' field */
#define ARENA_INUSE_FILLER 0x55 #define ARENA_INUSE_FILLER 0x55
...@@ -1132,19 +1133,20 @@ PVOID WINAPI RtlAllocateHeap( HANDLE heap, ULONG flags, ULONG size ) ...@@ -1132,19 +1133,20 @@ PVOID WINAPI RtlAllocateHeap( HANDLE heap, ULONG flags, ULONG size )
ARENA_INUSE *pInUse; ARENA_INUSE *pInUse;
SUBHEAP *subheap; SUBHEAP *subheap;
HEAP *heapPtr = HEAP_GetPtr( heap ); HEAP *heapPtr = HEAP_GetPtr( heap );
ULONG rounded_size;
/* Validate the parameters */ /* Validate the parameters */
if (!heapPtr) return NULL; if (!heapPtr) return NULL;
flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY; flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
flags |= heapPtr->flags; flags |= heapPtr->flags;
size = ROUND_SIZE(size); rounded_size = ROUND_SIZE(size);
if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE; if (rounded_size < HEAP_MIN_BLOCK_SIZE) rounded_size = HEAP_MIN_BLOCK_SIZE;
if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
/* Locate a suitable free block */ /* Locate a suitable free block */
if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap ))) if (!(pArena = HEAP_FindFreeBlock( heapPtr, rounded_size, &subheap )))
{ {
TRACE("(%p,%08lx,%08lx): returning NULL\n", TRACE("(%p,%08lx,%08lx): returning NULL\n",
heap, flags, size ); heap, flags, size );
...@@ -1169,7 +1171,8 @@ PVOID WINAPI RtlAllocateHeap( HANDLE heap, ULONG flags, ULONG size ) ...@@ -1169,7 +1171,8 @@ PVOID WINAPI RtlAllocateHeap( HANDLE heap, ULONG flags, ULONG size )
/* Shrink the block */ /* Shrink the block */
HEAP_ShrinkBlock( subheap, pInUse, size ); HEAP_ShrinkBlock( subheap, pInUse, rounded_size );
pInUse->unused_bytes = (pInUse->size & ARENA_SIZE_MASK) - size;
if (flags & HEAP_ZERO_MEMORY) if (flags & HEAP_ZERO_MEMORY)
clear_block( pInUse + 1, pInUse->size & ARENA_SIZE_MASK ); clear_block( pInUse + 1, pInUse->size & ARENA_SIZE_MASK );
...@@ -1262,6 +1265,7 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size ...@@ -1262,6 +1265,7 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size
DWORD oldSize; DWORD oldSize;
HEAP *heapPtr; HEAP *heapPtr;
SUBHEAP *subheap; SUBHEAP *subheap;
ULONG rounded_size;
if (!ptr) return NULL; if (!ptr) return NULL;
if (!(heapPtr = HEAP_GetPtr( heap ))) if (!(heapPtr = HEAP_GetPtr( heap )))
...@@ -1275,8 +1279,8 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size ...@@ -1275,8 +1279,8 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size
flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY | flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
HEAP_REALLOC_IN_PLACE_ONLY; HEAP_REALLOC_IN_PLACE_ONLY;
flags |= heapPtr->flags; flags |= heapPtr->flags;
size = ROUND_SIZE(size); rounded_size = ROUND_SIZE(size);
if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE; if (rounded_size < HEAP_MIN_BLOCK_SIZE) rounded_size = HEAP_MIN_BLOCK_SIZE;
if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET )) if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
...@@ -1293,12 +1297,12 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size ...@@ -1293,12 +1297,12 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size
pArena = (ARENA_INUSE *)ptr - 1; pArena = (ARENA_INUSE *)ptr - 1;
subheap = HEAP_FindSubHeap( heapPtr, pArena ); subheap = HEAP_FindSubHeap( heapPtr, pArena );
oldSize = (pArena->size & ARENA_SIZE_MASK); oldSize = (pArena->size & ARENA_SIZE_MASK);
if (size > oldSize) if (rounded_size > oldSize)
{ {
char *pNext = (char *)(pArena + 1) + oldSize; char *pNext = (char *)(pArena + 1) + oldSize;
if ((pNext < (char *)subheap + subheap->size) && if ((pNext < (char *)subheap + subheap->size) &&
(*(DWORD *)pNext & ARENA_FLAG_FREE) && (*(DWORD *)pNext & ARENA_FLAG_FREE) &&
(oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= size)) (oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= rounded_size))
{ {
/* The next block is free and large enough */ /* The next block is free and large enough */
ARENA_FREE *pFree = (ARENA_FREE *)pNext; ARENA_FREE *pFree = (ARENA_FREE *)pNext;
...@@ -1306,14 +1310,14 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size ...@@ -1306,14 +1310,14 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size
pFree->prev->next = pFree->next; pFree->prev->next = pFree->next;
pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree); pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree);
if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE) if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
+ size + HEAP_MIN_BLOCK_SIZE)) + rounded_size + HEAP_MIN_BLOCK_SIZE))
{ {
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY ); if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_NO_MEMORY ); RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_NO_MEMORY );
return NULL; return NULL;
} }
HEAP_ShrinkBlock( subheap, pArena, size ); HEAP_ShrinkBlock( subheap, pArena, rounded_size );
} }
else /* Do it the hard way */ else /* Do it the hard way */
{ {
...@@ -1322,7 +1326,7 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size ...@@ -1322,7 +1326,7 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size
SUBHEAP *newsubheap; SUBHEAP *newsubheap;
if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) || if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) ||
!(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap ))) !(pNew = HEAP_FindFreeBlock( heapPtr, rounded_size, &newsubheap )))
{ {
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY ); if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
...@@ -1338,7 +1342,7 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size ...@@ -1338,7 +1342,7 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size
pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE) pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE)
+ sizeof(ARENA_FREE) - sizeof(ARENA_INUSE); + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
pInUse->magic = ARENA_INUSE_MAGIC; pInUse->magic = ARENA_INUSE_MAGIC;
HEAP_ShrinkBlock( newsubheap, pInUse, size ); HEAP_ShrinkBlock( newsubheap, pInUse, rounded_size );
mark_block_initialized( pInUse + 1, oldSize ); mark_block_initialized( pInUse + 1, oldSize );
memcpy( pInUse + 1, pArena + 1, oldSize ); memcpy( pInUse + 1, pArena + 1, oldSize );
...@@ -1349,11 +1353,13 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size ...@@ -1349,11 +1353,13 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size
pArena = pInUse; pArena = pInUse;
} }
} }
else HEAP_ShrinkBlock( subheap, pArena, size ); /* Shrink the block */ else HEAP_ShrinkBlock( subheap, pArena, rounded_size ); /* Shrink the block */
pArena->unused_bytes = (pArena->size & ARENA_SIZE_MASK) - size;
/* Clear the extra bytes if needed */ /* Clear the extra bytes if needed */
if (size > oldSize) if (rounded_size > oldSize)
{ {
if (flags & HEAP_ZERO_MEMORY) if (flags & HEAP_ZERO_MEMORY)
clear_block( (char *)(pArena + 1) + oldSize, clear_block( (char *)(pArena + 1) + oldSize,
...@@ -1475,7 +1481,7 @@ ULONG WINAPI RtlSizeHeap( HANDLE heap, ULONG flags, PVOID ptr ) ...@@ -1475,7 +1481,7 @@ ULONG WINAPI RtlSizeHeap( HANDLE heap, ULONG flags, PVOID ptr )
else else
{ {
ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1; ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1;
ret = pArena->size & ARENA_SIZE_MASK; ret = (pArena->size & ARENA_SIZE_MASK) - pArena->unused_bytes;
} }
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
......
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