- Fix RtlQuery/SetHeapInformation prototypes, move them to an appropriate place.
- Implement RtlQuery/SetHeapInformation.
- Implement in-place block growing.
- Amount of winetest heap failures is down to 6 (3 exceptions still happen).

svn path=/trunk/; revision=49111
This commit is contained in:
Aleksey Bragin 2010-10-11 08:39:04 +00:00
parent dff2d51166
commit 0568f4e2ce
4 changed files with 335 additions and 80 deletions

View file

@ -707,6 +707,17 @@ RtlProtectHeap(
IN BOOLEAN Protect
);
NTSYSAPI
NTSTATUS
NTAPI
RtlQueryHeapInformation (
IN PVOID HeapHandle,
IN HEAP_INFORMATION_CLASS HeapInformationClass,
OUT PVOID HeapInformation OPTIONAL,
IN SIZE_T HeapInformationLength OPTIONAL,
OUT PSIZE_T ReturnLength OPTIONAL
);
NTSYSAPI
PWSTR
NTAPI
@ -728,6 +739,16 @@ RtlReAllocateHeap(
SIZE_T Size
);
NTSYSAPI
NTSTATUS
NTAPI
RtlSetHeapInformation (
IN PVOID HeapHandle,
IN HEAP_INFORMATION_CLASS HeapInformationClass,
IN PVOID HeapInformation OPTIONAL,
IN SIZE_T HeapInformationLength OPTIONAL
);
NTSYSAPI
BOOLEAN
NTAPI
@ -735,6 +756,27 @@ RtlLockHeap(
IN HANDLE Heap
);
NTSYSAPI
NTSTATUS
NTAPI
RtlMultipleAllocateHeap (
IN PVOID HeapHandle,
IN DWORD Flags,
IN SIZE_T Size,
IN DWORD Count,
OUT PVOID * Array
);
NTSYSAPI
NTSTATUS
NTAPI
RtlMultipleFreeHeap (
IN PVOID HeapHandle,
IN DWORD Flags,
IN DWORD Count,
OUT PVOID * Array
);
NTSYSAPI
NTSTATUS
NTAPI

View file

@ -4958,50 +4958,6 @@ typedef enum _HEAP_INFORMATION_CLASS {
HeapEnableTerminationOnCorruption
} HEAP_INFORMATION_CLASS;
NTSYSAPI
DWORD
NTAPI
RtlSetHeapInformation (
IN PVOID HeapHandle,
IN HEAP_INFORMATION_CLASS HeapInformationClass,
IN PVOID HeapInformation OPTIONAL,
IN SIZE_T HeapInformationLength OPTIONAL
);
NTSYSAPI
DWORD
NTAPI
RtlQueryHeapInformation (
IN PVOID HeapHandle,
IN HEAP_INFORMATION_CLASS HeapInformationClass,
OUT PVOID HeapInformation OPTIONAL,
IN SIZE_T HeapInformationLength OPTIONAL,
OUT PSIZE_T ReturnLength OPTIONAL
);
//
// Multiple alloc-free APIS
//
DWORD
NTAPI
RtlMultipleAllocateHeap (
IN PVOID HeapHandle,
IN DWORD Flags,
IN SIZE_T Size,
IN DWORD Count,
OUT PVOID * Array
);
DWORD
NTAPI
RtlMultipleFreeHeap (
IN PVOID HeapHandle,
IN DWORD Flags,
IN DWORD Count,
OUT PVOID * Array
);
typedef enum _PROCESSOR_CACHE_TYPE {
CacheUnified,
CacheInstruction,

View file

@ -1934,7 +1934,7 @@ RtlProtectHeap(IN PVOID HeapHandle,
return NULL;
}
DWORD
NTSTATUS
NTAPI
RtlSetHeapInformation(IN HANDLE HeapHandle OPTIONAL,
IN HEAP_INFORMATION_CLASS HeapInformationClass,
@ -1945,7 +1945,7 @@ RtlSetHeapInformation(IN HANDLE HeapHandle OPTIONAL,
return 0;
}
DWORD
NTSTATUS
NTAPI
RtlQueryHeapInformation(HANDLE HeapHandle,
HEAP_INFORMATION_CLASS HeapInformationClass,
@ -1979,7 +1979,7 @@ RtlQueryHeapInformation(HANDLE HeapHandle,
}
}
DWORD
NTSTATUS
NTAPI
RtlMultipleAllocateHeap(IN PVOID HeapHandle,
IN DWORD Flags,
@ -1991,7 +1991,7 @@ RtlMultipleAllocateHeap(IN PVOID HeapHandle,
return 0;
}
DWORD
NTSTATUS
NTAPI
RtlMultipleFreeHeap(IN PVOID HeapHandle,
IN DWORD Flags,

View file

@ -955,32 +955,32 @@ RtlpRemoveHeapFromProcessList(PHEAP Heap)
Use classic, lernt from university times algorithm for removing an entry
from a static array */
Current = (PHEAP *)&Peb->ProcessHeaps[Heap->ProcessHeapsListIndex - 1];
Next = Current + 1;
Current = (PHEAP *)&Peb->ProcessHeaps[Heap->ProcessHeapsListIndex - 1];
Next = Current + 1;
/* How many items we need to shift to the left */
Count = Peb->NumberOfHeaps - (Heap->ProcessHeapsListIndex - 1);
/* How many items we need to shift to the left */
Count = Peb->NumberOfHeaps - (Heap->ProcessHeapsListIndex - 1);
/* Move them all in a loop */
while (--Count)
{
/* Copy it and advance next pointer */
*Current = *Next;
/* Move them all in a loop */
while (--Count)
{
/* Copy it and advance next pointer */
*Current = *Next;
/* Update its index */
(*Current)->ProcessHeapsListIndex -= 1;
/* Update its index */
(*Current)->ProcessHeapsListIndex -= 1;
/* Advance pointers */
Current++;
Next++;
}
/* Advance pointers */
Current++;
Next++;
}
/* Decrease total number of heaps */
Peb->NumberOfHeaps--;
/* Decrease total number of heaps */
Peb->NumberOfHeaps--;
/* Zero last unused item */
Peb->ProcessHeaps[Peb->NumberOfHeaps] = NULL;
Heap->ProcessHeapsListIndex = 0;
/* Zero last unused item */
Peb->ProcessHeaps[Peb->NumberOfHeaps] = NULL;
Heap->ProcessHeapsListIndex = 0;
/* Release the lock */
RtlLeaveHeapLock(&RtlpProcessHeapsListLock);
@ -1977,6 +1977,8 @@ RtlpAllocateNonDedicated(PHEAP Heap,
/* Release the lock */
if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
DPRINT1("HEAP: Allocation failed!\n");
DPRINT1("Flags %x\n", Heap->Flags);
return NULL;
}
@ -2016,7 +2018,8 @@ RtlAllocateHeap(IN PVOID HeapPtr,
if (Size >= 0x80000000)
{
RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_NO_MEMORY);
return FALSE;
DPRINT1("HEAP: Allocation failed!\n");
return NULL;
}
if (Flags & (
@ -2167,6 +2170,7 @@ RtlAllocateHeap(IN PVOID HeapPtr,
// Set STATUS!
/* Release the lock */
if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
DPRINT1("HEAP: Allocation failed!\n");
return NULL;
}
@ -2202,6 +2206,7 @@ RtlAllocateHeap(IN PVOID HeapPtr,
/* Release the lock */
if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
DPRINT1("HEAP: Allocation failed!\n");
return NULL;
}
@ -2277,7 +2282,8 @@ BOOLEAN NTAPI RtlFreeHeap(
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed releasing memory with Status 0x%08X\n", Status);
DPRINT1("HEAP: Failed releasing memory with Status 0x%08X. Heap %p, ptr %p, base address %p\n",
Status, Heap, Ptr, VirtualEntry);
RtlSetLastWin32ErrorAndNtStatusFromNtStatus(Status);
}
}
@ -2351,8 +2357,225 @@ RtlpGrowBlockInPlace (IN PHEAP Heap,
IN SIZE_T Size,
IN SIZE_T Index)
{
/* We always fail growing in place now */
return FALSE;
UCHAR EntryFlags, RememberFlags;
PHEAP_FREE_ENTRY FreeEntry, UnusedEntry, FollowingEntry;
SIZE_T FreeSize, PrevSize, TailPart, AddedSize = 0;
PHEAP_ENTRY_EXTRA OldExtra, NewExtra;
/* We can't grow beyond specified threshold */
if (Index > Heap->VirtualMemoryThreshold)
return FALSE;
/* Get entry flags */
EntryFlags = InUseEntry->Flags;
/* Get the next free entry */
FreeEntry = (PHEAP_FREE_ENTRY)(InUseEntry + InUseEntry->Size);
if (EntryFlags & HEAP_ENTRY_LAST_ENTRY)
{
/* There is no next block, just uncommitted space. Calculate how much is needed */
FreeSize = (Index - InUseEntry->Size) << HEAP_ENTRY_SHIFT;
FreeSize = ROUND_UP(FreeSize, PAGE_SIZE);
/* Find and commit those pages */
FreeEntry = RtlpFindAndCommitPages(Heap,
Heap->Segments[InUseEntry->SegmentOffset],
&FreeSize,
FreeEntry);
/* Fail if it failed... */
if (!FreeEntry) return FALSE;
/* It was successful, perform coalescing */
FreeSize = FreeSize >> HEAP_ENTRY_SHIFT;
FreeEntry = RtlpCoalesceFreeBlocks(Heap, FreeEntry, &FreeSize, FALSE);
/* Check if it's enough */
if (FreeSize + InUseEntry->Size < Index)
{
/* Still not enough */
RtlpInsertFreeBlock(Heap, FreeEntry, FreeSize);
Heap->TotalFreeSize += FreeSize;
return FALSE;
}
/* Remember flags of this free entry */
RememberFlags = FreeEntry->Flags;
/* Sum up sizes */
FreeSize += InUseEntry->Size;
}
else
{
/* The next block indeed exists. Check if it's free or in use */
if (FreeEntry->Flags & HEAP_ENTRY_BUSY) return FALSE;
/* Next entry is free, check if it can fit the block we need */
FreeSize = InUseEntry->Size + FreeEntry->Size;
if (FreeSize < Index) return FALSE;
/* Remember flags of this free entry */
RememberFlags = FreeEntry->Flags;
/* Remove this block from the free list */
RtlpRemoveFreeBlock(Heap, FreeEntry, FALSE, FALSE);
Heap->TotalFreeSize -= FreeEntry->Size;
}
PrevSize = (InUseEntry->Size << HEAP_ENTRY_SHIFT) - InUseEntry->UnusedBytes;
FreeSize -= Index;
/* Don't produce too small blocks */
if (FreeSize <= 2)
{
Index += FreeSize;
FreeSize = 0;
}
/* Process extra stuff */
if (RememberFlags & HEAP_ENTRY_EXTRA_PRESENT)
{
/* Calculate pointers */
OldExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + InUseEntry->Size - 1);
NewExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + Index - 1);
/* Copy contents */
*NewExtra = *OldExtra;
// FIXME Tagging
}
/* Update sizes */
InUseEntry->Size = Index;
InUseEntry->UnusedBytes = ((Index << HEAP_ENTRY_SHIFT) - Size);
/* Check if there is a free space remaining after merging those blocks */
if (!FreeSize)
{
/* Update flags and sizes */
InUseEntry->Flags |= RememberFlags & HEAP_ENTRY_LAST_ENTRY;
/* Either update previous size of the next entry or mark it as a last
entry in the segment*/
if (RememberFlags & HEAP_ENTRY_LAST_ENTRY)
Heap->Segments[InUseEntry->SegmentOffset]->LastEntryInSegment = InUseEntry;
else
(InUseEntry + InUseEntry->Size)->PreviousSize = InUseEntry->Size;
}
else
{
/* 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->SegmentOffset = InUseEntry->SegmentOffset;
/* Update the following block or set the last entry in the segment */
if (RememberFlags & HEAP_ENTRY_LAST_ENTRY)
{
/* Set last entry and set flags and size */
Heap->Segments[InUseEntry->SegmentOffset]->LastEntryInSegment = InUseEntry;
UnusedEntry->Flags = RememberFlags;
UnusedEntry->Size = FreeSize;
/* Insert it to the heap and update total size */
RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
Heap->TotalFreeSize += FreeSize;
}
else
{
/* There is a block after this one */
FollowingEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)UnusedEntry + FreeSize);
if (FollowingEntry->Flags & HEAP_ENTRY_BUSY)
{
/* Update flags and set size of the unused space entry */
UnusedEntry->Flags = RememberFlags & (~HEAP_ENTRY_LAST_ENTRY);
UnusedEntry->Size = FreeSize;
/* Update previous size of the following entry */
FollowingEntry->PreviousSize = FreeSize;
/* Insert it to the heap and update total free size */
RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
Heap->TotalFreeSize += FreeSize;
}
else
{
/* That following entry is also free, what a fortune! */
RememberFlags = FollowingEntry->Flags;
/* Remove it */
RtlpRemoveFreeBlock(Heap, FollowingEntry, FALSE, FALSE);
Heap->TotalFreeSize -= FollowingEntry->Size;
/* And make up a new combined block */
FreeSize += FollowingEntry->Size;
UnusedEntry->Flags = RememberFlags;
/* Check where to put it */
if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
{
/* Fine for a dedicated list */
UnusedEntry->Size = FreeSize;
if (RememberFlags & HEAP_ENTRY_LAST_ENTRY)
Heap->Segments[UnusedEntry->SegmentOffset]->LastEntryInSegment = (PHEAP_ENTRY)UnusedEntry;
else
((PHEAP_ENTRY)UnusedEntry + FreeSize)->PreviousSize = FreeSize;
/* Insert it back and update total size */
RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
Heap->TotalFreeSize += FreeSize;
}
else
{
/* The block is very large, leave all the hassle to the insertion routine */
RtlpInsertFreeBlock(Heap, UnusedEntry, FreeSize);
}
}
}
}
/* 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)
{
RtlZeroMemory((PCHAR)(InUseEntry + 1) + PrevSize, Size - PrevSize);
}
else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
{
/* Calculate tail part which we need to fill */
TailPart = PrevSize & (sizeof(ULONG) - 1);
/* "Invert" it as usual */
if (TailPart) TailPart = 4 - TailPart;
if (Size > (PrevSize + TailPart))
AddedSize = (Size - (PrevSize + TailPart)) & ~(sizeof(ULONG) - 1);
if (AddedSize)
{
RtlFillMemoryUlong((PCHAR)(InUseEntry + 1) + PrevSize + TailPart,
AddedSize,
ARENA_INUSE_FILLER);
}
}
/* Fill the new tail */
if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
{
RtlFillMemory((PCHAR)(InUseEntry + 1) + Size,
HEAP_ENTRY_SIZE,
HEAP_TAIL_FILL);
}
/* Return success */
return TRUE;
}
PHEAP_ENTRY_EXTRA NTAPI
@ -3270,18 +3493,34 @@ RtlProtectHeap(IN PVOID HeapHandle,
return NULL;
}
DWORD
NTSTATUS
NTAPI
RtlSetHeapInformation(IN HANDLE HeapHandle OPTIONAL,
IN HEAP_INFORMATION_CLASS HeapInformationClass,
IN PVOID HeapInformation,
IN SIZE_T HeapInformationLength)
{
UNIMPLEMENTED;
return 0;
/* Setting heap information is not really supported except for enabling LFH */
if (HeapInformationClass == 0) return STATUS_SUCCESS;
/* Check buffer length */
if (HeapInformationLength < sizeof(ULONG))
{
/* The provided buffer is too small */
return STATUS_BUFFER_TOO_SMALL;
}
/* Check for a special magic value for enabling LFH */
if (*(PULONG)HeapInformation == 2)
{
DPRINT1("RtlSetHeapInformation() needs to enable LFH\n");
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
DWORD
NTSTATUS
NTAPI
RtlQueryHeapInformation(HANDLE HeapHandle,
HEAP_INFORMATION_CLASS HeapInformationClass,
@ -3289,11 +3528,29 @@ RtlQueryHeapInformation(HANDLE HeapHandle,
SIZE_T HeapInformationLength OPTIONAL,
PSIZE_T ReturnLength OPTIONAL)
{
UNIMPLEMENTED;
return 0;
PHEAP Heap = (PHEAP)HeapHandle;
/* Only HeapCompatibilityInformation is supported */
if (HeapInformationClass != HeapCompatibilityInformation)
return STATUS_UNSUCCESSFUL;
/* Set result length */
if (ReturnLength) *ReturnLength = sizeof(ULONG);
/* Check buffer length */
if (HeapInformationLength < sizeof(ULONG))
{
/* It's too small, return needed length */
return STATUS_BUFFER_TOO_SMALL;
}
/* Return front end heap type */
*(PULONG)HeapInformation = Heap->FrontEndHeapType;
return STATUS_SUCCESS;
}
DWORD
NTSTATUS
NTAPI
RtlMultipleAllocateHeap(IN PVOID HeapHandle,
IN DWORD Flags,
@ -3305,7 +3562,7 @@ RtlMultipleAllocateHeap(IN PVOID HeapHandle,
return 0;
}
DWORD
NTSTATUS
NTAPI
RtlMultipleFreeHeap(IN PVOID HeapHandle,
IN DWORD Flags,