mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 16:02:56 +00:00
[HEAP]
- Implement heap validation support. svn path=/trunk/; revision=49126
This commit is contained in:
parent
6c00026235
commit
1bcf80bc88
1 changed files with 481 additions and 4 deletions
|
@ -67,6 +67,20 @@ RtlpFindLeastSetBit(ULONG Bits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Maximum size of a tail-filling pattern used for compare operation */
|
||||||
|
UCHAR FillPattern[HEAP_ENTRY_SIZE] =
|
||||||
|
{
|
||||||
|
HEAP_TAIL_FILL,
|
||||||
|
HEAP_TAIL_FILL,
|
||||||
|
HEAP_TAIL_FILL,
|
||||||
|
HEAP_TAIL_FILL,
|
||||||
|
HEAP_TAIL_FILL,
|
||||||
|
HEAP_TAIL_FILL,
|
||||||
|
HEAP_TAIL_FILL,
|
||||||
|
HEAP_TAIL_FILL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
ULONG NTAPI
|
ULONG NTAPI
|
||||||
RtlCompareMemoryUlong(PVOID Source, ULONG Length, ULONG Value);
|
RtlCompareMemoryUlong(PVOID Source, ULONG Length, ULONG Value);
|
||||||
|
|
||||||
|
@ -3160,6 +3174,437 @@ RtlSizeHeap(
|
||||||
return EntrySize;
|
return EntrySize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOLEAN NTAPI
|
||||||
|
RtlpCheckInUsePattern(PHEAP_ENTRY HeapEntry)
|
||||||
|
{
|
||||||
|
SIZE_T Size, Result;
|
||||||
|
PCHAR TailPart;
|
||||||
|
|
||||||
|
/* Calculate size */
|
||||||
|
if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
|
||||||
|
Size = RtlpGetSizeOfBigBlock(HeapEntry);
|
||||||
|
else
|
||||||
|
Size = (HeapEntry->Size << HEAP_ENTRY_SHIFT) - HeapEntry->UnusedBytes;
|
||||||
|
|
||||||
|
/* Calculate pointer to the tail part of the block */
|
||||||
|
TailPart = (PCHAR)(HeapEntry + 1) + Size;
|
||||||
|
|
||||||
|
/* Compare tail pattern */
|
||||||
|
Result = RtlCompareMemory(TailPart,
|
||||||
|
FillPattern,
|
||||||
|
HEAP_ENTRY_SIZE);
|
||||||
|
|
||||||
|
if (Result != HEAP_ENTRY_SIZE)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Heap entry (size %x) %p tail is modified at %p\n", Size, HeapEntry, TailPart + Result);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All is fine */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN NTAPI
|
||||||
|
RtlpValidateHeapHeaders(
|
||||||
|
PHEAP Heap,
|
||||||
|
BOOLEAN Recalculate)
|
||||||
|
{
|
||||||
|
// We skip header validation for now
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN NTAPI
|
||||||
|
RtlpValidateHeapEntry(
|
||||||
|
PHEAP Heap,
|
||||||
|
PHEAP_ENTRY HeapEntry)
|
||||||
|
{
|
||||||
|
BOOLEAN BigAllocation, EntryFound = FALSE;
|
||||||
|
PHEAP_SEGMENT Segment;
|
||||||
|
ULONG SegmentOffset;
|
||||||
|
|
||||||
|
/* Perform various consistency checks of this entry */
|
||||||
|
if (!HeapEntry) goto invalid_entry;
|
||||||
|
if ((ULONG_PTR)HeapEntry & (HEAP_ENTRY_SIZE - 1)) goto invalid_entry;
|
||||||
|
if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY)) goto invalid_entry;
|
||||||
|
|
||||||
|
BigAllocation = HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC;
|
||||||
|
Segment = Heap->Segments[HeapEntry->SegmentOffset];
|
||||||
|
|
||||||
|
if (BigAllocation &&
|
||||||
|
(((ULONG_PTR)HeapEntry & (PAGE_SIZE - 1)) != FIELD_OFFSET(HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock)))
|
||||||
|
goto invalid_entry;
|
||||||
|
|
||||||
|
if (!BigAllocation && (HeapEntry->SegmentOffset >= HEAP_SEGMENTS ||
|
||||||
|
!Segment ||
|
||||||
|
HeapEntry < Segment->FirstEntry ||
|
||||||
|
HeapEntry >= Segment->LastValidEntry))
|
||||||
|
goto invalid_entry;
|
||||||
|
|
||||||
|
if ((HeapEntry->Flags & HEAP_ENTRY_FILL_PATTERN) &&
|
||||||
|
!RtlpCheckInUsePattern(HeapEntry))
|
||||||
|
goto invalid_entry;
|
||||||
|
|
||||||
|
/* Checks are done, if this is a virtual entry, that's all */
|
||||||
|
if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) return TRUE;
|
||||||
|
|
||||||
|
/* Go through segments and check if this entry fits into any of them */
|
||||||
|
for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
|
||||||
|
{
|
||||||
|
Segment = Heap->Segments[SegmentOffset];
|
||||||
|
if (!Segment) continue;
|
||||||
|
|
||||||
|
if ((HeapEntry >= Segment->FirstEntry) &&
|
||||||
|
(HeapEntry < Segment->LastValidEntry))
|
||||||
|
{
|
||||||
|
/* Got it */
|
||||||
|
EntryFound = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return our result of finding entry in the segments */
|
||||||
|
return EntryFound;
|
||||||
|
|
||||||
|
invalid_entry:
|
||||||
|
DPRINT1("HEAP: Invalid heap entry %p in heap %p\n", HeapEntry, Heap);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN NTAPI
|
||||||
|
RtlpValidateHeapSegment(
|
||||||
|
PHEAP Heap,
|
||||||
|
PHEAP_SEGMENT Segment,
|
||||||
|
UCHAR SegmentOffset,
|
||||||
|
PULONG FreeEntriesCount,
|
||||||
|
PSIZE_T TotalFreeSize,
|
||||||
|
PSIZE_T TagEntries,
|
||||||
|
PSIZE_T PseudoTagEntries)
|
||||||
|
{
|
||||||
|
PHEAP_UCR_DESCRIPTOR UcrDescriptor;
|
||||||
|
PLIST_ENTRY UcrEntry;
|
||||||
|
SIZE_T ByteSize, Size, Result;
|
||||||
|
PHEAP_ENTRY CurrentEntry;
|
||||||
|
ULONG UnCommittedPages;
|
||||||
|
ULONG UnCommittedRanges;
|
||||||
|
ULONG PreviousSize;
|
||||||
|
|
||||||
|
UnCommittedPages = 0;
|
||||||
|
UnCommittedRanges = 0;
|
||||||
|
|
||||||
|
if (IsListEmpty(&Segment->UCRSegmentList))
|
||||||
|
{
|
||||||
|
UcrEntry = NULL;
|
||||||
|
UcrDescriptor = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UcrEntry = Segment->UCRSegmentList.Flink;
|
||||||
|
UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Segment->BaseAddress == Heap)
|
||||||
|
CurrentEntry = &Heap->Entry;
|
||||||
|
else
|
||||||
|
CurrentEntry = &Segment->Entry;
|
||||||
|
|
||||||
|
while (CurrentEntry < Segment->LastValidEntry)
|
||||||
|
{
|
||||||
|
if (UcrDescriptor &&
|
||||||
|
((PVOID)CurrentEntry >= UcrDescriptor->Address))
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Entry %p is not inside uncommited range [%p .. %p)\n",
|
||||||
|
CurrentEntry, UcrDescriptor->Address,
|
||||||
|
(PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreviousSize = 0;
|
||||||
|
|
||||||
|
while (CurrentEntry < Segment->LastValidEntry)
|
||||||
|
{
|
||||||
|
if (PreviousSize != CurrentEntry->PreviousSize)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Entry %p has incorrect PreviousSize %x instead of %x\n",
|
||||||
|
CurrentEntry, CurrentEntry->PreviousSize, PreviousSize);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreviousSize = CurrentEntry->Size;
|
||||||
|
Size = CurrentEntry->Size << HEAP_ENTRY_SHIFT;
|
||||||
|
|
||||||
|
if (CurrentEntry->Flags & HEAP_ENTRY_BUSY)
|
||||||
|
{
|
||||||
|
if (TagEntries)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check fill pattern */
|
||||||
|
if (CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN)
|
||||||
|
{
|
||||||
|
if (!RtlpCheckInUsePattern(CurrentEntry))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The entry is free, increase free entries count and total free size */
|
||||||
|
*FreeEntriesCount = *FreeEntriesCount + 1;
|
||||||
|
*TotalFreeSize += CurrentEntry->Size;
|
||||||
|
|
||||||
|
if ((Heap->Flags & HEAP_FREE_CHECKING_ENABLED) &&
|
||||||
|
(CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN))
|
||||||
|
{
|
||||||
|
ByteSize = Size - sizeof(HEAP_FREE_ENTRY);
|
||||||
|
|
||||||
|
if ((CurrentEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT) &&
|
||||||
|
(ByteSize > sizeof(HEAP_FREE_ENTRY_EXTRA)))
|
||||||
|
{
|
||||||
|
ByteSize -= sizeof(HEAP_FREE_ENTRY_EXTRA);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = RtlCompareMemoryUlong((PCHAR)((PHEAP_FREE_ENTRY)CurrentEntry + 1),
|
||||||
|
ByteSize,
|
||||||
|
ARENA_FREE_FILLER);
|
||||||
|
|
||||||
|
if (Result != ByteSize)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Free heap block %p modified at %p after it was freed\n",
|
||||||
|
CurrentEntry,
|
||||||
|
(PCHAR)(CurrentEntry + 1) + Result);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurrentEntry->SegmentOffset != SegmentOffset)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Heap entry %p SegmentOffset is incorrect %x (should be %x)\n", CurrentEntry, SegmentOffset, CurrentEntry->SegmentOffset);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if it's the last entry */
|
||||||
|
if (CurrentEntry->Flags & HEAP_ENTRY_LAST_ENTRY)
|
||||||
|
{
|
||||||
|
CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
|
||||||
|
|
||||||
|
if (!UcrDescriptor)
|
||||||
|
{
|
||||||
|
/* Check if it's not really the last one */
|
||||||
|
if (CurrentEntry != Segment->LastValidEntry)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Heap entry %p is not last block in segment (%x)\n", CurrentEntry, Segment->LastValidEntry);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (CurrentEntry != UcrDescriptor->Address)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Heap entry %p does not match next uncommitted address (%p)\n",
|
||||||
|
CurrentEntry, UcrDescriptor->Address);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UnCommittedPages += (UcrDescriptor->Size / PAGE_SIZE);
|
||||||
|
UnCommittedRanges++;
|
||||||
|
|
||||||
|
CurrentEntry = (PHEAP_ENTRY)((PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
|
||||||
|
|
||||||
|
/* Go to the next UCR descriptor */
|
||||||
|
UcrEntry = UcrEntry->Flink;
|
||||||
|
if (UcrEntry == &Segment->UCRSegmentList)
|
||||||
|
{
|
||||||
|
UcrEntry = NULL;
|
||||||
|
UcrDescriptor = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance to the next entry */
|
||||||
|
CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check total numbers of UCP and UCR */
|
||||||
|
if (Segment->NumberOfUnCommittedPages != UnCommittedPages)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Segment %p NumberOfUnCommittedPages is invalid (%x != %x)\n",
|
||||||
|
Segment, Segment->NumberOfUnCommittedPages, UnCommittedPages);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Segment->NumberOfUnCommittedRanges != UnCommittedRanges)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Segment %p NumberOfUnCommittedRanges is invalid (%x != %x)\n",
|
||||||
|
Segment, Segment->NumberOfUnCommittedRanges, UnCommittedRanges);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN NTAPI
|
||||||
|
RtlpValidateHeap(PHEAP Heap,
|
||||||
|
BOOLEAN ForceValidation)
|
||||||
|
{
|
||||||
|
PHEAP_SEGMENT Segment;
|
||||||
|
BOOLEAN EmptyList;
|
||||||
|
UCHAR SegmentOffset;
|
||||||
|
SIZE_T Size, TotalFreeSize;
|
||||||
|
ULONG PreviousSize;
|
||||||
|
PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
|
||||||
|
PLIST_ENTRY ListHead, NextEntry;
|
||||||
|
PHEAP_FREE_ENTRY FreeEntry;
|
||||||
|
ULONG FreeBlocksCount, FreeListEntriesCount;
|
||||||
|
|
||||||
|
/* Check headers */
|
||||||
|
if (!RtlpValidateHeapHeaders(Heap, FALSE))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Skip validation if it's not needed */
|
||||||
|
if (!ForceValidation && !(Heap->Flags & HEAP_VALIDATE_ALL_ENABLED))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* Check free lists bitmaps */
|
||||||
|
FreeListEntriesCount = 0;
|
||||||
|
ListHead = &Heap->FreeLists[0];
|
||||||
|
|
||||||
|
for (Size = 0; Size < HEAP_FREELISTS; Size++)
|
||||||
|
{
|
||||||
|
if (Size)
|
||||||
|
{
|
||||||
|
/* This is a dedicated list. Check if it's empty */
|
||||||
|
EmptyList = IsListEmpty(ListHead);
|
||||||
|
|
||||||
|
if (Heap->u.FreeListsInUseBytes[Size >> 3] & (1 << (Size & 7)))
|
||||||
|
{
|
||||||
|
if (EmptyList)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Empty %x-free list marked as non-empty\n", Size);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!EmptyList)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Non-empty %x-free list marked as empty\n", Size);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now check this list entries */
|
||||||
|
NextEntry = ListHead->Flink;
|
||||||
|
PreviousSize = 0;
|
||||||
|
|
||||||
|
while (ListHead != NextEntry)
|
||||||
|
{
|
||||||
|
FreeEntry = CONTAINING_RECORD(NextEntry, HEAP_FREE_ENTRY, FreeList);
|
||||||
|
NextEntry = NextEntry->Flink;
|
||||||
|
|
||||||
|
/* If there is an in-use entry in a free list - that's quite a big problem */
|
||||||
|
if (FreeEntry->Flags & HEAP_ENTRY_BUSY)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: %x-dedicated list free element %x is marked in-use\n", Size, FreeEntry);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check sizes according to that specific list's size */
|
||||||
|
if ((Size == 0) && (FreeEntry->Size < HEAP_FREELISTS))
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Non dedicated list free element %x has size %x which would fit a dedicated list\n", FreeEntry, FreeEntry->Size);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if (Size && (FreeEntry->Size != Size))
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: %x-dedicated list free element %x has incorrect size %x\n", Size, FreeEntry, FreeEntry->Size);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if ((Size == 0) && (FreeEntry->Size < PreviousSize))
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Non dedicated list free element %x is not put in order\n", FreeEntry);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember previous size*/
|
||||||
|
PreviousSize = FreeEntry->Size;
|
||||||
|
|
||||||
|
/* Add up to the total amount of free entries */
|
||||||
|
FreeListEntriesCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go to the head of the next free list */
|
||||||
|
ListHead++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check big allocations */
|
||||||
|
ListHead = &Heap->VirtualAllocdBlocks;
|
||||||
|
NextEntry = ListHead->Flink;
|
||||||
|
|
||||||
|
while (ListHead != NextEntry)
|
||||||
|
{
|
||||||
|
VirtualAllocBlock = CONTAINING_RECORD(NextEntry, HEAP_VIRTUAL_ALLOC_ENTRY, Entry);
|
||||||
|
|
||||||
|
/* We can only check the fill pattern */
|
||||||
|
if (VirtualAllocBlock->BusyBlock.Flags & HEAP_ENTRY_FILL_PATTERN)
|
||||||
|
{
|
||||||
|
if (!RtlpCheckInUsePattern(&VirtualAllocBlock->BusyBlock))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NextEntry = NextEntry->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check all segments */
|
||||||
|
FreeBlocksCount = 0;
|
||||||
|
TotalFreeSize = 0;
|
||||||
|
|
||||||
|
for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
|
||||||
|
{
|
||||||
|
Segment = Heap->Segments[SegmentOffset];
|
||||||
|
|
||||||
|
/* Go to the next one if there is no segment */
|
||||||
|
if (!Segment) continue;
|
||||||
|
|
||||||
|
if (!RtlpValidateHeapSegment(Heap,
|
||||||
|
Segment,
|
||||||
|
SegmentOffset,
|
||||||
|
&FreeBlocksCount,
|
||||||
|
&TotalFreeSize,
|
||||||
|
NULL,
|
||||||
|
NULL))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FreeListEntriesCount != FreeBlocksCount)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Free blocks count in arena (%d) does not match free blocks number in the free lists (%d)\n", FreeBlocksCount, FreeListEntriesCount);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Heap->TotalFreeSize != TotalFreeSize)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Total size of free blocks in arena (%d) does not equal to the one in heap header (%d)\n", TotalFreeSize, Heap->TotalFreeSize);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* RtlValidateHeap
|
* RtlValidateHeap
|
||||||
|
@ -3180,15 +3625,47 @@ RtlSizeHeap(
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOLEAN NTAPI RtlValidateHeap(
|
BOOLEAN NTAPI RtlValidateHeap(
|
||||||
HANDLE Heap,
|
HANDLE HeapPtr,
|
||||||
ULONG Flags,
|
ULONG Flags,
|
||||||
PVOID Block
|
PVOID Block
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
PHEAP Heap = (PHEAP)HeapPtr;
|
||||||
|
BOOLEAN HeapLocked = FALSE;
|
||||||
|
BOOLEAN HeapValid;
|
||||||
|
|
||||||
/* Imitate success */
|
// FIXME Check for special heap
|
||||||
return TRUE;
|
|
||||||
|
/* Check signature */
|
||||||
|
if (Heap->Signature != HEAP_SIGNATURE)
|
||||||
|
{
|
||||||
|
DPRINT1("HEAP: Signature %x is invalid for heap %p\n", Heap->Signature, Heap);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force flags */
|
||||||
|
Flags = Heap->ForceFlags;
|
||||||
|
|
||||||
|
/* Acquire the lock if necessary */
|
||||||
|
if (!(Flags & HEAP_NO_SERIALIZE))
|
||||||
|
{
|
||||||
|
RtlEnterHeapLock(Heap->LockVariable);
|
||||||
|
HeapLocked = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Either validate whole heap or just one entry */
|
||||||
|
if (!Block)
|
||||||
|
HeapValid = RtlpValidateHeap(Heap, TRUE);
|
||||||
|
else
|
||||||
|
HeapValid = RtlpValidateHeapEntry(Heap, (PHEAP_ENTRY)Block - 1);
|
||||||
|
|
||||||
|
/* Unlock if it's lockable */
|
||||||
|
if (HeapLocked)
|
||||||
|
{
|
||||||
|
RtlLeaveHeapLock(Heap->LockVariable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return HeapValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue