mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 01:15:43 +00:00
- Some 64bits syncs from Wine by Samuel Serapion.
svn path=/trunk/; revision=38648
This commit is contained in:
parent
174b42a736
commit
eca633ce05
1 changed files with 106 additions and 65 deletions
|
@ -68,7 +68,7 @@
|
|||
|
||||
typedef struct tagARENA_INUSE
|
||||
{
|
||||
DWORD size; /* Block size; must be the first field */
|
||||
SIZE_T size; /* Block size; must be the first field */
|
||||
DWORD magic : 23; /* Magic number */
|
||||
DWORD has_user_data : 1; /* There is user data associated with this block */
|
||||
DWORD unused_bytes : 8; /* Number of bytes in the block not used by user data (max value is HEAP_MIN_DATA_SIZE+HEAP_MIN_SHRINK_SIZE) */
|
||||
|
@ -76,7 +76,7 @@ typedef struct tagARENA_INUSE
|
|||
|
||||
typedef struct tagARENA_FREE
|
||||
{
|
||||
DWORD size; /* Block size; must be the first field */
|
||||
SIZE_T size; /* Block size; must be the first field */
|
||||
DWORD magic; /* Magic number */
|
||||
struct list entry; /* Entry in free list */
|
||||
} ARENA_FREE;
|
||||
|
@ -90,14 +90,18 @@ typedef struct tagARENA_FREE
|
|||
#define ARENA_INUSE_FILLER 0x55
|
||||
#define ARENA_FREE_FILLER 0xaa
|
||||
|
||||
#define ALIGNMENT 8 /* everything is aligned on 8 byte boundaries */
|
||||
#define ROUND_SIZE(size) (((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1))
|
||||
/* everything is aligned on 8 byte boundaries (16 for Win64)*/
|
||||
#define ALIGNMENT (2*sizeof(void*))
|
||||
#define ARENA_OFFSET (ALIGNMENT - sizeof(ARENA_INUSE))
|
||||
|
||||
#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 */
|
||||
#define HEAP_MIN_DATA_SIZE 16
|
||||
#define HEAP_MIN_DATA_SIZE ROUND_SIZE(2 * sizeof(struct list))
|
||||
/* minimum size that must remain to shrink an allocated block */
|
||||
#define HEAP_MIN_SHRINK_SIZE (HEAP_MIN_DATA_SIZE+sizeof(ARENA_FREE))
|
||||
|
||||
|
@ -112,14 +116,15 @@ static const DWORD HEAP_freeListSizes[HEAP_NB_FREE_LISTS] =
|
|||
typedef struct
|
||||
{
|
||||
ARENA_FREE arena;
|
||||
void *aligment[4];
|
||||
} FREE_LIST_ENTRY;
|
||||
|
||||
struct tagHEAP;
|
||||
|
||||
typedef struct tagSUBHEAP
|
||||
{
|
||||
DWORD size; /* Size of the whole sub-heap */
|
||||
DWORD commitSize; /* Committed size of the sub-heap */
|
||||
SIZE_T size; /* Size of the whole sub-heap */
|
||||
SIZE_T commitSize; /* Committed size of the sub-heap */
|
||||
DWORD headerSize; /* Size of the heap header */
|
||||
struct tagSUBHEAP *next; /* Next sub-heap */
|
||||
struct tagHEAP *heap; /* Main heap structure */
|
||||
|
@ -208,6 +213,12 @@ static __inline unsigned int get_freelist_index( SIZE_T size )
|
|||
return i;
|
||||
}
|
||||
|
||||
/* get the memory protection type to use for a given heap */
|
||||
static inline ULONG get_protection_type( DWORD flags )
|
||||
{
|
||||
return (flags & HEAP_CREATE_ENABLE_EXECUTE) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
||||
}
|
||||
|
||||
static RTL_CRITICAL_SECTION_DEBUG process_heap_critsect_debug =
|
||||
{
|
||||
0, 0, NULL, /* will be set later */
|
||||
|
@ -282,8 +293,8 @@ static void HEAP_Dump( HEAP *heap )
|
|||
}
|
||||
}
|
||||
DPRINTF( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
|
||||
subheap->size, subheap->commitSize, freeSize, usedSize,
|
||||
arenaSize, (arenaSize * 100) / subheap->size );
|
||||
subheap->size, subheap->commitSize, freeSize, usedSize,
|
||||
arenaSize, (arenaSize * 100) / subheap->size );
|
||||
subheap = subheap->next;
|
||||
}
|
||||
}
|
||||
|
@ -457,7 +468,7 @@ static __inline BOOL HEAP_Commit( SUBHEAP *subheap, ARENA_INUSE *pArena, SIZE_T
|
|||
else
|
||||
{
|
||||
Status = ZwAllocateVirtualMemory( NtCurrentProcess(), &ptr, 0,
|
||||
&size, MEM_COMMIT, PAGE_READWRITE );
|
||||
&size, MEM_COMMIT, get_protection_type(subheap->heap->flags) );
|
||||
}
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
|
@ -649,7 +660,7 @@ static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
|
|||
NTSTATUS Status;
|
||||
|
||||
if (!address && ZwAllocateVirtualMemory( NtCurrentProcess(), &address, 0,
|
||||
&commitSize, MEM_COMMIT, PAGE_READWRITE ))
|
||||
&commitSize, MEM_COMMIT, get_protection_type(flags) ))
|
||||
{
|
||||
WARN("Could not commit %08lx bytes for sub-heap %p\n", commitSize, address );
|
||||
return FALSE;
|
||||
|
@ -733,7 +744,7 @@ static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
|
|||
0,
|
||||
&commitSize,
|
||||
MEM_COMMIT,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
get_protection_type(flags));
|
||||
}
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
|
@ -766,13 +777,14 @@ static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, void *base, DWORD flags,
|
|||
totalSize = (totalSize + 0xffff) & 0xffff0000;
|
||||
commitSize = (commitSize + 0xffff) & 0xffff0000;
|
||||
if (!commitSize) commitSize = 0x10000;
|
||||
totalSize = min( totalSize, 0xffff0000 ); /* don't allow a heap larger than 4Gb */
|
||||
if (totalSize < commitSize) totalSize = commitSize;
|
||||
|
||||
if (!address)
|
||||
{
|
||||
/* allocate the memory block */
|
||||
if (ZwAllocateVirtualMemory( NtCurrentProcess(), &address, 0, &totalSize,
|
||||
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ))
|
||||
MEM_RESERVE | MEM_COMMIT, get_protection_type(flags) ))
|
||||
{
|
||||
WARN("Could not allocate %08lx bytes\n", totalSize );
|
||||
return NULL;
|
||||
|
@ -804,6 +816,7 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size,
|
|||
{
|
||||
SUBHEAP *subheap;
|
||||
struct list *ptr;
|
||||
SIZE_T total_size;
|
||||
FREE_LIST_ENTRY *pEntry = heap->freeList + get_freelist_index( size + sizeof(ARENA_INUSE) );
|
||||
|
||||
/* Find a suitable free list, and in it find a block large enough */
|
||||
|
@ -835,9 +848,11 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size,
|
|||
* So just one heap struct, one first free arena which will eventually
|
||||
* get used, and a second free arena that might get assigned all remaining
|
||||
* free space in HEAP_ShrinkBlock() */
|
||||
size += ROUND_SIZE(sizeof(SUBHEAP)) + sizeof(ARENA_INUSE) + sizeof(ARENA_FREE);
|
||||
if (!(subheap = HEAP_CreateSubHeap( heap, NULL, heap->flags, size,
|
||||
max( HEAP_DEF_SIZE, size ), NULL )))
|
||||
total_size = size + ROUND_SIZE(sizeof(SUBHEAP)) + sizeof(ARENA_INUSE) + sizeof(ARENA_FREE);
|
||||
if (total_size < size) return NULL; /* overflow */
|
||||
|
||||
if (!(subheap = HEAP_CreateSubHeap( heap, NULL, heap->flags, total_size,
|
||||
max( HEAP_DEF_SIZE, total_size ), NULL )))
|
||||
return NULL;
|
||||
|
||||
TRACE("created new sub-heap %p of %08lx bytes for heap %p\n",
|
||||
|
@ -874,7 +889,7 @@ static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
|
|||
char *heapEnd = (char *)subheap + subheap->size;
|
||||
|
||||
/* Check for unaligned pointers */
|
||||
if ( (ULONG_PTR)pArena % ALIGNMENT != 0 )
|
||||
if ( (ULONG_PTR)pArena % ALIGNMENT != ARENA_OFFSET )
|
||||
{
|
||||
ERR("Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena );
|
||||
return FALSE;
|
||||
|
@ -964,7 +979,7 @@ static BOOL HEAP_ValidateInUseArena( const SUBHEAP *subheap, const ARENA_INUSE *
|
|||
const char *heapEnd = (const char *)subheap + subheap->size;
|
||||
|
||||
/* Check for unaligned pointers */
|
||||
if ( (ULONG_PTR)pArena % ALIGNMENT != 0 )
|
||||
if ( (ULONG_PTR)pArena % ALIGNMENT != ARENA_OFFSET )
|
||||
{
|
||||
if ( quiet == NOISY )
|
||||
{
|
||||
|
@ -1169,6 +1184,7 @@ RtlCreateHeap(ULONG flags,
|
|||
{
|
||||
processHeap = subheap->heap; /* assume the first heap we create is the process main heap */
|
||||
list_init( &processHeap->entry );
|
||||
assert( (ULONG_PTR)processHeap->freeList % ALIGNMENT == ARENA_OFFSET );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1252,13 +1268,16 @@ RtlAllocateHeap(HANDLE heap, /* [in] Handle of private heap block */
|
|||
//flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
|
||||
flags |= heapPtr->flags;
|
||||
rounded_size = ROUND_SIZE(size);
|
||||
if (rounded_size < size) /* overflow */
|
||||
{
|
||||
if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rounded_size < HEAP_MIN_DATA_SIZE) rounded_size = HEAP_MIN_DATA_SIZE;
|
||||
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterHeapLock( &heapPtr->critSection );
|
||||
/* Locate a suitable free block */
|
||||
|
||||
/* Locate a suitable free block */
|
||||
|
||||
if (!(pArena = HEAP_FindFreeBlock( heapPtr, rounded_size, &subheap )))
|
||||
{
|
||||
TRACE("(%p,%08lx,%08lx): returning NULL\n",
|
||||
|
@ -1288,7 +1307,10 @@ RtlAllocateHeap(HANDLE heap, /* [in] Handle of private heap block */
|
|||
pInUse->unused_bytes = (pInUse->size & ARENA_SIZE_MASK) - size;
|
||||
|
||||
if (flags & HEAP_ZERO_MEMORY)
|
||||
clear_block( pInUse + 1, pInUse->size & ARENA_SIZE_MASK );
|
||||
{
|
||||
clear_block( pInUse + 1, size );
|
||||
mark_block_uninitialized( (char *)(pInUse + 1) + size, pInUse->unused_bytes );
|
||||
}
|
||||
else
|
||||
mark_block_uninitialized( pInUse + 1, pInUse->size & ARENA_SIZE_MASK );
|
||||
|
||||
|
@ -1339,16 +1361,26 @@ BOOLEAN NTAPI RtlFreeHeap(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* Turn the block into a free block */
|
||||
|
||||
/* Some sanity checks */
|
||||
pInUse = (ARENA_INUSE *)ptr - 1;
|
||||
subheap = HEAP_FindSubHeap( heapPtr, pInUse );
|
||||
if ((char *)pInUse < (char *)subheap + subheap->headerSize) goto error;
|
||||
if (!HEAP_ValidateInUseArena( subheap, pInUse, QUIET )) goto error;
|
||||
|
||||
/* Turn the block into a free block */
|
||||
|
||||
HEAP_MakeInUseBlockFree( subheap, pInUse );
|
||||
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveHeapLock( &heapPtr->critSection );
|
||||
|
||||
TRACE("(%p,%08lx,%p): returning TRUE\n", heap, flags, ptr );
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveHeapLock( &heapPtr->critSection );
|
||||
RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_INVALID_PARAMETER );
|
||||
TRACE("(%p,%08x,%p): returning FALSE\n", heap, flags, ptr );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1376,7 +1408,7 @@ PVOID NTAPI RtlReAllocateHeap(
|
|||
ARENA_INUSE *pArena;
|
||||
HEAP *heapPtr;
|
||||
SUBHEAP *subheap;
|
||||
SIZE_T oldSize, rounded_size;
|
||||
SIZE_T oldBlockSize, oldActualSize, rounded_size;
|
||||
|
||||
if (!ptr) return NULL;
|
||||
if (!(heapPtr = HEAP_GetPtr( heap )))
|
||||
|
@ -1390,55 +1422,44 @@ PVOID NTAPI RtlReAllocateHeap(
|
|||
//Flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
|
||||
// HEAP_REALLOC_IN_PLACE_ONLY;
|
||||
flags |= heapPtr->flags;
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterHeapLock( &heapPtr->critSection );
|
||||
|
||||
rounded_size = ROUND_SIZE(size);
|
||||
if (rounded_size < size) goto oom; /* overflow */
|
||||
if (rounded_size < HEAP_MIN_DATA_SIZE) rounded_size = HEAP_MIN_DATA_SIZE;
|
||||
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterHeapLock( &heapPtr->critSection );
|
||||
if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
|
||||
{
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveHeapLock( &heapPtr->critSection );
|
||||
RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_INVALID_PARAMETER );
|
||||
TRACE("(%p,%08lx,%p,%08lx): returning NULL\n", heap, flags, ptr, size );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pArena = (ARENA_INUSE *)ptr - 1;
|
||||
subheap = HEAP_FindSubHeap( heapPtr, pArena );
|
||||
oldSize = (pArena->size & ARENA_SIZE_MASK);
|
||||
if (rounded_size > oldSize)
|
||||
if(!(subheap = HEAP_FindSubHeap( heapPtr, pArena ))) goto done;
|
||||
if ((char *)pArena < (char *)subheap + subheap->headerSize) goto error;
|
||||
if (!HEAP_ValidateInUseArena( subheap, pArena, QUIET )) goto error;
|
||||
|
||||
oldBlockSize = (pArena->size & ARENA_SIZE_MASK);
|
||||
oldActualSize = (pArena->size & ARENA_SIZE_MASK) - pArena->unused_bytes;
|
||||
|
||||
if (rounded_size > oldBlockSize)
|
||||
{
|
||||
char *pNext = (char *)(pArena + 1) + oldSize;
|
||||
char *pNext = (char *)(pArena + 1) + oldBlockSize;
|
||||
if ((pNext < (char *)subheap + subheap->size) &&
|
||||
(*(DWORD *)pNext & ARENA_FLAG_FREE) &&
|
||||
(oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= rounded_size))
|
||||
(oldBlockSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= 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);
|
||||
if (!HEAP_Commit( subheap, pArena, rounded_size ))
|
||||
{
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveHeapLock( &heapPtr->critSection );
|
||||
if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
|
||||
RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_NO_MEMORY );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!HEAP_Commit( subheap, pArena, rounded_size )) goto oom;
|
||||
|
||||
HEAP_ShrinkBlock( subheap, pArena, rounded_size );
|
||||
mark_block_initialized( pArena + 1, oldActualSize );
|
||||
}
|
||||
else /* Do it the hard way */
|
||||
{
|
||||
ARENA_FREE *pNew;
|
||||
ARENA_INUSE *pInUse;
|
||||
SUBHEAP *newsubheap;
|
||||
|
||||
if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) ||
|
||||
!(pNew = HEAP_FindFreeBlock( heapPtr, rounded_size, &newsubheap )))
|
||||
{
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveHeapLock( &heapPtr->critSection );
|
||||
if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
|
||||
RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_NO_MEMORY );
|
||||
return NULL;
|
||||
}
|
||||
goto oom;
|
||||
|
||||
/* Build the in-use arena */
|
||||
|
||||
|
@ -1448,8 +1469,9 @@ PVOID NTAPI RtlReAllocateHeap(
|
|||
+ sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
|
||||
pInUse->magic = ARENA_INUSE_MAGIC;
|
||||
HEAP_ShrinkBlock( newsubheap, pInUse, rounded_size );
|
||||
mark_block_initialized( pInUse + 1, oldSize );
|
||||
memcpy( pInUse + 1, pArena + 1, oldSize );
|
||||
|
||||
mark_block_initialized( pInUse + 1, oldActualSize );
|
||||
memcpy( pInUse + 1, pArena + 1, oldActualSize );
|
||||
|
||||
/* Free the previous block */
|
||||
|
||||
|
@ -1458,28 +1480,47 @@ PVOID NTAPI RtlReAllocateHeap(
|
|||
pArena = pInUse;
|
||||
}
|
||||
}
|
||||
else HEAP_ShrinkBlock( subheap, pArena, rounded_size ); /* Shrink the block */
|
||||
else
|
||||
{
|
||||
HEAP_ShrinkBlock( subheap, pArena, rounded_size ); /* Shrink the block */
|
||||
mark_block_initialized( pArena + 1, size );
|
||||
}
|
||||
|
||||
pArena->unused_bytes = (pArena->size & ARENA_SIZE_MASK) - size;
|
||||
|
||||
/* Clear the extra bytes if needed */
|
||||
|
||||
if (rounded_size > oldSize)
|
||||
if (size > oldActualSize)
|
||||
{
|
||||
if (flags & HEAP_ZERO_MEMORY)
|
||||
clear_block( (char *)(pArena + 1) + oldSize,
|
||||
(pArena->size & ARENA_SIZE_MASK) - oldSize );
|
||||
{
|
||||
clear_block( (char *)(pArena + 1) + oldActualSize, size - oldActualSize );
|
||||
mark_block_uninitialized( (char *)(pArena + 1) + size,
|
||||
(pArena->size & ARENA_SIZE_MASK) - oldActualSize );
|
||||
}
|
||||
else
|
||||
mark_block_uninitialized( (char *)(pArena + 1) + oldSize,
|
||||
(pArena->size & ARENA_SIZE_MASK) - oldSize );
|
||||
mark_block_uninitialized( (char *)(pArena + 1) + oldActualSize,
|
||||
(pArena->size & ARENA_SIZE_MASK) - oldActualSize );
|
||||
}
|
||||
|
||||
/* Return the new arena */
|
||||
|
||||
done:
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveHeapLock( &heapPtr->critSection );
|
||||
|
||||
TRACE("(%p,%08lx,%p,%08lx): returning %p\n", heap, flags, ptr, size, pArena + 1 );
|
||||
return (LPVOID)(pArena + 1);
|
||||
|
||||
oom:
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveHeapLock( &heapPtr->critSection );
|
||||
if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
|
||||
RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_NO_MEMORY );
|
||||
TRACE("(%p,%08x,%p,%08lx): returning oom\n", heap, flags, ptr, size );
|
||||
return NULL;
|
||||
|
||||
error:
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveHeapLock( &heapPtr->critSection );
|
||||
RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_INVALID_PARAMETER );
|
||||
TRACE("(%p,%08x,%p,%08lx): returning error\n", heap, flags, ptr, size );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1583,7 +1624,7 @@ RtlSizeHeap(
|
|||
}
|
||||
else
|
||||
{
|
||||
ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1;
|
||||
const ARENA_INUSE *pArena = (const ARENA_INUSE *)ptr - 1;
|
||||
ret = (pArena->size & ARENA_SIZE_MASK) - pArena->unused_bytes;
|
||||
}
|
||||
if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveHeapLock( &heapPtr->critSection );
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue