#define NDEBUG
#include <debug.h>
-HEAP_LOCK RtlpProcessHeapsListLock;
+RTL_CRITICAL_SECTION RtlpProcessHeapsListLock;
/* Bitmaps stuff */
HEAP_TAIL_FILL
};
-
-ULONG NTAPI
-RtlCompareMemoryUlong(PVOID Source, ULONG Length, ULONG Value);
-
/* FUNCTIONS *****************************************************************/
-VOID NTAPI
-RtlpInitializeHeap(PHEAP Heap,
- PULONG HeaderSize,
- ULONG Flags,
- BOOLEAN AllocateLock,
- PVOID Lock)
+NTSTATUS NTAPI
+RtlpInitializeHeap(OUT PHEAP Heap,
+ IN ULONG Flags,
+ IN PHEAP_LOCK Lock OPTIONAL,
+ IN PRTL_HEAP_PARAMETERS Parameters)
{
- PVOID NextHeapBase = Heap + 1;
- PHEAP_UCR_DESCRIPTOR UcrDescriptor;
ULONG NumUCRs = 8;
- ULONG i;
+ ULONG Index;
+ SIZE_T HeaderSize;
NTSTATUS Status;
+ PHEAP_UCR_DESCRIPTOR UcrDescriptor;
- /* Add UCRs size */
- *HeaderSize += NumUCRs * sizeof(*UcrDescriptor);
+ /* Preconditions */
+ ASSERT(Heap != NULL);
+ ASSERT(Parameters != NULL);
+ ASSERT(!(Flags & HEAP_LOCK_USER_ALLOCATED));
+ ASSERT(!(Flags & HEAP_NO_SERIALIZE) || (Lock == NULL)); /* HEAP_NO_SERIALIZE => no lock */
- /* Prepare a list of UCRs */
- InitializeListHead(&Heap->UCRList);
- InitializeListHead(&Heap->UCRSegments);
- UcrDescriptor = NextHeapBase;
+ /* Start out with the size of a plain Heap header */
+ HeaderSize = ROUND_UP(sizeof(HEAP), sizeof(HEAP_ENTRY));
- for (i=0; i<NumUCRs; i++, UcrDescriptor++)
+ /* Check if space needs to be added for the Heap Lock */
+ if (!(Flags & HEAP_NO_SERIALIZE))
{
- InsertTailList(&Heap->UCRList, &UcrDescriptor->ListEntry);
+ if (Lock != NULL)
+ /* The user manages the Heap Lock */
+ Flags |= HEAP_LOCK_USER_ALLOCATED;
+ else
+ if (RtlpGetMode() == UserMode)
+ {
+ /* In user mode, the Heap Lock trails the Heap header */
+ Lock = (PHEAP_LOCK) ((ULONG_PTR) (Heap) + HeaderSize);
+ HeaderSize += ROUND_UP(sizeof(HEAP_LOCK), sizeof(HEAP_ENTRY));
+ }
}
- NextHeapBase = UcrDescriptor;
- // TODO: Add tagging
+ /* Add space for the initial Heap UnCommitted Range Descriptor list */
+ UcrDescriptor = (PHEAP_UCR_DESCRIPTOR) ((ULONG_PTR) (Heap) + HeaderSize);
+ HeaderSize += ROUND_UP(NumUCRs * sizeof(HEAP_UCR_DESCRIPTOR), sizeof(HEAP_ENTRY));
- /* Round up header size again */
- *HeaderSize = ROUND_UP(*HeaderSize, HEAP_ENTRY_SIZE);
+ /* Sanity check */
+ ASSERT(HeaderSize <= PAGE_SIZE);
- ASSERT(*HeaderSize <= PAGE_SIZE);
-
- /* Initialize heap's header */
- Heap->Entry.Size = (*HeaderSize) >> HEAP_ENTRY_SHIFT;
+ /* Initialise the Heap Entry header containing the Heap header */
+ Heap->Entry.Size = (USHORT)(HeaderSize >> HEAP_ENTRY_SHIFT);
Heap->Entry.Flags = HEAP_ENTRY_BUSY;
+ Heap->Entry.SmallTagIndex = LOBYTE(Heap->Entry.Size) ^ HIBYTE(Heap->Entry.Size) ^ Heap->Entry.Flags;
+ Heap->Entry.PreviousSize = 0;
+ Heap->Entry.SegmentOffset = 0;
+ Heap->Entry.UnusedBytes = 0;
+ /* Initialise the Heap header */
Heap->Signature = HEAP_SIGNATURE;
Heap->Flags = Flags;
Heap->ForceFlags = (Flags & (HEAP_NO_SERIALIZE |
HEAP_TAIL_CHECKING_ENABLED |
HEAP_CREATE_ALIGN_16 |
HEAP_FREE_CHECKING_ENABLED));
+
+ /* Initialise the Heap parameters */
+ Heap->VirtualMemoryThreshold = ROUND_UP(Parameters->VirtualMemoryThreshold, sizeof(HEAP_ENTRY)) >> HEAP_ENTRY_SHIFT;
+ Heap->SegmentReserve = Parameters->SegmentReserve;
+ Heap->SegmentCommit = Parameters->SegmentCommit;
+ Heap->DeCommitFreeBlockThreshold = Parameters->DeCommitFreeBlockThreshold >> HEAP_ENTRY_SHIFT;
+ Heap->DeCommitTotalFreeThreshold = Parameters->DeCommitTotalFreeThreshold >> HEAP_ENTRY_SHIFT;
+ Heap->MaximumAllocationSize = Parameters->MaximumAllocationSize;
+ Heap->CommitRoutine = Parameters->CommitRoutine;
+
+ /* Initialise the Heap validation info */
Heap->HeaderValidateCopy = NULL;
- Heap->HeaderValidateLength = ((PCHAR)NextHeapBase - (PCHAR)Heap);
+ Heap->HeaderValidateLength = (USHORT)HeaderSize;
- /* Initialize free lists */
- for (i=0; i<HEAP_FREELISTS; i++)
+ /* Initialise the Heap Lock */
+ if (!(Flags & HEAP_NO_SERIALIZE) && !(Flags & HEAP_LOCK_USER_ALLOCATED))
{
- InitializeListHead(&Heap->FreeLists[i]);
+ Status = RtlInitializeHeapLock(&Lock);
+ if (!NT_SUCCESS(Status))
+ return Status;
}
+ Heap->LockVariable = Lock;
- /* Initialize "big" allocations list */
- InitializeListHead(&Heap->VirtualAllocdBlocks);
-
- /* Initialize lock */
- if (AllocateLock)
+ /* Initialise the Heap alignment info */
+ if (Flags & HEAP_CREATE_ALIGN_16)
{
- Lock = NextHeapBase;
- Status = RtlInitializeHeapLock((PHEAP_LOCK)Lock);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Initializing the lock failed!\n");
- return /*NULL*/; // FIXME!
- }
+ Heap->AlignMask = (ULONG) ~15;
+ Heap->AlignRound = 15 + sizeof(HEAP_ENTRY);
+ }
+ else
+ {
+ Heap->AlignMask = (ULONG) ~(sizeof(HEAP_ENTRY) - 1);
+ Heap->AlignRound = 2 * sizeof(HEAP_ENTRY) - 1;
}
- /* Set the lock variable */
- Heap->LockVariable = Lock;
+ if (Flags & HEAP_TAIL_CHECKING_ENABLED)
+ Heap->AlignRound += sizeof(HEAP_ENTRY);
+
+ /* Initialise the Heap Segment list */
+ for (Index = 0; Index < HEAP_SEGMENTS; ++Index)
+ Heap->Segments[Index] = NULL;
+
+ /* Initialise the Heap Free Heap Entry lists */
+ for (Index = 0; Index < HEAP_FREELISTS; ++Index)
+ InitializeListHead(&Heap->FreeLists[Index]);
+
+ /* Initialise the Heap Virtual Allocated Blocks list */
+ InitializeListHead(&Heap->VirtualAllocdBlocks);
+
+ /* Initialise the Heap UnCommitted Region lists */
+ InitializeListHead(&Heap->UCRSegments);
+ InitializeListHead(&Heap->UCRList);
+
+ /* Register the initial Heap UnCommitted Region Descriptors */
+ for (Index = 0; Index < NumUCRs; ++Index)
+ InsertTailList(&Heap->UCRList, &UcrDescriptor[Index].ListEntry);
+
+ return STATUS_SUCCESS;
}
VOID FORCEINLINE
}
else
{
- Size = BlockSize;
+ Size = (USHORT)BlockSize;
FreeEntry->Flags = Flags;
}
{
/* Release reserved memory */
ZwFreeVirtualMemory(NtCurrentProcess(),
- (PVOID *)&UcrDescriptor,
+ (PVOID *)&UcrSegment,
&ReserveSize,
MEM_RELEASE);
return NULL;
}
/* There is a whole bunch of new UCR descriptors. Put them into the unused list */
- while ((PCHAR)UcrDescriptor < ((PCHAR)UcrSegment + UcrSegment->CommittedSize))
+ while ((PCHAR)(UcrDescriptor + 1) <= (PCHAR)UcrSegment + UcrSegment->CommittedSize)
{
InsertTailList(&Heap->UCRList, &UcrDescriptor->ListEntry);
UcrDescriptor++;
/* Go through the list of UCR descriptors, they are sorted from lowest address
to the highest */
Current = Segment->UCRSegmentList.Flink;
- while(Current != &Segment->UCRSegmentList)
+ while (Current != &Segment->UCRSegmentList)
{
UcrDescriptor = CONTAINING_RECORD(Current, HEAP_UCR_DESCRIPTOR, SegmentEntry);
return;
}
- /* We found the block after which the new one should go */
+ /* We found the block before which the new one should go */
break;
}
else if (((ULONG_PTR)UcrDescriptor->Address + UcrDescriptor->Size) == Address)
UcrDescriptor->Address = (PVOID)Address;
UcrDescriptor->Size = Size;
- /* "Current" is the descriptor after which our one should go */
+ /* "Current" is the descriptor before which our one should go */
InsertTailList(Current, &UcrDescriptor->SegmentEntry);
DPRINT("Added segment UCR with base %p, size 0x%x\n", Address, Size);
/* Go through UCRs in a segment */
Current = Segment->UCRSegmentList.Flink;
- while(Current != &Segment->UCRSegmentList)
+ while (Current != &Segment->UCRSegmentList)
{
UcrDescriptor = CONTAINING_RECORD(Current, HEAP_UCR_DESCRIPTOR, SegmentEntry);
}
/* Update tracking numbers */
- Segment->NumberOfUnCommittedPages -= *Size / PAGE_SIZE;
+ Segment->NumberOfUnCommittedPages -= (ULONG)(*Size / PAGE_SIZE);
/* Calculate first and last entries */
FirstEntry = (PHEAP_ENTRY)Address;
while (!(LastEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
{
+ ASSERT(LastEntry->Size != 0);
LastEntry += LastEntry->Size;
}
ASSERT((LastEntry + LastEntry->Size) == FirstEntry);
DPRINT("Updating UcrDescriptor %p, new Address %p, size %d\n",
UcrDescriptor, UcrDescriptor->Address, UcrDescriptor->Size);
-
- /* Set various first entry fields*/
+
+ /* Set various first entry fields */
FirstEntry->SegmentOffset = LastEntry->SegmentOffset;
- FirstEntry->Size = *Size >> HEAP_ENTRY_SHIFT;
+ FirstEntry->Size = (USHORT)(*Size >> HEAP_ENTRY_SHIFT);
FirstEntry->PreviousSize = LastEntry->Size;
/* Check if anything left in this UCR */
if (UcrDescriptor->Size == 0)
{
/* It's fully exhausted */
-
- /* Check if this is the end of the segment */
+
+ /* Check if this is the end of the segment */
if(UcrDescriptor->Address == Segment->LastValidEntry)
{
FirstEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
{
FirstEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
}
-
+
/* We're done */
return (PHEAP_FREE_ENTRY)FirstEntry;
}
PHEAP_ENTRY PrecedingInUseEntry = NULL, NextInUseEntry = NULL;
PHEAP_FREE_ENTRY NextFreeEntry;
PHEAP_UCR_DESCRIPTOR UcrDescriptor;
- ULONG PrecedingSize, NextSize, DecommitSize;
+ SIZE_T PrecedingSize, NextSize, DecommitSize;
ULONG_PTR DecommitBase;
NTSTATUS Status;
/* Insert uncommitted pages */
RtlpInsertUnCommittedPages(Segment, DecommitBase, DecommitSize);
- Segment->NumberOfUnCommittedPages += (DecommitSize / PAGE_SIZE);
+ Segment->NumberOfUnCommittedPages += (ULONG)(DecommitSize / PAGE_SIZE);
if (PrecedingSize)
{
/* Adjust size of this free entry and insert it */
FreeEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
- FreeEntry->Size = PrecedingSize;
+ FreeEntry->Size = (USHORT)PrecedingSize;
Heap->TotalFreeSize += PrecedingSize;
/* Insert it into the free list */
NextFreeEntry->Flags = 0;
NextFreeEntry->PreviousSize = 0;
NextFreeEntry->SegmentOffset = Segment->Entry.SegmentOffset;
- NextFreeEntry->Size = NextSize;
+ NextFreeEntry->Size = (USHORT)NextSize;
- ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)NextFreeEntry + NextSize))->PreviousSize = NextSize;
+ ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)NextFreeEntry + NextSize))->PreviousSize = (USHORT)NextSize;
Heap->TotalFreeSize += NextSize;
RtlpInsertFreeBlockHelper(Heap, NextFreeEntry, NextSize, FALSE);
}
}
-BOOLEAN NTAPI
-RtlpInitializeHeapSegment(PHEAP Heap,
- PHEAP_SEGMENT Segment,
- UCHAR SegmentIndex,
- ULONG Flags,
- PVOID BaseAddress,
- PVOID UncommittedBase,
- PVOID LimitAddress)
+NTSTATUS
+NTAPI
+RtlpInitializeHeapSegment(IN OUT PHEAP Heap,
+ OUT PHEAP_SEGMENT Segment,
+ IN UCHAR SegmentIndex,
+ IN ULONG SegmentFlags,
+ IN SIZE_T SegmentReserve,
+ IN SIZE_T SegmentCommit)
{
- ULONG Pages, CommitSize;
PHEAP_ENTRY HeapEntry;
- USHORT PreviousSize = 0, NewSize;
- NTSTATUS Status;
-
- Pages = ((PCHAR)LimitAddress - (PCHAR)BaseAddress) / PAGE_SIZE;
-
- HeapEntry = (PHEAP_ENTRY)ROUND_UP(Segment + 1, HEAP_ENTRY_SIZE);
- DPRINT("RtlpInitializeHeapSegment(%p %p %x %x %p %p %p)\n", Heap, Segment, SegmentIndex, Flags, BaseAddress, UncommittedBase, LimitAddress);
- DPRINT("Pages %x, HeapEntry %p, sizeof(HEAP_SEGMENT) %x\n", Pages, HeapEntry, sizeof(HEAP_SEGMENT));
+ /* Preconditions */
+ ASSERT(Heap != NULL);
+ ASSERT(Segment != NULL);
+ ASSERT(SegmentCommit >= PAGE_SIZE);
+ ASSERT(ROUND_DOWN(SegmentCommit, PAGE_SIZE) == SegmentCommit);
+ ASSERT(SegmentReserve >= SegmentCommit);
+ ASSERT(ROUND_DOWN(SegmentReserve, PAGE_SIZE) == SegmentReserve);
- /* Check if it's the first segment and remember its size */
- if (Heap == BaseAddress)
- PreviousSize = Heap->Entry.Size;
+ DPRINT("RtlpInitializeHeapSegment(%p %p %x %x %lx %lx)\n", Heap, Segment, SegmentIndex, SegmentFlags, SegmentReserve, SegmentCommit);
- NewSize = ((PCHAR)HeapEntry - (PCHAR)Segment) >> HEAP_ENTRY_SHIFT;
-
- if ((PVOID)(HeapEntry + 1) >= UncommittedBase)
+ /* Initialise the Heap Entry header if this is not the first Heap Segment */
+ if ((PHEAP_SEGMENT) (Heap) != Segment)
{
- /* Check if it goes beyond the limit */
- if ((PVOID)(HeapEntry + 1) >= LimitAddress)
- return FALSE;
-
- /* Need to commit memory */
- CommitSize = (PCHAR)(HeapEntry + 1) - (PCHAR)UncommittedBase;
- Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
- (PVOID)&UncommittedBase,
- 0,
- &CommitSize,
- MEM_COMMIT,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Committing page failed with status 0x%08X\n", Status);
- return FALSE;
- }
-
- DPRINT("Committed %d bytes at base %p\n", CommitSize, UncommittedBase);
-
- /* Calcule the new uncommitted base */
- UncommittedBase = (PVOID)((PCHAR)UncommittedBase + CommitSize);
+ Segment->Entry.Size = ROUND_UP(sizeof(HEAP_SEGMENT), sizeof(HEAP_ENTRY)) >> HEAP_ENTRY_SHIFT;
+ Segment->Entry.Flags = HEAP_ENTRY_BUSY;
+ Segment->Entry.SmallTagIndex = LOBYTE(Segment->Entry.Size) ^ HIBYTE(Segment->Entry.Size) ^ Segment->Entry.Flags;
+ Segment->Entry.PreviousSize = 0;
+ Segment->Entry.SegmentOffset = SegmentIndex;
+ Segment->Entry.UnusedBytes = 0;
}
- /* Initialize the segment entry */
- Segment->Entry.PreviousSize = PreviousSize;
- Segment->Entry.Size = NewSize;
- Segment->Entry.Flags = HEAP_ENTRY_BUSY;
- Segment->Entry.SegmentOffset = SegmentIndex;
+ /* Sanity check */
+ ASSERT((Segment->Entry.Size << HEAP_ENTRY_SHIFT) <= PAGE_SIZE);
- /* Initialize the segment itself */
+ /* Initialise the Heap Segment header */
Segment->SegmentSignature = HEAP_SEGMENT_SIGNATURE;
+ Segment->SegmentFlags = SegmentFlags;
Segment->Heap = Heap;
- Segment->BaseAddress = BaseAddress;
- Segment->FirstEntry = HeapEntry;
- Segment->LastValidEntry = (PHEAP_ENTRY)((PCHAR)BaseAddress + Pages * PAGE_SIZE);
- Segment->NumberOfPages = Pages;
- Segment->NumberOfUnCommittedPages = ((PCHAR)LimitAddress - (PCHAR)UncommittedBase) / PAGE_SIZE;
- InitializeListHead(&Segment->UCRSegmentList);
+ Heap->Segments[SegmentIndex] = Segment;
+
+ /* Initialise the Heap Segment location information */
+ Segment->BaseAddress = Segment;
+ Segment->NumberOfPages = (ULONG)(SegmentReserve >> PAGE_SHIFT);
+
+ /* Initialise the Heap Entries contained within the Heap Segment */
+ Segment->FirstEntry = &Segment->Entry + Segment->Entry.Size;
+ Segment->LastValidEntry = (PHEAP_ENTRY)((ULONG_PTR)Segment + SegmentReserve);
- /* Insert uncommitted pages into UCR (uncommitted ranges) list */
- if (Segment->NumberOfUnCommittedPages)
+ if (((SIZE_T)Segment->Entry.Size << HEAP_ENTRY_SHIFT) < SegmentCommit)
{
- RtlpInsertUnCommittedPages(Segment, (ULONG_PTR)UncommittedBase, Segment->NumberOfUnCommittedPages * PAGE_SIZE);
- }
+ HeapEntry = Segment->FirstEntry;
- /* Set the segment index pointer */
- Heap->Segments[SegmentIndex] = Segment;
+ /* Prepare a Free Heap Entry header */
+ HeapEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
+ HeapEntry->PreviousSize = Segment->Entry.Size;
+ HeapEntry->SegmentOffset = SegmentIndex;
- /* Prepare a free heap entry */
- HeapEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
- HeapEntry->PreviousSize = Segment->Entry.Size;
- HeapEntry->SegmentOffset = SegmentIndex;
+ /* Register the Free Heap Entry */
+ RtlpInsertFreeBlock(Heap, (PHEAP_FREE_ENTRY) HeapEntry, (SegmentCommit >> HEAP_ENTRY_SHIFT) - Segment->Entry.Size);
+ }
- /* Insert it */
- RtlpInsertFreeBlock(Heap, (PHEAP_FREE_ENTRY)HeapEntry, (PHEAP_ENTRY)UncommittedBase - HeapEntry);
+ /* Initialise the Heap Segment UnCommitted Range information */
+ Segment->NumberOfUnCommittedPages = (ULONG)((SegmentReserve - SegmentCommit) >> PAGE_SHIFT);
+ Segment->NumberOfUnCommittedRanges = 0;
+ InitializeListHead(&Segment->UCRSegmentList);
- return TRUE;
+ /* Register the UnCommitted Range of the Heap Segment */
+ if (Segment->NumberOfUnCommittedPages != 0)
+ RtlpInsertUnCommittedPages(Segment, (ULONG_PTR) (Segment) + SegmentCommit, SegmentReserve - SegmentCommit);
+
+ return STATUS_SUCCESS;
}
VOID NTAPI
Peb = RtlGetCurrentPeb();
/* Acquire the lock */
- RtlEnterHeapLock(&RtlpProcessHeapsListLock);
+ RtlEnterCriticalSection(&RtlpProcessHeapsListLock);
//_SEH2_TRY {
/* Check if max number of heaps reached */
/* Add the heap to the process heaps */
Peb->ProcessHeaps[Peb->NumberOfHeaps] = Heap;
Peb->NumberOfHeaps++;
- Heap->ProcessHeapsListIndex = Peb->NumberOfHeaps;
+ Heap->ProcessHeapsListIndex = (USHORT)Peb->NumberOfHeaps;
// } _SEH2_FINALLY {
/* Release the lock */
- RtlLeaveHeapLock(&RtlpProcessHeapsListLock);
+ RtlLeaveCriticalSection(&RtlpProcessHeapsListLock);
// } _SEH2_END
}
Peb = RtlGetCurrentPeb();
/* Acquire the lock */
- RtlEnterHeapLock(&RtlpProcessHeapsListLock);
+ RtlEnterCriticalSection(&RtlpProcessHeapsListLock);
/* Check if we don't need anything to do */
if ((Heap->ProcessHeapsListIndex == 0) ||
(Peb->NumberOfHeaps == 0))
{
/* Release the lock */
- RtlLeaveHeapLock(&RtlpProcessHeapsListLock);
+ RtlLeaveCriticalSection(&RtlpProcessHeapsListLock);
return;
}
Heap->ProcessHeapsListIndex = 0;
/* Release the lock */
- RtlLeaveHeapLock(&RtlpProcessHeapsListLock);
+ RtlLeaveCriticalSection(&RtlpProcessHeapsListLock);
}
PHEAP_FREE_ENTRY NTAPI
FreeEntry = CurrentEntry;
*FreeSize = *FreeSize + CurrentEntry->Size;
Heap->TotalFreeSize -= CurrentEntry->Size;
- FreeEntry->Size = *FreeSize;
+ FreeEntry->Size = (USHORT)(*FreeSize);
/* Also update previous size if needed */
if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
{
- ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = *FreeSize;
+ ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = (USHORT)(*FreeSize);
}
}
/* Update sizes */
*FreeSize = *FreeSize + NextEntry->Size;
Heap->TotalFreeSize -= NextEntry->Size;
- FreeEntry->Size = *FreeSize;
+ FreeEntry->Size = (USHORT)(*FreeSize);
/* Also update previous size if needed */
if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
{
- ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = *FreeSize;
+ ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = (USHORT)(*FreeSize);
}
}
}
DPRINT("RtlpExtendHeap(%p %x)\n", Heap, Size);
/* Calculate amount in pages */
- Pages = (Size + PAGE_SIZE - 1) / PAGE_SIZE;
+ Pages = (ULONG)((Size + PAGE_SIZE - 1) / PAGE_SIZE);
FreeSize = Pages * PAGE_SIZE;
DPRINT("Pages %x, FreeSize %x. Going through segments...\n", Pages, FreeSize);
/* Initialize heap segment if commit was successful */
if (NT_SUCCESS(Status))
- {
- if (!RtlpInitializeHeapSegment(Heap, Segment, EmptyIndex, 0, Segment,
- (PCHAR)Segment + CommitSize, (PCHAR)Segment + ReserveSize))
- {
- Status = STATUS_NO_MEMORY;
- }
- }
+ Status = RtlpInitializeHeapSegment(Heap, Segment, EmptyIndex, 0, ReserveSize, CommitSize);
/* If everything worked - cool */
if (NT_SUCCESS(Status)) return (PHEAP_FREE_ENTRY)Segment->FirstEntry;
ULONG NtGlobalFlags = RtlGetNtGlobalFlags();
ULONG HeapSegmentFlags = 0;
NTSTATUS Status;
- ULONG MaxBlockSize, HeaderSize;
- BOOLEAN AllocateLock = FALSE;
+ ULONG MaxBlockSize;
/* Check for a special heap */
if (RtlpPageHeapEnabled && !Addr && !Lock)
if (RtlpHeapIsSpecial(Flags))
return RtlDebugCreateHeap(Flags, Addr, TotalSize, CommitSize, Lock, Parameters);
- /* Calculate header size */
- HeaderSize = sizeof(HEAP);
- if (!(Flags & HEAP_NO_SERIALIZE))
- {
- if (Lock)
- {
- Flags |= HEAP_LOCK_USER_ALLOCATED;
- }
- else
- {
- HeaderSize += sizeof(HEAP_LOCK);
- AllocateLock = TRUE;
- }
- }
- else if (Lock)
- {
- /* Invalid parameters */
+ /* Without serialization, a lock makes no sense */
+ if ((Flags & HEAP_NO_SERIALIZE) && (Lock != NULL))
return NULL;
- }
/* See if we are already provided with an address for the heap */
if (Addr)
UncommittedAddress = (PCHAR)UncommittedAddress + CommitSize;
}
- DPRINT("Created heap %p, CommitSize %x, ReserveSize %x\n", Heap, CommitSize, TotalSize);
-
/* Initialize the heap */
- RtlpInitializeHeap(Heap, &HeaderSize, Flags, AllocateLock, Lock);
-
- /* Initialize heap's first segment */
- if (!RtlpInitializeHeapSegment(Heap,
- (PHEAP_SEGMENT)((PCHAR)Heap + HeaderSize),
- 0,
- HeapSegmentFlags,
- CommittedAddress,
- UncommittedAddress,
- (PCHAR)CommittedAddress + TotalSize))
- {
- DPRINT1("Failed to initialize heap segment\n");
+ Status = RtlpInitializeHeap(Heap, Flags, Lock, Parameters);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize heap (%x)\n", Status);
return NULL;
}
- /* Set other data */
- Heap->ProcessHeapsListIndex = 0;
- Heap->SegmentCommit = Parameters->SegmentCommit;
- Heap->SegmentReserve = Parameters->SegmentReserve;
- Heap->DeCommitFreeBlockThreshold = Parameters->DeCommitFreeBlockThreshold >> HEAP_ENTRY_SHIFT;
- Heap->DeCommitTotalFreeThreshold = Parameters->DeCommitTotalFreeThreshold >> HEAP_ENTRY_SHIFT;
- Heap->MaximumAllocationSize = Parameters->MaximumAllocationSize;
- Heap->VirtualMemoryThreshold = ROUND_UP(Parameters->VirtualMemoryThreshold, HEAP_ENTRY_SIZE) >> HEAP_ENTRY_SHIFT;
- Heap->CommitRoutine = Parameters->CommitRoutine;
-
- /* Set alignment */
- if (Flags & HEAP_CREATE_ALIGN_16)
- {
- Heap->AlignMask = (ULONG)~15;
- Heap->AlignRound = 15 + sizeof(HEAP_ENTRY);
- }
- else
+ /* Initialize heap's first segment */
+ Status = RtlpInitializeHeapSegment(Heap, (PHEAP_SEGMENT) (Heap), 0, HeapSegmentFlags, TotalSize, CommitSize);
+ if (!NT_SUCCESS(Status))
{
- Heap->AlignMask = (ULONG)~(HEAP_ENTRY_SIZE - 1);
- Heap->AlignRound = HEAP_ENTRY_SIZE - 1 + sizeof(HEAP_ENTRY);
+ DPRINT1("Failed to initialize heap segment (%x)\n", Status);
+ return NULL;
}
- if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
- Heap->AlignRound += HEAP_ENTRY_SIZE;
+ DPRINT("Created heap %p, CommitSize %x, ReserveSize %x\n", Heap, CommitSize, TotalSize);
/* Add heap to process list in case of usermode heap */
if (RtlpGetMode() == UserMode)
// FIXME: What about lookasides?
}
- DPRINT("Heap %p, flags 0x%08x\n", Heap, Heap->Flags);
return Heap;
}
/* Free UCR segments if any were created */
Current = Heap->UCRSegments.Flink;
- while(Current != &Heap->UCRSegments)
+ while (Current != &Heap->UCRSegments)
{
UcrSegment = CONTAINING_RECORD(Current, HEAP_UCR_SEGMENT, ListEntry);
PHEAP_ENTRY NTAPI
RtlpSplitEntry(PHEAP Heap,
+ ULONG Flags,
PHEAP_FREE_ENTRY FreeBlock,
SIZE_T AllocationSize,
SIZE_T Index,
SIZE_T Size)
{
- PHEAP_FREE_ENTRY SplitBlock;
- UCHAR FreeFlags;
+ PHEAP_FREE_ENTRY SplitBlock, SplitBlock2;
+ UCHAR FreeFlags, EntryFlags = HEAP_ENTRY_BUSY;
PHEAP_ENTRY InUseEntry;
SIZE_T FreeSize;
+ /* Add extra flags in case of settable user value feature is requested,
+ or there is a tag (small or normal) or there is a request to
+ capture stack backtraces */
+ if ((Flags & HEAP_EXTRA_FLAGS_MASK) ||
+ Heap->PseudoTagEntries)
+ {
+ /* Add flag which means that the entry will have extra stuff attached */
+ EntryFlags |= HEAP_ENTRY_EXTRA_PRESENT;
+
+ /* NB! AllocationSize is already adjusted by RtlAllocateHeap */
+ }
+
+ /* Add settable user flags, if any */
+ EntryFlags |= (Flags & HEAP_SETTABLE_USER_FLAGS) >> 4;
+
/* Save flags, update total free size */
FreeFlags = FreeBlock->Flags;
Heap->TotalFreeSize -= FreeBlock->Size;
/* Make this block an in-use one */
InUseEntry = (PHEAP_ENTRY)FreeBlock;
- InUseEntry->Flags = HEAP_ENTRY_BUSY;
+ InUseEntry->Flags = EntryFlags;
InUseEntry->SmallTagIndex = 0;
/* Calculate the extra amount */
FreeSize = InUseEntry->Size - Index;
/* Update it's size fields (we don't need their data anymore) */
- InUseEntry->Size = Index;
- InUseEntry->UnusedBytes = AllocationSize - Size;
+ InUseEntry->Size = (USHORT)Index;
+ InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
/* If there is something to split - do the split */
if (FreeSize != 0)
/* Initialize it */
SplitBlock->Flags = FreeFlags;
SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
- SplitBlock->Size = FreeSize;
- SplitBlock->PreviousSize = Index;
-
- /* Coalesce it with the next entry */
- SplitBlock = RtlpCoalesceFreeBlocks(Heap, SplitBlock, &FreeSize, FALSE);
- RtlpInsertFreeBlock(Heap, SplitBlock, FreeSize);
-
- /* Reset the flag */
+ SplitBlock->Size = (USHORT)FreeSize;
+ SplitBlock->PreviousSize = (USHORT)Index;
+
+ /* Check if it's the last entry */
+ if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
+ {
+ /* Insert it to the free list if it's the last entry */
+ RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
+ Heap->TotalFreeSize += FreeSize;
+ }
+ else
+ {
+ /* Not so easy - need to update next's previous size too */
+ SplitBlock2 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize);
+
+ if (SplitBlock2->Flags & HEAP_ENTRY_BUSY)
+ {
+ SplitBlock2->PreviousSize = (USHORT)FreeSize;
+ RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
+ Heap->TotalFreeSize += FreeSize;
+ }
+ else
+ {
+ /* Even more complex - the next entry is free, so we can merge them into one! */
+ SplitBlock->Flags = SplitBlock2->Flags;
+
+ /* Remove that next entry */
+ RtlpRemoveFreeBlock(Heap, SplitBlock2, FALSE, FALSE);
+
+ /* Update sizes */
+ FreeSize += SplitBlock2->Size;
+ Heap->TotalFreeSize -= SplitBlock2->Size;
+
+ if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
+ {
+ /* Insert it back */
+ SplitBlock->Size = (USHORT)FreeSize;
+
+ /* Don't forget to update previous size of the next entry! */
+ if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
+ {
+ ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
+ }
+
+ /* Actually insert it */
+ RtlpInsertFreeBlockHelper(Heap, SplitBlock, (USHORT)FreeSize, FALSE);
+
+ /* Update total size */
+ Heap->TotalFreeSize += FreeSize;
+ }
+ else
+ {
+ /* Resulting block is quite big */
+ RtlpInsertFreeBlock(Heap, SplitBlock, FreeSize);
+ }
+ }
+ }
+
+ /* Reset flags of the free entry */
FreeFlags = 0;
}
}
RemoveEntryList(&FreeBlock->FreeList);
/* Split it */
- InUseEntry = RtlpSplitEntry(Heap, FreeBlock, AllocationSize, Index, Size);
+ InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
/* Release the lock */
if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
RemoveEntryList(&FreeBlock->FreeList);
/* Split it */
- InUseEntry = RtlpSplitEntry(Heap, FreeBlock, AllocationSize, Index, Size);
+ InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
/* Release the lock */
if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
PULONG FreeListsInUse;
ULONG FreeListsInUseUlong;
SIZE_T AllocationSize;
- SIZE_T Index;
+ SIZE_T Index, InUseIndex, i;
PLIST_ENTRY FreeListHead;
PHEAP_ENTRY InUseEntry;
PHEAP_FREE_ENTRY FreeBlock;
- ULONG InUseIndex, i;
- UCHAR FreeFlags;
+ UCHAR FreeFlags, EntryFlags = HEAP_ENTRY_BUSY;
EXCEPTION_RECORD ExceptionRecord;
BOOLEAN HeapLocked = FALSE;
PHEAP_VIRTUAL_ALLOC_ENTRY VirtualBlock = NULL;
else
AllocationSize = 1;
AllocationSize = (AllocationSize + Heap->AlignRound) & Heap->AlignMask;
+
+ /* Add extra flags in case of settable user value feature is requested,
+ or there is a tag (small or normal) or there is a request to
+ capture stack backtraces */
+ if ((Flags & HEAP_EXTRA_FLAGS_MASK) ||
+ Heap->PseudoTagEntries)
+ {
+ /* Add flag which means that the entry will have extra stuff attached */
+ EntryFlags |= HEAP_ENTRY_EXTRA_PRESENT;
+
+ /* Account for extra stuff size */
+ AllocationSize += sizeof(HEAP_ENTRY_EXTRA);
+ }
+
+ /* Add settable user flags, if any */
+ EntryFlags |= (Flags & HEAP_SETTABLE_USER_FLAGS) >> 4;
+
Index = AllocationSize >> HEAP_ENTRY_SHIFT;
/* Acquire the lock if necessary */
if (!(Flags & HEAP_NO_SERIALIZE))
{
- RtlEnterHeapLock(Heap->LockVariable);
+ RtlEnterHeapLock(Heap->LockVariable, TRUE);
HeapLocked = TRUE;
}
/* Initialize this block */
InUseEntry = (PHEAP_ENTRY)FreeBlock;
- InUseEntry->Flags = HEAP_ENTRY_BUSY | (FreeFlags & HEAP_ENTRY_LAST_ENTRY);
- InUseEntry->UnusedBytes = AllocationSize - Size;
+ InUseEntry->Flags = EntryFlags | (FreeFlags & HEAP_ENTRY_LAST_ENTRY);
+ InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
InUseEntry->SmallTagIndex = 0;
}
else
RtlpRemoveFreeBlock(Heap, FreeBlock, TRUE, FALSE);
/* Split it */
- InUseEntry = RtlpSplitEntry(Heap, FreeBlock, AllocationSize, Index, Size);
+ InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
}
/* Release the lock */
}
/* Initialize the newly allocated block */
- VirtualBlock->BusyBlock.Size = (AllocationSize - Size);
- VirtualBlock->BusyBlock.Flags = HEAP_ENTRY_VIRTUAL_ALLOC | HEAP_ENTRY_EXTRA_PRESENT | HEAP_ENTRY_BUSY;
+ VirtualBlock->BusyBlock.Size = (USHORT)(AllocationSize - Size);
+ VirtualBlock->BusyBlock.Flags = EntryFlags | HEAP_ENTRY_VIRTUAL_ALLOC | HEAP_ENTRY_EXTRA_PRESENT;
VirtualBlock->CommitSize = AllocationSize;
VirtualBlock->ReserveSize = AllocationSize;
/* Lock if necessary */
if (!(Flags & HEAP_NO_SERIALIZE))
{
- RtlEnterHeapLock(Heap->LockVariable);
+ RtlEnterHeapLock(Heap->LockVariable, TRUE);
Locked = TRUE;
}
}
/* Update sizes */
- InUseEntry->Size = Index;
- InUseEntry->UnusedBytes = ((Index << HEAP_ENTRY_SHIFT) - Size);
+ InUseEntry->Size = (USHORT)Index;
+ InUseEntry->UnusedBytes = (UCHAR)((Index << HEAP_ENTRY_SHIFT) - Size);
/* Check if there is a free space remaining after merging those blocks */
if (!FreeSize)
/* Complex case, we need to split the block to give unused free space
back to the heap */
UnusedEntry = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
- UnusedEntry->PreviousSize = Index;
+ UnusedEntry->PreviousSize = (USHORT)Index;
UnusedEntry->SegmentOffset = InUseEntry->SegmentOffset;
/* Update the following block or set the last entry in the segment */
{
/* Set flags and size */
UnusedEntry->Flags = RememberFlags;
- UnusedEntry->Size = FreeSize;
+ UnusedEntry->Size = (USHORT)FreeSize;
/* Insert it to the heap and update total size */
RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
{
/* Update flags and set size of the unused space entry */
UnusedEntry->Flags = RememberFlags & (~HEAP_ENTRY_LAST_ENTRY);
- UnusedEntry->Size = FreeSize;
+ UnusedEntry->Size = (USHORT)FreeSize;
/* Update previous size of the following entry */
- FollowingEntry->PreviousSize = FreeSize;
+ FollowingEntry->PreviousSize = (USHORT)FreeSize;
/* Insert it to the heap and update total free size */
RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
{
/* Fine for a dedicated list */
- UnusedEntry->Size = FreeSize;
+ UnusedEntry->Size = (USHORT)FreeSize;
if (!(RememberFlags & HEAP_ENTRY_LAST_ENTRY))
- ((PHEAP_ENTRY)UnusedEntry + FreeSize)->PreviousSize = FreeSize;
+ ((PHEAP_ENTRY)UnusedEntry + FreeSize)->PreviousSize = (USHORT)FreeSize;
/* Insert it back and update total size */
RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
}
}
- /* Copy user settable flags */
- InUseEntry->Flags &= ~HEAP_ENTRY_SETTABLE_FLAGS;
- InUseEntry->Flags |= ((Flags & HEAP_SETTABLE_USER_FLAGS) >> 4);
-
/* Properly "zero out" (and fill!) the space */
if (Flags & HEAP_ZERO_MEMORY)
{
HEAP_TAIL_FILL);
}
+ /* Copy user settable flags */
+ InUseEntry->Flags &= ~HEAP_ENTRY_SETTABLE_FLAGS;
+ InUseEntry->Flags |= ((Flags & HEAP_SETTABLE_USER_FLAGS) >> 4);
+
/* Return success */
return TRUE;
}
/* Acquire the lock if necessary */
if (!(Flags & HEAP_NO_SERIALIZE))
{
- RtlEnterHeapLock(Heap->LockVariable);
+ RtlEnterHeapLock(Heap->LockVariable, TRUE);
HeapLocked = TRUE;
- Flags ^= HEAP_NO_SERIALIZE;
+ Flags &= ~HEAP_NO_SERIALIZE;
}
/* Get the pointer to the in-use entry */
if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
{
/* Simple in case of a virtual alloc - just an unused size */
- InUseEntry->Size = AllocationSize - Size;
+ InUseEntry->Size = (USHORT)((AllocationSize - Size) >> HEAP_ENTRY_SHIFT);
}
else if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
{
// FIXME Tagging, TagIndex
/* Update unused bytes count */
- InUseEntry->UnusedBytes = AllocationSize - Size;
+ InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
}
else
{
// FIXME Tagging, SmallTagIndex
- InUseEntry->UnusedBytes = AllocationSize - Size;
+ InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
}
/* If new size is bigger than the old size */
/* Initialize this entry */
SplitBlock->Flags = FreeFlags;
- SplitBlock->PreviousSize = Index;
+ SplitBlock->PreviousSize = (USHORT)Index;
SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
/* Remember free size */
FreeSize = InUseEntry->Size - Index;
/* Set new size */
- InUseEntry->Size = Index;
+ InUseEntry->Size = (USHORT)Index;
InUseEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
/* Is that the last entry */
if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
{
- SplitBlock->Size = FreeSize;
+ SplitBlock->Size = (USHORT)FreeSize;
if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
{
/* Update previous size of the next entry */
- ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = FreeSize;
+ ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
}
/* Insert the new one back and update total size */
/* Lock if it's lockable */
if (!(Heap->Flags & HEAP_NO_SERIALIZE))
{
- RtlEnterHeapLock(Heap->LockVariable);
+ RtlEnterHeapLock(Heap->LockVariable, TRUE);
}
return TRUE;
HeapEntry >= Segment->LastValidEntry))
goto invalid_entry;
- if ((HeapEntry->Flags & HEAP_ENTRY_FILL_PATTERN) &&
+ if ((HeapEntry->Flags & HEAP_ENTRY_FILL_PATTERN) &&
!RtlpCheckInUsePattern(HeapEntry))
goto invalid_entry;
}
else
{
- UnCommittedPages += (UcrDescriptor->Size / PAGE_SIZE);
+ UnCommittedPages += (ULONG)(UcrDescriptor->Size / PAGE_SIZE);
UnCommittedRanges++;
CurrentEntry = (PHEAP_ENTRY)((PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
/* Acquire the lock if necessary */
if (!(Flags & HEAP_NO_SERIALIZE))
{
- RtlEnterHeapLock(Heap->LockVariable);
+ RtlEnterHeapLock(Heap->LockVariable, TRUE);
HeapLocked = TRUE;
}
Peb->NumberOfHeaps = 0;
/* Initialize the process heaps list protecting lock */
- RtlInitializeHeapLock(&RtlpProcessHeapsListLock);
+ RtlInitializeCriticalSection(&RtlpProcessHeapsListLock);
}
PHEAP Heap = (PHEAP)HeapHandle;
PHEAP_ENTRY HeapEntry;
PHEAP_ENTRY_EXTRA Extra;
- BOOLEAN HeapLocked = FALSE;
+ BOOLEAN HeapLocked = FALSE, ValueSet = FALSE;
/* Force flags */
Flags |= Heap->Flags;
/* Lock if it's lockable */
if (!(Heap->Flags & HEAP_NO_SERIALIZE))
{
- RtlEnterHeapLock(Heap->LockVariable);
+ RtlEnterHeapLock(Heap->LockVariable, TRUE);
HeapLocked = TRUE;
}
/* Use extra to store the value */
Extra = RtlpGetExtraStuffPointer(HeapEntry);
Extra->Settable = (ULONG_PTR)UserValue;
+
+ /* Indicate that value was set */
+ ValueSet = TRUE;
}
/* Release the heap lock if it was acquired */
if (HeapLocked)
RtlLeaveHeapLock(Heap->LockVariable);
- return TRUE;
+ return ValueSet;
}
/*
/* Lock if it's lockable */
if (!(Heap->Flags & HEAP_NO_SERIALIZE))
{
- RtlEnterHeapLock(Heap->LockVariable);
+ RtlEnterHeapLock(Heap->LockVariable, TRUE);
HeapLocked = TRUE;
}
/* Lock if it's lockable */
if (!(Heap->Flags & HEAP_NO_SERIALIZE))
{
- RtlEnterHeapLock(Heap->LockVariable);
+ RtlEnterHeapLock(Heap->LockVariable, TRUE);
HeapLocked = TRUE;
}