ReactOS 0.4.15-dev-7889-g76290a6
heap.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/rtl/heap.c
5 * PURPOSE: RTL Heap backend allocator
6 * PROGRAMMERS: Copyright 2010 Aleksey Bragin
7 * Copyright 2020 Katayama Hirofumi MZ
8 */
9
10/* Useful references:
11 http://msdn.microsoft.com/en-us/library/ms810466.aspx
12 http://msdn.microsoft.com/en-us/library/ms810603.aspx
13 http://www.securitylab.ru/analytics/216376.php
14 http://binglongx.spaces.live.com/blog/cns!142CBF6D49079DE8!596.entry
15 http://www.phreedom.org/research/exploits/asn1-bitstring/
16 http://illmatics.com/Understanding_the_LFH.pdf
17 http://www.alex-ionescu.com/?p=18
18*/
19
20/* INCLUDES *****************************************************************/
21
22#include <rtl.h>
23#include <heap.h>
24
25#define NDEBUG
26#include <debug.h>
27
28/* Bitmaps stuff */
29
30/* How many least significant bits are clear */
32{
33 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
34 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
35 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
36 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
37 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
38 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
39 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
40 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
41 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
42 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
43 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
44 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
45 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
46 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
47 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
48 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
49};
50
54{
55 if (Bits & 0xFFFF)
56 {
57 if (Bits & 0xFF)
58 return RtlpBitsClearLow[Bits & 0xFF]; /* Lowest byte */
59 else
60 return RtlpBitsClearLow[(Bits >> 8) & 0xFF] + 8; /* 2nd byte */
61 }
62 else
63 {
64 if ((Bits >> 16) & 0xFF)
65 return RtlpBitsClearLow[(Bits >> 16) & 0xFF] + 16; /* 3rd byte */
66 else
67 return RtlpBitsClearLow[(Bits >> 24) & 0xFF] + 24; /* Highest byte */
68 }
69}
70
71/* Maximum size of a tail-filling pattern used for compare operation */
73{
82};
83
84static
87{
88 if (Entry->Flags & HEAP_ENTRY_LAST_ENTRY)
89 return TRUE;
90
91 Entry = Entry + Entry->Size;
92
93 /* 1-sized busy last entry are the committed range guard entries */
94 if ((Entry->Flags != (HEAP_ENTRY_BUSY | HEAP_ENTRY_LAST_ENTRY)) || (Entry->Size != 1))
95 return FALSE;
96
97 /* This must be the last or the penultimate entry in the page */
98 ASSERT(((PVOID)PAGE_ROUND_UP(Entry) == (Entry + 1)) ||
99 ((PVOID)PAGE_ROUND_UP(Entry)== (Entry + 2)));
100 return TRUE;
101}
102
103/* FUNCTIONS *****************************************************************/
104
107 IN ULONG Flags,
110{
111 ULONG NumUCRs = 8;
112 ULONG Index;
113 SIZE_T HeaderSize;
115 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
116 SIZE_T DeCommitFreeBlockThreshold;
117
118 /* Preconditions */
119 ASSERT(Heap != NULL);
122 ASSERT(!(Flags & HEAP_NO_SERIALIZE) || (Lock == NULL)); /* HEAP_NO_SERIALIZE => no lock */
123
124 /* Make sure we're not doing stupid things */
125 DeCommitFreeBlockThreshold = Parameters->DeCommitFreeBlockThreshold >> HEAP_ENTRY_SHIFT;
126 /* Start out with the size of a plain Heap header + our hints of free entries + the bitmap */
127 HeaderSize = FIELD_OFFSET(HEAP, FreeHints[DeCommitFreeBlockThreshold])
128 + (ROUND_UP(DeCommitFreeBlockThreshold, RTL_BITS_OF(ULONG)) / RTL_BITS_OF(ULONG)) * sizeof(ULONG);
129
130 /* Check if space needs to be added for the Heap Lock */
131 if (!(Flags & HEAP_NO_SERIALIZE))
132 {
133 if (Lock != NULL)
134 /* The user manages the Heap Lock */
136 else
137 if (RtlpGetMode() == UserMode)
138 {
139 /* In user mode, the Heap Lock trails the Heap header */
140 Lock = (PHEAP_LOCK) ((ULONG_PTR) (Heap) + HeaderSize);
141 HeaderSize += sizeof(HEAP_LOCK);
142 }
143 }
144
145 /* Add space for the initial Heap UnCommitted Range Descriptor list */
146 UcrDescriptor = (PHEAP_UCR_DESCRIPTOR) ((ULONG_PTR) (Heap) + HeaderSize);
147 HeaderSize += NumUCRs * sizeof(HEAP_UCR_DESCRIPTOR);
148
149 HeaderSize = ROUND_UP(HeaderSize, HEAP_ENTRY_SIZE);
150 /* Sanity check */
151 ASSERT(HeaderSize <= PAGE_SIZE);
152
153 /* Initialise the Heap Entry header containing the Heap header */
154 Heap->Entry.Size = (USHORT)(HeaderSize >> HEAP_ENTRY_SHIFT);
155 Heap->Entry.Flags = HEAP_ENTRY_BUSY;
156 Heap->Entry.SmallTagIndex = LOBYTE(Heap->Entry.Size) ^ HIBYTE(Heap->Entry.Size) ^ Heap->Entry.Flags;
157 Heap->Entry.PreviousSize = 0;
158 Heap->Entry.SegmentOffset = 0;
159 Heap->Entry.UnusedBytes = 0;
160
161 /* Initialise the Heap header */
162 Heap->Signature = HEAP_SIGNATURE;
163 Heap->Flags = Flags;
164 Heap->ForceFlags = (Flags & (HEAP_NO_SERIALIZE |
173
174 /* Initialise the Heap parameters */
175 Heap->VirtualMemoryThreshold = ROUND_UP(Parameters->VirtualMemoryThreshold, sizeof(HEAP_ENTRY)) >> HEAP_ENTRY_SHIFT;
176 Heap->SegmentReserve = Parameters->SegmentReserve;
177 Heap->SegmentCommit = Parameters->SegmentCommit;
178 Heap->DeCommitFreeBlockThreshold = DeCommitFreeBlockThreshold;
179 Heap->DeCommitTotalFreeThreshold = Parameters->DeCommitTotalFreeThreshold >> HEAP_ENTRY_SHIFT;
180 Heap->MaximumAllocationSize = Parameters->MaximumAllocationSize;
181 Heap->CommitRoutine = Parameters->CommitRoutine;
182
183 /* Initialise the Heap validation info */
184 Heap->HeaderValidateCopy = NULL;
185 Heap->HeaderValidateLength = (USHORT)HeaderSize;
186
187 /* Initialise the Heap Lock */
189 {
191 if (!NT_SUCCESS(Status))
192 return Status;
193 }
194 Heap->LockVariable = Lock;
195
196 /* Initialise the Heap alignment info */
198 {
199 Heap->AlignMask = (ULONG) ~15;
200 Heap->AlignRound = 15 + sizeof(HEAP_ENTRY);
201 }
202 else
203 {
204 Heap->AlignMask = (ULONG) ~(sizeof(HEAP_ENTRY) - 1);
205 Heap->AlignRound = 2 * sizeof(HEAP_ENTRY) - 1;
206 }
207
209 Heap->AlignRound += sizeof(HEAP_ENTRY);
210
211 /* Initialise the Heap Segment list */
212 for (Index = 0; Index < HEAP_SEGMENTS; ++Index)
213 Heap->Segments[Index] = NULL;
214
215 /* Initialise the free entry lists. */
216 InitializeListHead(&Heap->FreeLists);
217 RtlInitializeBitMap(&Heap->FreeHintBitmap,
218 (PULONG)&Heap->FreeHints[DeCommitFreeBlockThreshold],
219 DeCommitFreeBlockThreshold);
220 RtlClearAllBits(&Heap->FreeHintBitmap);
221 RtlZeroMemory(&Heap->FreeHints[0], sizeof(Heap->FreeHints[0]) * DeCommitFreeBlockThreshold);
222
223 /* Initialise the Heap Virtual Allocated Blocks list */
224 InitializeListHead(&Heap->VirtualAllocdBlocks);
225
226 /* Initialise the Heap UnCommitted Region lists */
227 InitializeListHead(&Heap->UCRSegments);
228 InitializeListHead(&Heap->UCRList);
229
230 /* Register the initial Heap UnCommitted Region Descriptors */
231 for (Index = 0; Index < NumUCRs; ++Index)
232 InsertTailList(&Heap->UCRList, &UcrDescriptor[Index].ListEntry);
233
234 return STATUS_SUCCESS;
235}
236
239 PHEAP_FREE_ENTRY FreeEntry,
240 SIZE_T BlockSize,
241 BOOLEAN NoFill)
242{
243 ULONG HintIndex, NextHintIndex;
244
245 ASSERT(FreeEntry->Size == BlockSize);
246
247 /* Fill if it's not denied */
248 if (!NoFill)
249 {
250 FreeEntry->Flags &= ~(HEAP_ENTRY_FILL_PATTERN |
253
255 {
256 RtlFillMemoryUlong((PCHAR)(FreeEntry + 1),
257 (BlockSize << HEAP_ENTRY_SHIFT) - sizeof(*FreeEntry),
259
260 FreeEntry->Flags |= HEAP_ENTRY_FILL_PATTERN;
261 }
262 }
263 else
264 {
265 /* Clear out all flags except the last entry one */
266 FreeEntry->Flags &= HEAP_ENTRY_LAST_ENTRY;
267 }
268
269 /* See if this should go to the dedicated list */
270 if (BlockSize > Heap->DeCommitFreeBlockThreshold)
271 {
272 PLIST_ENTRY ListEntry = Heap->FreeHints[0];
273
274 /* Check if we have a hint there */
275 if (ListEntry == NULL)
276 {
277 ASSERT(!RtlTestBit(&Heap->FreeHintBitmap, 0));
278 Heap->FreeHints[0] = &FreeEntry->FreeList;
279 RtlSetBit(&Heap->FreeHintBitmap, 0);
280 InsertTailList(&Heap->FreeLists, &FreeEntry->FreeList);
281 return;
282 }
283
284 ASSERT(RtlTestBit(&Heap->FreeHintBitmap, 0));
285
286 while (ListEntry != &Heap->FreeLists)
287 {
288 PHEAP_FREE_ENTRY PreviousEntry = CONTAINING_RECORD(ListEntry,
290 FreeList);
291 if (PreviousEntry->Size >= BlockSize)
292 {
293 DPRINT("Inserting size %lu before %lu.\n", BlockSize, PreviousEntry->Size);
294 break;
295 }
296
297 ListEntry = ListEntry->Flink;
298 }
299
300 InsertTailList(ListEntry, &FreeEntry->FreeList);
301
302 /* Update our hint if needed */
303 if (Heap->FreeHints[0] == ListEntry)
304 Heap->FreeHints[0] = &FreeEntry->FreeList;
305
306 return;
307 }
308
309 ASSERT(BlockSize >= 2);
310 HintIndex = BlockSize - 1;
311
312 if (Heap->FreeHints[HintIndex] != NULL)
313 {
315
316 /* Insert it after our hint. */
317 InsertHeadList(Heap->FreeHints[HintIndex], &FreeEntry->FreeList);
318
319 return;
320 }
321
322 /* This is the first time we insert such an entry in the list. */
324 if (IsListEmpty(&Heap->FreeLists))
325 {
326 /* First entry inserted in this list ever */
327 InsertHeadList(&Heap->FreeLists, &FreeEntry->FreeList);
329 Heap->FreeHints[HintIndex] = &FreeEntry->FreeList;
330 return;
331 }
332
333 /* Find the closest one */
334 NextHintIndex = RtlFindSetBits(&Heap->FreeHintBitmap, 1, HintIndex);
335 ASSERT(NextHintIndex != 0xFFFFFFFF);
336 if ((NextHintIndex == 0) || (NextHintIndex > HintIndex))
337 {
338 /*
339 * We found a larger entry. Insert this one before.
340 * It is guaranteed to be our successor in the list.
341 */
342 InsertTailList(Heap->FreeHints[NextHintIndex], &FreeEntry->FreeList);
343 }
344 else
345 {
346 /* We only found an entry smaller than us. Then we will be the largest one. */
347 ASSERT(CONTAINING_RECORD(Heap->FreeLists.Blink, HEAP_FREE_ENTRY, FreeList)->Size < BlockSize);
348 InsertTailList(&Heap->FreeLists, &FreeEntry->FreeList);
349 }
350
351 /* Setup our hint */
353 Heap->FreeHints[HintIndex] = &FreeEntry->FreeList;
354}
355
358 PHEAP_FREE_ENTRY FreeEntry,
359 SIZE_T BlockSize)
360{
361 USHORT Size, PreviousSize;
362 UCHAR SegmentOffset, Flags;
364
365 DPRINT("RtlpInsertFreeBlock(%p %p %x)\n", Heap, FreeEntry, BlockSize);
366
367 /* Increase the free size counter */
368 Heap->TotalFreeSize += BlockSize;
369
370 /* Remember certain values */
371 Flags = FreeEntry->Flags;
372 PreviousSize = FreeEntry->PreviousSize;
373 SegmentOffset = FreeEntry->SegmentOffset;
374 Segment = Heap->Segments[SegmentOffset];
375
376 /* Process it */
377 while (BlockSize)
378 {
379 /* Check for the max size */
380 if (BlockSize > HEAP_MAX_BLOCK_SIZE)
381 {
383
384 /* Special compensation if it goes above limit just by 1 */
385 if (BlockSize == (HEAP_MAX_BLOCK_SIZE + 1))
386 Size -= 16;
387
388 FreeEntry->Flags = 0;
389 }
390 else
391 {
392 Size = (USHORT)BlockSize;
393 FreeEntry->Flags = Flags;
394 }
395
396 /* Change its size and insert it into a free list */
397 FreeEntry->Size = Size;
398 FreeEntry->PreviousSize = PreviousSize;
399 FreeEntry->SegmentOffset = SegmentOffset;
400
401 /* Call a helper to actually insert the block */
402 RtlpInsertFreeBlockHelper(Heap, FreeEntry, Size, FALSE);
403
404 /* Update sizes */
405 PreviousSize = Size;
406 BlockSize -= Size;
407
408 /* Go to the next entry */
409 FreeEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeEntry + Size);
410
411 /* Check if that's all */
412 if ((PHEAP_ENTRY)FreeEntry >= Segment->LastValidEntry) return;
413 }
414
415 /* Update previous size if needed */
417 FreeEntry->PreviousSize = PreviousSize;
418}
419
420static
421VOID
423 PHEAP_FREE_ENTRY FreeEntry,
424 BOOLEAN NoFill)
425{
426 SIZE_T Result, RealSize;
428
429 /* Remove the free block */
430 if (FreeEntry->Size > Heap->DeCommitFreeBlockThreshold)
431 HintIndex = 0;
432 else
433 HintIndex = FreeEntry->Size - 1;
434
436
437 /* Are we removing the hint entry for this size ? */
438 if (Heap->FreeHints[HintIndex] == &FreeEntry->FreeList)
439 {
440 PHEAP_FREE_ENTRY NewHintEntry = NULL;
441 if (FreeEntry->FreeList.Flink != &Heap->FreeLists)
442 {
443 NewHintEntry = CONTAINING_RECORD(FreeEntry->FreeList.Flink,
445 FreeList);
446 /*
447 * In non-dedicated list, we just put the next entry as hint.
448 * For the dedicated ones, we take care of putting entries of the right size hint.
449 */
450 if ((HintIndex != 0) && (NewHintEntry->Size != FreeEntry->Size))
451 {
452 /* Of course this must be a larger one after us */
453 ASSERT(NewHintEntry->Size > FreeEntry->Size);
454 NewHintEntry = NULL;
455 }
456 }
457
458 /* Replace the hint, if we can */
459 if (NewHintEntry != NULL)
460 {
461 Heap->FreeHints[HintIndex] = &NewHintEntry->FreeList;
462 }
463 else
464 {
465 Heap->FreeHints[HintIndex] = NULL;
467 }
468 }
469
470 RemoveEntryList(&FreeEntry->FreeList);
471
472 /* Fill with pattern if necessary */
473 if (!NoFill &&
474 (FreeEntry->Flags & HEAP_ENTRY_FILL_PATTERN))
475 {
476 RealSize = (FreeEntry->Size << HEAP_ENTRY_SHIFT) - sizeof(*FreeEntry);
477
478 /* Deduct extra stuff from block's real size */
479 if (FreeEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT &&
480 RealSize > sizeof(HEAP_FREE_ENTRY_EXTRA))
481 {
482 RealSize -= sizeof(HEAP_FREE_ENTRY_EXTRA);
483 }
484
485 /* Check if the free filler is intact */
486 Result = RtlCompareMemoryUlong((PCHAR)(FreeEntry + 1),
487 RealSize,
489
490 if (Result != RealSize)
491 {
492 DPRINT1("Free heap block %p modified at %p after it was freed\n",
493 FreeEntry,
494 (PCHAR)(FreeEntry + 1) + Result);
495 }
496 }
497}
498
501{
502 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry;
503
504 /* Get pointer to the containing record */
505 VirtualEntry = CONTAINING_RECORD(HeapEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
506 ASSERT(VirtualEntry->BusyBlock.Size >= sizeof(HEAP_VIRTUAL_ALLOC_ENTRY));
507
508 /* Restore the real size */
509 return VirtualEntry->CommitSize - HeapEntry->Size;
510}
511
514{
516 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
517 PHEAP_UCR_SEGMENT UcrSegment;
518 PHEAP Heap = Segment->Heap;
522
523 DPRINT("RtlpCreateUnCommittedRange(%p)\n", Segment);
524
525 /* Check if we have unused UCRs */
526 if (IsListEmpty(&Heap->UCRList))
527 {
528 /* Get a pointer to the first UCR segment */
529 UcrSegment = CONTAINING_RECORD(Heap->UCRSegments.Flink, HEAP_UCR_SEGMENT, ListEntry);
530
531 /* Check the list of UCR segments */
532 if (IsListEmpty(&Heap->UCRSegments) ||
533 UcrSegment->ReservedSize == UcrSegment->CommittedSize)
534 {
535 /* We need to create a new one. Reserve 16 pages for it */
536 UcrSegment = NULL;
537 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
538 (PVOID *)&UcrSegment,
539 0,
543
544 if (!NT_SUCCESS(Status)) return NULL;
545
546 /* Commit one page */
547 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
548 (PVOID *)&UcrSegment,
549 0,
550 &CommitSize,
553
554 if (!NT_SUCCESS(Status))
555 {
556 /* Release reserved memory */
557 ZwFreeVirtualMemory(NtCurrentProcess(),
558 (PVOID *)&UcrSegment,
561 return NULL;
562 }
563
564 /* Set it's data */
565 UcrSegment->ReservedSize = ReserveSize;
566 UcrSegment->CommittedSize = CommitSize;
567
568 /* Add it to the head of the list */
569 InsertHeadList(&Heap->UCRSegments, &UcrSegment->ListEntry);
570
571 /* Get a pointer to the first available UCR descriptor */
572 UcrDescriptor = (PHEAP_UCR_DESCRIPTOR)(UcrSegment + 1);
573 }
574 else
575 {
576 /* It's possible to use existing UCR segment. Commit one more page */
577 UcrDescriptor = (PHEAP_UCR_DESCRIPTOR)((PCHAR)UcrSegment + UcrSegment->CommittedSize);
578 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
579 (PVOID *)&UcrDescriptor,
580 0,
581 &CommitSize,
584
585 if (!NT_SUCCESS(Status)) return NULL;
586
587 ASSERT((PCHAR)UcrDescriptor == ((PCHAR)UcrSegment + UcrSegment->CommittedSize));
588
589 /* Update sizes */
590 UcrSegment->CommittedSize += CommitSize;
591 }
592
593 /* There is a whole bunch of new UCR descriptors. Put them into the unused list */
594 while ((PCHAR)(UcrDescriptor + 1) <= (PCHAR)UcrSegment + UcrSegment->CommittedSize)
595 {
596 InsertTailList(&Heap->UCRList, &UcrDescriptor->ListEntry);
597 UcrDescriptor++;
598 }
599 }
600
601 /* There are unused UCRs, just get the first one */
602 Entry = RemoveHeadList(&Heap->UCRList);
603 UcrDescriptor = CONTAINING_RECORD(Entry, HEAP_UCR_DESCRIPTOR, ListEntry);
604 return UcrDescriptor;
605}
606
609 PHEAP_UCR_DESCRIPTOR UcrDescriptor)
610{
611 /* Zero it out */
612 UcrDescriptor->Address = NULL;
613 UcrDescriptor->Size = 0;
614
615 /* Put it into the heap's list of unused UCRs */
616 InsertHeadList(&Segment->Heap->UCRList, &UcrDescriptor->ListEntry);
617}
618
622 SIZE_T Size)
623{
624 PLIST_ENTRY Current;
625 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
626
627 DPRINT("RtlpInsertUnCommittedPages(%p %08Ix %Ix)\n", Segment, Address, Size);
628
629 /* Go through the list of UCR descriptors, they are sorted from lowest address
630 to the highest */
631 Current = Segment->UCRSegmentList.Flink;
632 while (Current != &Segment->UCRSegmentList)
633 {
634 UcrDescriptor = CONTAINING_RECORD(Current, HEAP_UCR_DESCRIPTOR, SegmentEntry);
635
636 if ((ULONG_PTR)UcrDescriptor->Address > Address)
637 {
638 /* Check for a really lucky case */
639 if ((Address + Size) == (ULONG_PTR)UcrDescriptor->Address)
640 {
641 /* Exact match */
642 UcrDescriptor->Address = (PVOID)Address;
643 UcrDescriptor->Size += Size;
644 return;
645 }
646
647 /* We found the block before which the new one should go */
648 break;
649 }
650 else if (((ULONG_PTR)UcrDescriptor->Address + UcrDescriptor->Size) == Address)
651 {
652 /* Modify this entry */
653 Address = (ULONG_PTR)UcrDescriptor->Address;
654 Size += UcrDescriptor->Size;
655
656 /* Advance to the next descriptor */
657 Current = Current->Flink;
658
659 /* Remove the current descriptor from the list and destroy it */
660 RemoveEntryList(&UcrDescriptor->SegmentEntry);
661 RtlpDestroyUnCommittedRange(Segment, UcrDescriptor);
662
663 Segment->NumberOfUnCommittedRanges--;
664 }
665 else
666 {
667 /* Advance to the next descriptor */
668 Current = Current->Flink;
669 }
670 }
671
672 /* Create a new UCR descriptor */
673 UcrDescriptor = RtlpCreateUnCommittedRange(Segment);
674 if (!UcrDescriptor) return;
675
676 UcrDescriptor->Address = (PVOID)Address;
677 UcrDescriptor->Size = Size;
678
679 /* "Current" is the descriptor before which our one should go */
680 InsertTailList(Current, &UcrDescriptor->SegmentEntry);
681
682 DPRINT("Added segment UCR with base %08Ix, size 0x%x\n", Address, Size);
683
684 /* Increase counters */
685 Segment->NumberOfUnCommittedRanges++;
686}
687
688static
693 PVOID AddressRequested)
694{
695 PLIST_ENTRY Current;
697
698 DPRINT("RtlpFindAndCommitPages(%p %p %Ix %p)\n", Heap, Segment, *Size, AddressRequested);
699
700 /* Go through UCRs in a segment */
701 Current = Segment->UCRSegmentList.Flink;
702 while (Current != &Segment->UCRSegmentList)
703 {
704 PHEAP_UCR_DESCRIPTOR UcrDescriptor = CONTAINING_RECORD(Current, HEAP_UCR_DESCRIPTOR, SegmentEntry);
705
706 /* Check if we can use that one right away */
707 if (UcrDescriptor->Size >= *Size &&
708 (UcrDescriptor->Address == AddressRequested || !AddressRequested))
709 {
710 PHEAP_ENTRY GuardEntry, FreeEntry;
711 PVOID Address = UcrDescriptor->Address;
712
713 /* Commit it */
714 if (Heap->CommitRoutine)
715 {
716 Status = Heap->CommitRoutine(Heap, &Address, Size);
717 }
718 else
719 {
720 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
721 &Address,
722 0,
723 Size,
726 }
727
728 DPRINT("Committed %Iu bytes at base %08Ix, UCR size is %lu\n", *Size, Address, UcrDescriptor->Size);
729
730 /* Fail in unsuccessful case */
731 if (!NT_SUCCESS(Status))
732 {
733 DPRINT1("Committing page failed with status 0x%08X\n", Status);
734 return NULL;
735 }
736
737 /* Update tracking numbers */
738 Segment->NumberOfUnCommittedPages -= (ULONG)(*Size / PAGE_SIZE);
739
740 /* Update UCR descriptor */
741 UcrDescriptor->Address = (PVOID)((ULONG_PTR)UcrDescriptor->Address + *Size);
742 UcrDescriptor->Size -= *Size;
743
744 /* Grab the previous guard entry */
745 GuardEntry = (PHEAP_ENTRY)Address - 1;
746 ASSERT(GuardEntry->Flags & HEAP_ENTRY_LAST_ENTRY);
747 ASSERT(GuardEntry->Flags & HEAP_ENTRY_BUSY);
748 ASSERT(GuardEntry->Size == 1);
749
750 /* Did we have a double guard entry ? */
751 if (GuardEntry->PreviousSize == 1)
752 {
753 /* Use the one before instead */
754 GuardEntry--;
755
756 ASSERT(GuardEntry->Flags & HEAP_ENTRY_LAST_ENTRY);
757 ASSERT(GuardEntry->Flags & HEAP_ENTRY_BUSY);
758 ASSERT(GuardEntry->Size == 1);
759
760 /* We gain one slot more */
762 }
763
764 /* This will become our returned free entry.
765 * Now we can make it span the whole committed range.
766 * But we keep one slot for a guard entry, if needed.
767 */
768 FreeEntry = GuardEntry;
769
770 FreeEntry->Flags &= ~(HEAP_ENTRY_BUSY | HEAP_ENTRY_LAST_ENTRY);
771 FreeEntry->Size = (*Size) >> HEAP_ENTRY_SHIFT;
772
773 DPRINT("Updating UcrDescriptor %p, new Address %p, size %lu\n",
774 UcrDescriptor, UcrDescriptor->Address, UcrDescriptor->Size);
775
776 /* Check if anything left in this UCR */
777 if (UcrDescriptor->Size == 0)
778 {
779 /* It's fully exhausted. Take the guard entry for us */
780 FreeEntry->Size++;
782
783 ASSERT((FreeEntry + FreeEntry->Size) == UcrDescriptor->Address);
784
785 /* Check if this is the end of the segment */
786 if(UcrDescriptor->Address == Segment->LastValidEntry)
787 {
788 FreeEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
789 }
790 else
791 {
792 PHEAP_ENTRY NextEntry = UcrDescriptor->Address;
793
794 /* We should not have a UCR right behind us */
795 ASSERT((UcrDescriptor->SegmentEntry.Flink == &Segment->UCRSegmentList)
796 || (CONTAINING_RECORD(UcrDescriptor->SegmentEntry.Flink, HEAP_UCR_DESCRIPTOR, SegmentEntry)->Address > UcrDescriptor->Address));
797
798 ASSERT(NextEntry->PreviousSize == 0);
799 ASSERT(NextEntry == FreeEntry + FreeEntry->Size);
800 NextEntry->PreviousSize = FreeEntry->Size;
801 }
802
803 /* This UCR needs to be removed because it became useless */
804 RemoveEntryList(&UcrDescriptor->SegmentEntry);
805
806 RtlpDestroyUnCommittedRange(Segment, UcrDescriptor);
807 Segment->NumberOfUnCommittedRanges--;
808 }
809 else
810 {
811 /* Setup a guard entry */
812 GuardEntry = (PHEAP_ENTRY)UcrDescriptor->Address - 1;
813 ASSERT(GuardEntry == FreeEntry + FreeEntry->Size);
814 GuardEntry->Flags = HEAP_ENTRY_LAST_ENTRY | HEAP_ENTRY_BUSY;
815 GuardEntry->Size = 1;
816 GuardEntry->PreviousSize = FreeEntry->Size;
817 GuardEntry->SegmentOffset = FreeEntry->SegmentOffset;
818 DPRINT("Setting %p as UCR guard entry.\n", GuardEntry);
819 }
820
821 /* We're done */
822 return (PHEAP_FREE_ENTRY)FreeEntry;
823 }
824
825 /* Advance to the next descriptor */
826 Current = Current->Flink;
827 }
828
829 return NULL;
830}
831
832static
833VOID
835 PHEAP_FREE_ENTRY FreeEntry,
836 SIZE_T Size)
837{
839 PHEAP_ENTRY NextEntry, GuardEntry;
840 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
841 SIZE_T PrecedingSize, DecommitSize;
842 ULONG_PTR DecommitBase, DecommitEnd;
844
845 DPRINT("Decommitting %p %p %x\n", Heap, FreeEntry, Size);
846
847 /* We can't decommit if there is a commit routine! */
848 if (Heap->CommitRoutine)
849 {
850 /* Just add it back the usual way */
851 RtlpInsertFreeBlock(Heap, FreeEntry, Size);
852 return;
853 }
854
855 /* Get the segment */
856 Segment = Heap->Segments[FreeEntry->SegmentOffset];
857
858 /* Get the preceding entry */
859 DecommitBase = ROUND_UP(FreeEntry, PAGE_SIZE);
860 PrecedingSize = (PHEAP_ENTRY)DecommitBase - (PHEAP_ENTRY)FreeEntry;
861
862 if (PrecedingSize == 0)
863 {
864 /* We need some space in order to insert our guard entry */
865 DecommitBase += PAGE_SIZE;
866 PrecedingSize += PAGE_SIZE >> HEAP_ENTRY_SHIFT;
867 }
868
869 /* Get the entry after this one. */
870
871 /* Do we really have a next entry */
873 {
874 /* No, Decommit till the next UCR. */
875 DecommitEnd = PAGE_ROUND_UP((PHEAP_ENTRY)FreeEntry + FreeEntry->Size);
876 NextEntry = NULL;
877 }
878 else
879 {
880 NextEntry = (PHEAP_ENTRY)FreeEntry + Size;
881 DecommitEnd = PAGE_ROUND_DOWN(NextEntry);
882
883 /* Can we make a free entry out of what's left ? */
884 if ((NextEntry - (PHEAP_ENTRY)DecommitEnd) == 1)
885 {
886 /* Nope. Let's keep one page before this */
887 DecommitEnd -= PAGE_SIZE;
888 }
889 }
890
891 if (DecommitEnd <= DecommitBase)
892 {
893 /* There's nothing left to decommit. */
894 RtlpInsertFreeBlock(Heap, FreeEntry, Size);
895 return;
896 }
897
898 DecommitSize = DecommitEnd - DecommitBase;
899
900 /* A decommit is necessary. Create a UCR descriptor */
901 UcrDescriptor = RtlpCreateUnCommittedRange(Segment);
902 if (!UcrDescriptor)
903 {
904 DPRINT1("HEAP: Failed to create UCR descriptor\n");
905 RtlpInsertFreeBlock(Heap, FreeEntry, PrecedingSize);
906 return;
907 }
908
909 /* Decommit the memory */
910 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
911 (PVOID *)&DecommitBase,
912 &DecommitSize,
914 ASSERT((DecommitBase + DecommitSize) == DecommitEnd);
915
916 /* Delete that UCR. This is needed to assure there is an unused UCR entry in the list */
917 RtlpDestroyUnCommittedRange(Segment, UcrDescriptor);
918
919 if (!NT_SUCCESS(Status))
920 {
921 RtlpInsertFreeBlock(Heap, FreeEntry, Size);
922 return;
923 }
924
925 /* Insert uncommitted pages */
926 RtlpInsertUnCommittedPages(Segment, DecommitBase, DecommitSize);
927 Segment->NumberOfUnCommittedPages += (ULONG)(DecommitSize / PAGE_SIZE);
928
929 /* Insert our guard entry before this */
930 GuardEntry = (PHEAP_ENTRY)DecommitBase - 1;
931 GuardEntry->Size = 1;
932 GuardEntry->Flags = HEAP_ENTRY_BUSY | HEAP_ENTRY_LAST_ENTRY;
933 GuardEntry->SegmentOffset = FreeEntry->SegmentOffset;
934 DPRINT("Setting %p as UCR guard entry.\n", GuardEntry);
935
936 /* Now see what's really behind us */
937 PrecedingSize--;
938 switch (PrecedingSize)
939 {
940 case 1:
941 /* No space left for a free entry. Make this another guard entry */
942 GuardEntry->PreviousSize = 1;
943 GuardEntry--;
944 GuardEntry->Size = 1;
945 GuardEntry->Flags = HEAP_ENTRY_BUSY | HEAP_ENTRY_LAST_ENTRY;
946 GuardEntry->SegmentOffset = FreeEntry->SegmentOffset;
947 /* Fall-through */
948 case 0:
949 /* There was just enough space four our guard entry */
950 ASSERT((PHEAP_ENTRY)FreeEntry == GuardEntry);
951 GuardEntry->PreviousSize = FreeEntry->PreviousSize;
952 break;
953 default:
954 /* We can insert this as a free entry */
955 GuardEntry->PreviousSize = PrecedingSize;
956 FreeEntry->Size = PrecedingSize;
957 FreeEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
958 FreeEntry = RtlpCoalesceFreeBlocks(Heap, FreeEntry, &PrecedingSize, FALSE);
959 RtlpInsertFreeBlock(Heap, FreeEntry, PrecedingSize);
960 break;
961 }
962
963 /* Now the next one */
964 if (NextEntry)
965 {
966 ASSERT((PHEAP_ENTRY)DecommitEnd <= NextEntry);
967
968 SIZE_T NextSize = NextEntry - (PHEAP_ENTRY)DecommitEnd;
969 if (NextSize)
970 {
971 PHEAP_FREE_ENTRY NextFreeEntry = (PHEAP_FREE_ENTRY)DecommitEnd;
972
973 /* Make sure this is all valid */
974 ASSERT((PHEAP_ENTRY)DecommitEnd < Segment->LastValidEntry);
975 ASSERT(NextSize >= 2);
976
977 /* Adjust size of this free entry and insert it */
978 NextFreeEntry->Flags = 0;
979 NextFreeEntry->PreviousSize = 0;
980 NextFreeEntry->SegmentOffset = Segment->Entry.SegmentOffset;
981 NextFreeEntry->Size = (USHORT)NextSize;
982
983 NextEntry->PreviousSize = NextSize;
984 ASSERT(NextEntry == (PHEAP_ENTRY)NextFreeEntry + NextFreeEntry->Size);
985
986 NextFreeEntry = RtlpCoalesceFreeBlocks(Heap, NextFreeEntry, &NextSize, FALSE);
987 RtlpInsertFreeBlock(Heap, NextFreeEntry, NextSize);
988 }
989 else
990 {
991 /* This one must be at the beginning of a page */
992 ASSERT(NextEntry == (PHEAP_ENTRY)PAGE_ROUND_DOWN(NextEntry));
993 /* And we must have a gap betwwen */
994 ASSERT(NextEntry > (PHEAP_ENTRY)DecommitBase);
995 NextEntry->PreviousSize = 0;
996 }
997 }
998}
999
1001NTAPI
1004 IN UCHAR SegmentIndex,
1005 IN ULONG SegmentFlags,
1006 IN SIZE_T SegmentReserve,
1007 IN SIZE_T SegmentCommit)
1008{
1009 /* Preconditions */
1010 ASSERT(Heap != NULL);
1011 ASSERT(Segment != NULL);
1012 ASSERT(SegmentCommit >= PAGE_SIZE);
1013 ASSERT(ROUND_DOWN(SegmentCommit, PAGE_SIZE) == SegmentCommit);
1014 ASSERT(SegmentReserve >= SegmentCommit);
1015 ASSERT(ROUND_DOWN(SegmentReserve, PAGE_SIZE) == SegmentReserve);
1016
1017 DPRINT("RtlpInitializeHeapSegment(%p %p %x %x %lx %lx)\n", Heap, Segment, SegmentIndex, SegmentFlags, SegmentReserve, SegmentCommit);
1018
1019 /* Initialise the Heap Entry header if this is not the first Heap Segment */
1020 if ((PHEAP_SEGMENT) (Heap) != Segment)
1021 {
1022 Segment->Entry.Size = ROUND_UP(sizeof(HEAP_SEGMENT), sizeof(HEAP_ENTRY)) >> HEAP_ENTRY_SHIFT;
1023 Segment->Entry.Flags = HEAP_ENTRY_BUSY;
1024 Segment->Entry.SmallTagIndex = LOBYTE(Segment->Entry.Size) ^ HIBYTE(Segment->Entry.Size) ^ Segment->Entry.Flags;
1025 Segment->Entry.PreviousSize = 0;
1026 Segment->Entry.SegmentOffset = SegmentIndex;
1027 Segment->Entry.UnusedBytes = 0;
1028 }
1029
1030 /* Sanity check */
1031 ASSERT((Segment->Entry.Size << HEAP_ENTRY_SHIFT) <= PAGE_SIZE);
1032
1033 /* Initialise the Heap Segment header */
1034 Segment->SegmentSignature = HEAP_SEGMENT_SIGNATURE;
1035 Segment->SegmentFlags = SegmentFlags;
1036 Segment->Heap = Heap;
1037 Heap->Segments[SegmentIndex] = Segment;
1038
1039 /* Initialise the Heap Segment location information */
1040 Segment->BaseAddress = Segment;
1041 Segment->NumberOfPages = (ULONG)(SegmentReserve >> PAGE_SHIFT);
1042
1043 /* Initialise the Heap Entries contained within the Heap Segment */
1044 Segment->FirstEntry = &Segment->Entry + Segment->Entry.Size;
1045 Segment->LastValidEntry = (PHEAP_ENTRY)((ULONG_PTR)Segment + SegmentReserve);
1046
1047 /* Initialise the Heap Segment UnCommitted Range information */
1048 Segment->NumberOfUnCommittedPages = (ULONG)((SegmentReserve - SegmentCommit) >> PAGE_SHIFT);
1049 Segment->NumberOfUnCommittedRanges = 0;
1050 InitializeListHead(&Segment->UCRSegmentList);
1051
1052 /* We must have space for a guard entry ! */
1053 ASSERT (((SegmentCommit >> HEAP_ENTRY_SHIFT) > Segment->Entry.Size) || (Segment->NumberOfUnCommittedPages == 0));
1054
1055 if (((SIZE_T)Segment->Entry.Size << HEAP_ENTRY_SHIFT) < SegmentCommit)
1056 {
1057 PHEAP_ENTRY FreeEntry = NULL;
1058
1059 if (Segment->NumberOfUnCommittedPages != 0)
1060 {
1061 /* Ensure we put our guard entry at the end of the last committed page */
1062 PHEAP_ENTRY GuardEntry = &Segment->Entry + (SegmentCommit >> HEAP_ENTRY_SHIFT) - 1;
1063
1064 ASSERT(GuardEntry > &Segment->Entry);
1065 GuardEntry->Size = 1;
1066 GuardEntry->Flags = HEAP_ENTRY_BUSY | HEAP_ENTRY_LAST_ENTRY;
1067 GuardEntry->SegmentOffset = SegmentIndex;
1068 GuardEntry->PreviousSize = GuardEntry - Segment->FirstEntry;
1069
1070 /* Chack what is left behind us */
1071 switch (GuardEntry->PreviousSize)
1072 {
1073 case 1:
1074 /* There is not enough space for a free entry. Double the guard entry */
1075 GuardEntry--;
1076 GuardEntry->Size = 1;
1077 GuardEntry->Flags = HEAP_ENTRY_BUSY | HEAP_ENTRY_LAST_ENTRY;
1078 GuardEntry->SegmentOffset = SegmentIndex;
1079 DPRINT1("Setting %p as UCR guard entry.\n", GuardEntry);
1080 /* Fall through */
1081 case 0:
1082 ASSERT(GuardEntry == Segment->FirstEntry);
1083 GuardEntry->PreviousSize = Segment->Entry.Size;
1084 break;
1085 default:
1086 /* There will be a free entry between the segment and the guard entry */
1087 FreeEntry = Segment->FirstEntry;
1088 FreeEntry->PreviousSize = Segment->Entry.Size;
1089 FreeEntry->SegmentOffset = SegmentIndex;
1090 FreeEntry->Size = GuardEntry->PreviousSize;
1091 FreeEntry->Flags = 0;
1092 break;
1093 }
1094 }
1095 else
1096 {
1097 /* Prepare a Free Heap Entry header */
1098 FreeEntry = Segment->FirstEntry;
1099 FreeEntry->PreviousSize = Segment->Entry.Size;
1100 FreeEntry->SegmentOffset = SegmentIndex;
1101 FreeEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
1102 FreeEntry->Size = (SegmentCommit >> HEAP_ENTRY_SHIFT) - Segment->Entry.Size;
1103 }
1104
1105 /* Register the Free Heap Entry */
1106 if (FreeEntry)
1107 RtlpInsertFreeBlock(Heap, (PHEAP_FREE_ENTRY)FreeEntry, FreeEntry->Size);
1108 }
1109
1110 /* Register the UnCommitted Range of the Heap Segment */
1111 if (Segment->NumberOfUnCommittedPages != 0)
1112 RtlpInsertUnCommittedPages(Segment, (ULONG_PTR) (Segment) + SegmentCommit, SegmentReserve - SegmentCommit);
1113
1114 return STATUS_SUCCESS;
1115}
1116
1117VOID NTAPI
1119{
1122 SIZE_T Size = 0;
1123
1124 /* Make sure it's not user allocated */
1125 if (Segment->SegmentFlags & HEAP_USER_ALLOCATED) return;
1126
1127 BaseAddress = Segment->BaseAddress;
1128 DPRINT("Destroying segment %p, BA %p\n", Segment, BaseAddress);
1129
1130 /* Release virtual memory */
1131 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
1132 &BaseAddress,
1133 &Size,
1134 MEM_RELEASE);
1135
1136 if (!NT_SUCCESS(Status))
1137 {
1138 DPRINT1("HEAP: Failed to release segment's memory with status 0x%08X\n", Status);
1139 }
1140}
1141
1144{
1146 return NULL;
1147}
1148
1151 PHEAP_FREE_ENTRY FreeEntry,
1152 PSIZE_T FreeSize,
1154{
1155 PHEAP_FREE_ENTRY CurrentEntry, NextEntry;
1156 UCHAR SegmentOffset;
1157
1158 /* Get the previous entry */
1159 CurrentEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeEntry - FreeEntry->PreviousSize);
1160
1161 /* Check it */
1162 if (CurrentEntry != FreeEntry &&
1163 !(CurrentEntry->Flags & HEAP_ENTRY_BUSY) &&
1164 (*FreeSize + CurrentEntry->Size) <= HEAP_MAX_BLOCK_SIZE)
1165 {
1166 ASSERT(FreeEntry->PreviousSize == CurrentEntry->Size);
1167
1168 /* Remove it if asked for */
1169 if (Remove)
1170 {
1171 RtlpRemoveFreeBlock(Heap, FreeEntry, FALSE);
1172 Heap->TotalFreeSize -= FreeEntry->Size;
1173
1174 /* Remove it only once! */
1175 Remove = FALSE;
1176 }
1177
1178 /* Remove previous entry too */
1179 RtlpRemoveFreeBlock(Heap, CurrentEntry, FALSE);
1180
1181 /* Copy flags */
1182 CurrentEntry->Flags = FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY;
1183
1184 /* Advance FreeEntry and update sizes */
1185 FreeEntry = CurrentEntry;
1186 *FreeSize = *FreeSize + CurrentEntry->Size;
1187 Heap->TotalFreeSize -= CurrentEntry->Size;
1188 FreeEntry->Size = (USHORT)(*FreeSize);
1189
1190 /* Also update previous size if needed */
1191 if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
1192 {
1193 ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = (USHORT)(*FreeSize);
1194 }
1195 else
1196 {
1197 SegmentOffset = FreeEntry->SegmentOffset;
1198 ASSERT(SegmentOffset < HEAP_SEGMENTS);
1199 }
1200 }
1201
1202 /* Check the next block if it exists */
1203 if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
1204 {
1205 NextEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeEntry + *FreeSize);
1206
1207 if (!(NextEntry->Flags & HEAP_ENTRY_BUSY) &&
1208 NextEntry->Size + *FreeSize <= HEAP_MAX_BLOCK_SIZE)
1209 {
1210 ASSERT(*FreeSize == NextEntry->PreviousSize);
1211
1212 /* Remove it if asked for */
1213 if (Remove)
1214 {
1215 RtlpRemoveFreeBlock(Heap, FreeEntry, FALSE);
1216 Heap->TotalFreeSize -= FreeEntry->Size;
1217 }
1218
1219 /* Copy flags */
1220 FreeEntry->Flags = NextEntry->Flags & HEAP_ENTRY_LAST_ENTRY;
1221
1222 /* Remove next entry now */
1223 RtlpRemoveFreeBlock(Heap, NextEntry, FALSE);
1224
1225 /* Update sizes */
1226 *FreeSize = *FreeSize + NextEntry->Size;
1227 Heap->TotalFreeSize -= NextEntry->Size;
1228 FreeEntry->Size = (USHORT)(*FreeSize);
1229
1230 /* Also update previous size if needed */
1231 if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
1232 {
1233 ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = (USHORT)(*FreeSize);
1234 }
1235 else
1236 {
1237 SegmentOffset = FreeEntry->SegmentOffset;
1238 ASSERT(SegmentOffset < HEAP_SEGMENTS);
1239 }
1240 }
1241 }
1242 return FreeEntry;
1243}
1244
1245static
1248 SIZE_T Size)
1249{
1250 ULONG Pages;
1251 UCHAR Index, EmptyIndex;
1252 SIZE_T FreeSize, CommitSize, ReserveSize;
1254 PHEAP_FREE_ENTRY FreeEntry;
1256
1257 DPRINT("RtlpExtendHeap(%p %x)\n", Heap, Size);
1258
1259 /* Calculate amount in pages */
1260 Pages = (ULONG)((Size + PAGE_SIZE - 1) / PAGE_SIZE);
1261 FreeSize = Pages * PAGE_SIZE;
1262 DPRINT("Pages %x, FreeSize %x. Going through segments...\n", Pages, FreeSize);
1263
1264 /* Find an empty segment */
1265 EmptyIndex = HEAP_SEGMENTS;
1266 for (Index = 0; Index < HEAP_SEGMENTS; Index++)
1267 {
1268 Segment = Heap->Segments[Index];
1269
1270 if (Segment) DPRINT("Segment[%u] %p with NOUCP %x\n", Index, Segment, Segment->NumberOfUnCommittedPages);
1271
1272 /* Check if its size suits us */
1273 if (Segment &&
1274 Pages <= Segment->NumberOfUnCommittedPages)
1275 {
1276 DPRINT("This segment is suitable\n");
1277
1278 /* Commit needed amount */
1279 FreeEntry = RtlpFindAndCommitPages(Heap, Segment, &FreeSize, NULL);
1280
1281 /* Coalesce it with adjacent entries */
1282 if (FreeEntry)
1283 {
1284 FreeSize = FreeSize >> HEAP_ENTRY_SHIFT;
1285 FreeEntry = RtlpCoalesceFreeBlocks(Heap, FreeEntry, &FreeSize, FALSE);
1286 RtlpInsertFreeBlock(Heap, FreeEntry, FreeSize);
1287 return FreeEntry;
1288 }
1289 }
1290 else if (!Segment &&
1291 EmptyIndex == HEAP_SEGMENTS)
1292 {
1293 /* Remember the first unused segment index */
1294 EmptyIndex = Index;
1295 }
1296 }
1297
1298 /* No luck, need to grow the heap */
1299 if ((Heap->Flags & HEAP_GROWABLE) &&
1300 (EmptyIndex != HEAP_SEGMENTS))
1301 {
1302 Segment = NULL;
1303
1304 /* Reserve the memory */
1305 if ((Size + PAGE_SIZE) <= Heap->SegmentReserve)
1307 else
1309
1310 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
1311 (PVOID)&Segment,
1312 0,
1313 &ReserveSize,
1316
1317 /* If it failed, retry again with a half division algorithm */
1318 while (!NT_SUCCESS(Status) &&
1320 {
1321 ReserveSize /= 2;
1322
1323 if (ReserveSize < (Size + PAGE_SIZE))
1325
1326 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
1327 (PVOID)&Segment,
1328 0,
1329 &ReserveSize,
1332 }
1333
1334 /* Proceed only if it's success */
1335 if (NT_SUCCESS(Status))
1336 {
1337 Heap->SegmentReserve += ReserveSize;
1338
1339 /* Now commit the memory */
1340 if ((Size + PAGE_SIZE) <= Heap->SegmentCommit)
1341 CommitSize = Heap->SegmentCommit;
1342 else
1344
1345 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
1346 (PVOID)&Segment,
1347 0,
1348 &CommitSize,
1349 MEM_COMMIT,
1351
1352 DPRINT("Committed %lu bytes at base %p\n", CommitSize, Segment);
1353
1354 /* Initialize heap segment if commit was successful */
1355 if (NT_SUCCESS(Status))
1357
1358 /* If everything worked - cool */
1359 if (NT_SUCCESS(Status)) return (PHEAP_FREE_ENTRY)Segment->FirstEntry;
1360
1361 DPRINT1("Committing failed with status 0x%08X\n", Status);
1362
1363 /* Nope, we failed. Free memory */
1364 ZwFreeVirtualMemory(NtCurrentProcess(),
1365 (PVOID)&Segment,
1366 &ReserveSize,
1367 MEM_RELEASE);
1368 }
1369 else
1370 {
1371 DPRINT1("Reserving failed with status 0x%08X\n", Status);
1372 }
1373 }
1374
1375 if (RtlpGetMode() == UserMode)
1376 {
1377 /* If coalescing on free is disabled in usermode, then do it here */
1379 {
1380 FreeEntry = RtlpCoalesceHeap(Heap);
1381
1382 /* If it's a suitable one - return it */
1383 if (FreeEntry &&
1384 FreeEntry->Size >= Size)
1385 {
1386 return FreeEntry;
1387 }
1388 }
1389 }
1390
1391 return NULL;
1392}
1393
1394/***********************************************************************
1395 * RtlCreateHeap
1396 * RETURNS
1397 * Handle of heap: Success
1398 * NULL: Failure
1399 *
1400 * @implemented
1401 */
1404 PVOID Addr,
1405 SIZE_T TotalSize,
1407 PVOID Lock,
1409{
1410 PVOID CommittedAddress = NULL, UncommittedAddress = NULL;
1411 PHEAP Heap = NULL;
1412 RTL_HEAP_PARAMETERS SafeParams = {0};
1413 ULONG_PTR MaximumUserModeAddress;
1414 SYSTEM_BASIC_INFORMATION SystemInformation;
1415 MEMORY_BASIC_INFORMATION MemoryInfo;
1416 ULONG NtGlobalFlags = RtlGetNtGlobalFlags();
1417 ULONG HeapSegmentFlags = 0;
1419 ULONG MaxBlockSize;
1420
1421 /* Check for a special heap */
1422 if (RtlpPageHeapEnabled && !Addr && !Lock)
1423 {
1424 Heap = RtlpPageHeapCreate(Flags, Addr, TotalSize, CommitSize, Lock, Parameters);
1425 if (Heap) return Heap;
1426
1427 /* Reset a special Parameters == -1 hack */
1428 if ((ULONG_PTR)Parameters == (ULONG_PTR)-1)
1429 Parameters = NULL;
1430 else
1431 DPRINT1("Enabling page heap failed\n");
1432 }
1433
1434 /* Check validation flags */
1436 {
1437 DPRINT1("Invalid flags 0x%08x, fixing...\n", Flags);
1439 }
1440
1441 /* Capture parameters */
1442 if (Parameters)
1443 {
1444 _SEH2_TRY
1445 {
1446 /* If size of structure correct, then copy it */
1447 if (Parameters->Length == sizeof(RTL_HEAP_PARAMETERS))
1448 RtlCopyMemory(&SafeParams, Parameters, sizeof(RTL_HEAP_PARAMETERS));
1449 }
1451 {
1452 _SEH2_YIELD(return NULL);
1453 }
1454 _SEH2_END;
1455 }
1456
1457 Parameters = &SafeParams;
1458
1459 /* Check global flags */
1460 if (NtGlobalFlags & FLG_HEAP_DISABLE_COALESCING)
1462
1463 if (NtGlobalFlags & FLG_HEAP_ENABLE_FREE_CHECK)
1465
1466 if (NtGlobalFlags & FLG_HEAP_ENABLE_TAIL_CHECK)
1468
1469 if (RtlpGetMode() == UserMode)
1470 {
1471 /* Also check these flags if in usermode */
1472 if (NtGlobalFlags & FLG_HEAP_VALIDATE_ALL)
1474
1475 if (NtGlobalFlags & FLG_HEAP_VALIDATE_PARAMETERS)
1477
1478 if (NtGlobalFlags & FLG_USER_STACK_TRACE_DB)
1480 }
1481
1482 /* Set tunable parameters */
1484
1485 /* Get the max um address */
1487 &SystemInformation,
1488 sizeof(SystemInformation),
1489 NULL);
1490
1491 if (!NT_SUCCESS(Status))
1492 {
1493 DPRINT1("Getting max usermode address failed with status 0x%08x\n", Status);
1494 return NULL;
1495 }
1496
1497 MaximumUserModeAddress = SystemInformation.MaximumUserModeAddress;
1498
1499 /* Calculate max alloc size */
1500 if (!Parameters->MaximumAllocationSize)
1501 Parameters->MaximumAllocationSize = MaximumUserModeAddress - (ULONG_PTR)0x10000 - PAGE_SIZE;
1502
1503 MaxBlockSize = 0x80000 - PAGE_SIZE;
1504
1505 if (!Parameters->VirtualMemoryThreshold ||
1506 Parameters->VirtualMemoryThreshold > MaxBlockSize)
1507 {
1508 Parameters->VirtualMemoryThreshold = MaxBlockSize;
1509 }
1510
1511 if (Parameters->DeCommitFreeBlockThreshold != PAGE_SIZE)
1512 {
1513 DPRINT1("WARNING: Ignoring DeCommitFreeBlockThreshold %lx, setting it to PAGE_SIZE.\n",
1514 Parameters->DeCommitFreeBlockThreshold);
1515 Parameters->DeCommitFreeBlockThreshold = PAGE_SIZE;
1516 }
1517
1518 /* Check reserve/commit sizes and set default values */
1519 if (!CommitSize)
1520 {
1522 if (TotalSize)
1523 TotalSize = ROUND_UP(TotalSize, PAGE_SIZE);
1524 else
1525 TotalSize = 64 * PAGE_SIZE;
1526 }
1527 else
1528 {
1529 /* Round up the commit size to be at least the page size */
1531
1532 if (TotalSize)
1533 TotalSize = ROUND_UP(TotalSize, PAGE_SIZE);
1534 else
1535 TotalSize = ROUND_UP(CommitSize, 16 * PAGE_SIZE);
1536 }
1537
1538 /* Call special heap */
1540 return RtlDebugCreateHeap(Flags, Addr, TotalSize, CommitSize, Lock, Parameters);
1541
1542 /* Without serialization, a lock makes no sense */
1543 if ((Flags & HEAP_NO_SERIALIZE) && (Lock != NULL))
1544 return NULL;
1545
1546 /* See if we are already provided with an address for the heap */
1547 if (Addr)
1548 {
1549 if (Parameters->CommitRoutine)
1550 {
1551 /* There is a commit routine, so no problem here, check params */
1552 if ((Flags & HEAP_GROWABLE) ||
1553 !Parameters->InitialCommit ||
1554 !Parameters->InitialReserve ||
1555 (Parameters->InitialCommit > Parameters->InitialReserve))
1556 {
1557 /* Fail */
1558 return NULL;
1559 }
1560
1561 /* Calculate committed and uncommitted addresses */
1562 CommittedAddress = Addr;
1563 UncommittedAddress = (PCHAR)Addr + Parameters->InitialCommit;
1564 TotalSize = Parameters->InitialReserve;
1565
1566 /* Zero the initial page ourselves */
1567 RtlZeroMemory(CommittedAddress, PAGE_SIZE);
1568 }
1569 else
1570 {
1571 /* Commit routine is absent, so query how much memory caller reserved */
1573 Addr,
1575 &MemoryInfo,
1576 sizeof(MemoryInfo),
1577 NULL);
1578
1579 if (!NT_SUCCESS(Status))
1580 {
1581 DPRINT1("Querying amount of user supplied memory failed with status 0x%08X\n", Status);
1582 return NULL;
1583 }
1584
1585 /* Validate it */
1586 if (MemoryInfo.BaseAddress != Addr ||
1587 MemoryInfo.State == MEM_FREE)
1588 {
1589 return NULL;
1590 }
1591
1592 /* Validation checks passed, set committed/uncommitted addresses */
1593 CommittedAddress = Addr;
1594
1595 /* Check if it's committed or not */
1596 if (MemoryInfo.State == MEM_COMMIT)
1597 {
1598 /* Zero it out because it's already committed */
1599 RtlZeroMemory(CommittedAddress, PAGE_SIZE);
1600
1601 /* Calculate uncommitted address value */
1602 CommitSize = MemoryInfo.RegionSize;
1603 TotalSize = CommitSize;
1604 UncommittedAddress = (PCHAR)Addr + CommitSize;
1605
1606 /* Check if uncommitted address is reserved */
1608 UncommittedAddress,
1610 &MemoryInfo,
1611 sizeof(MemoryInfo),
1612 NULL);
1613
1614 if (NT_SUCCESS(Status) &&
1615 MemoryInfo.State == MEM_RESERVE)
1616 {
1617 /* It is, so add it up to the reserve size */
1618 TotalSize += MemoryInfo.RegionSize;
1619 }
1620 }
1621 else
1622 {
1623 /* It's not committed, inform following code that a commit is necessary */
1625 UncommittedAddress = Addr;
1626 }
1627 }
1628
1629 /* Mark this as a user-committed mem */
1630 HeapSegmentFlags = HEAP_USER_ALLOCATED;
1631 Heap = (PHEAP)Addr;
1632 }
1633 else
1634 {
1635 /* Check commit routine */
1636 if (Parameters->CommitRoutine) return NULL;
1637
1638 /* Reserve memory */
1639 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
1640 (PVOID *)&Heap,
1641 0,
1642 &TotalSize,
1645
1646 if (!NT_SUCCESS(Status))
1647 {
1648 DPRINT1("Failed to reserve memory with status 0x%08x\n", Status);
1649 return NULL;
1650 }
1651
1652 /* Set base addresses */
1653 CommittedAddress = Heap;
1654 UncommittedAddress = Heap;
1655 }
1656
1657 /* Check if we need to commit something */
1658 if (CommittedAddress == UncommittedAddress)
1659 {
1660 /* Commit the required size */
1661 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
1662 &CommittedAddress,
1663 0,
1664 &CommitSize,
1665 MEM_COMMIT,
1667
1668 DPRINT("Committed %Iu bytes at base %p\n", CommitSize, CommittedAddress);
1669
1670 if (!NT_SUCCESS(Status))
1671 {
1672 DPRINT1("Failure, Status 0x%08X\n", Status);
1673
1674 /* Release memory if it was reserved */
1675 if (!Addr) ZwFreeVirtualMemory(NtCurrentProcess(),
1676 (PVOID *)&Heap,
1677 &TotalSize,
1678 MEM_RELEASE);
1679
1680 return NULL;
1681 }
1682
1683 /* Calculate new uncommitted address */
1684 UncommittedAddress = (PCHAR)UncommittedAddress + CommitSize;
1685 }
1686
1687 /* Initialize the heap */
1689 if (!NT_SUCCESS(Status))
1690 {
1691 DPRINT1("Failed to initialize heap (%x)\n", Status);
1692 return NULL;
1693 }
1694
1695 /* Initialize heap's first segment */
1696 Status = RtlpInitializeHeapSegment(Heap, (PHEAP_SEGMENT) (Heap), 0, HeapSegmentFlags, TotalSize, CommitSize);
1697 if (!NT_SUCCESS(Status))
1698 {
1699 DPRINT1("Failed to initialize heap segment (%x)\n", Status);
1700 return NULL;
1701 }
1702
1703 DPRINT("Created heap %p, CommitSize %x, ReserveSize %x\n", Heap, CommitSize, TotalSize);
1704
1705 /* Add heap to process list in case of usermode heap */
1706 if (RtlpGetMode() == UserMode)
1707 {
1709
1710 // FIXME: What about lookasides?
1711 }
1712
1713 return Heap;
1714}
1715
1716/***********************************************************************
1717 * RtlDestroyHeap
1718 * RETURNS
1719 * TRUE: Success
1720 * FALSE: Failure
1721 *
1722 * @implemented
1723 *
1724 * RETURNS
1725 * Success: A NULL HANDLE, if heap is NULL or it was destroyed
1726 * Failure: The Heap handle, if heap is the process heap.
1727 */
1729RtlDestroyHeap(HANDLE HeapPtr) /* [in] Handle of heap */
1730{
1731 PHEAP Heap = (PHEAP)HeapPtr;
1732 PLIST_ENTRY Current;
1733 PHEAP_UCR_SEGMENT UcrSegment;
1734 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry;
1736 SIZE_T Size;
1737 LONG i;
1739
1740 if (!HeapPtr) return NULL;
1741
1742 /* Call page heap routine if required */
1743 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) return RtlpPageHeapDestroy(HeapPtr);
1744
1745 /* Call special heap */
1746 if (RtlpHeapIsSpecial(Heap->Flags))
1747 {
1748 if (!RtlDebugDestroyHeap(Heap)) return HeapPtr;
1749 }
1750
1751 /* Check for a process heap */
1752 if (RtlpGetMode() == UserMode &&
1753 HeapPtr == NtCurrentPeb()->ProcessHeap) return HeapPtr;
1754
1755 /* Free up all big allocations */
1756 Current = Heap->VirtualAllocdBlocks.Flink;
1757 while (Current != &Heap->VirtualAllocdBlocks)
1758 {
1759 VirtualEntry = CONTAINING_RECORD(Current, HEAP_VIRTUAL_ALLOC_ENTRY, Entry);
1760 BaseAddress = (PVOID)VirtualEntry;
1761 Current = Current->Flink;
1762 Size = 0;
1763 ZwFreeVirtualMemory(NtCurrentProcess(),
1764 &BaseAddress,
1765 &Size,
1766 MEM_RELEASE);
1767 }
1768
1769 /* Delete tags and remove heap from the process heaps list in user mode */
1770 if (RtlpGetMode() == UserMode)
1771 {
1772 // FIXME DestroyTags
1774 }
1775
1776 /* Delete the heap lock */
1777 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
1778 {
1779 /* Delete it if it wasn't user allocated */
1780 if (!(Heap->Flags & HEAP_LOCK_USER_ALLOCATED))
1782
1783 /* Clear out the lock variable */
1784 Heap->LockVariable = NULL;
1785 }
1786
1787 /* Free UCR segments if any were created */
1788 Current = Heap->UCRSegments.Flink;
1789 while (Current != &Heap->UCRSegments)
1790 {
1791 UcrSegment = CONTAINING_RECORD(Current, HEAP_UCR_SEGMENT, ListEntry);
1792
1793 /* Advance to the next descriptor */
1794 Current = Current->Flink;
1795
1796 BaseAddress = (PVOID)UcrSegment;
1797 Size = 0;
1798
1799 /* Release that memory */
1800 ZwFreeVirtualMemory(NtCurrentProcess(),
1801 &BaseAddress,
1802 &Size,
1803 MEM_RELEASE);
1804 }
1805
1806 /* Go through segments and destroy them */
1807 for (i = HEAP_SEGMENTS - 1; i >= 0; i--)
1808 {
1809 Segment = Heap->Segments[i];
1811 }
1812
1813 return NULL;
1814}
1815
1818 ULONG Flags,
1819 PHEAP_FREE_ENTRY FreeBlock,
1821 SIZE_T Index,
1822 SIZE_T Size)
1823{
1824 PHEAP_FREE_ENTRY SplitBlock, SplitBlock2;
1825 UCHAR FreeFlags, EntryFlags = HEAP_ENTRY_BUSY;
1826 PHEAP_ENTRY InUseEntry;
1827 SIZE_T FreeSize;
1828 UCHAR SegmentOffset;
1829
1830 /* Add extra flags in case of settable user value feature is requested,
1831 or there is a tag (small or normal) or there is a request to
1832 capture stack backtraces */
1833 if ((Flags & HEAP_EXTRA_FLAGS_MASK) ||
1834 Heap->PseudoTagEntries)
1835 {
1836 /* Add flag which means that the entry will have extra stuff attached */
1837 EntryFlags |= HEAP_ENTRY_EXTRA_PRESENT;
1838
1839 /* NB! AllocationSize is already adjusted by RtlAllocateHeap */
1840 }
1841
1842 /* Add settable user flags, if any */
1843 EntryFlags |= (Flags & HEAP_SETTABLE_USER_FLAGS) >> 4;
1844
1845 /* Save flags, update total free size */
1846 FreeFlags = FreeBlock->Flags;
1847 Heap->TotalFreeSize -= FreeBlock->Size;
1848
1849 /* Make this block an in-use one */
1850 InUseEntry = (PHEAP_ENTRY)FreeBlock;
1851 InUseEntry->Flags = EntryFlags;
1852 InUseEntry->SmallTagIndex = 0;
1853
1854 /* Calculate the extra amount */
1855 FreeSize = InUseEntry->Size - Index;
1856
1857 /* Update it's size fields (we don't need their data anymore) */
1858 InUseEntry->Size = (USHORT)Index;
1859 InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
1860
1861 /* If there is something to split - do the split */
1862 if (FreeSize != 0)
1863 {
1864 /* Don't split if resulting entry can't contain any payload data
1865 (i.e. being just HEAP_ENTRY_SIZE) */
1866 if (FreeSize == 1)
1867 {
1868 /* Increase sizes of the in-use entry */
1869 InUseEntry->Size++;
1870 InUseEntry->UnusedBytes += sizeof(HEAP_ENTRY);
1871 }
1872 else
1873 {
1874 /* Calculate a pointer to the new entry */
1875 SplitBlock = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
1876
1877 /* Initialize it */
1878 SplitBlock->Flags = FreeFlags;
1879 SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
1880 SplitBlock->Size = (USHORT)FreeSize;
1881 SplitBlock->PreviousSize = (USHORT)Index;
1882
1883 /* Check if it's the last entry */
1884 if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
1885 {
1886 /* Insert it to the free list if it's the last entry */
1887 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
1888 Heap->TotalFreeSize += FreeSize;
1889 }
1890 else
1891 {
1892 /* Not so easy - need to update next's previous size too */
1893 SplitBlock2 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize);
1894
1895 if (SplitBlock2->Flags & HEAP_ENTRY_BUSY)
1896 {
1897 SplitBlock2->PreviousSize = (USHORT)FreeSize;
1898 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
1899 Heap->TotalFreeSize += FreeSize;
1900 }
1901 else
1902 {
1903 /* Even more complex - the next entry is free, so we can merge them into one! */
1904 SplitBlock->Flags = SplitBlock2->Flags;
1905
1906 /* Remove that next entry */
1907 RtlpRemoveFreeBlock(Heap, SplitBlock2, FALSE);
1908
1909 /* Update sizes */
1910 FreeSize += SplitBlock2->Size;
1911 Heap->TotalFreeSize -= SplitBlock2->Size;
1912
1913 if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
1914 {
1915 /* Insert it back */
1916 SplitBlock->Size = (USHORT)FreeSize;
1917
1918 /* Don't forget to update previous size of the next entry! */
1919 if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
1920 {
1921 ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
1922 }
1923
1924 /* Actually insert it */
1925 RtlpInsertFreeBlockHelper(Heap, SplitBlock, (USHORT)FreeSize, FALSE);
1926
1927 /* Update total size */
1928 Heap->TotalFreeSize += FreeSize;
1929 }
1930 else
1931 {
1932 /* Resulting block is quite big */
1933 RtlpInsertFreeBlock(Heap, SplitBlock, FreeSize);
1934 }
1935 }
1936 }
1937
1938 /* Reset flags of the free entry */
1939 FreeFlags = 0;
1940 if (SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY)
1941 {
1942 SegmentOffset = SplitBlock->SegmentOffset;
1943 ASSERT(SegmentOffset < HEAP_SEGMENTS);
1944 }
1945 }
1946 }
1947
1948 /* Set last entry flag */
1949 if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
1950 InUseEntry->Flags |= HEAP_ENTRY_LAST_ENTRY;
1951
1952 return InUseEntry;
1953}
1954
1955static
1956PVOID
1958 ULONG Flags,
1959 SIZE_T Size,
1961 SIZE_T Index,
1962 BOOLEAN HeapLocked)
1963{
1964 PHEAP_FREE_ENTRY FreeBlock;
1965
1966 /* The entries in the list must be too small for us */
1967 ASSERT(IsListEmpty(&Heap->FreeLists) ||
1968 (CONTAINING_RECORD(Heap->FreeLists.Blink, HEAP_FREE_ENTRY, FreeList)->Size < Index));
1969
1970 /* Extend the heap */
1971 FreeBlock = RtlpExtendHeap(Heap, AllocationSize);
1972
1973 /* Use the new biggest entry we've got */
1974 if (FreeBlock)
1975 {
1976 PHEAP_ENTRY InUseEntry;
1977 PHEAP_ENTRY_EXTRA Extra;
1978
1979 RtlpRemoveFreeBlock(Heap, FreeBlock, TRUE);
1980
1981 /* Split it */
1982 InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
1983
1984 /* Release the lock */
1985 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
1986
1987 /* Zero memory if that was requested */
1988 if (Flags & HEAP_ZERO_MEMORY)
1989 RtlZeroMemory(InUseEntry + 1, Size);
1990 else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
1991 {
1992 /* Fill this block with a special pattern */
1993 RtlFillMemoryUlong(InUseEntry + 1, Size & ~0x3, ARENA_INUSE_FILLER);
1994 }
1995
1996 /* Fill tail of the block with a special pattern too if requested */
1998 {
1999 RtlFillMemory((PCHAR)(InUseEntry + 1) + Size, sizeof(HEAP_ENTRY), HEAP_TAIL_FILL);
2000 InUseEntry->Flags |= HEAP_ENTRY_FILL_PATTERN;
2001 }
2002
2003 /* Prepare extra if it's present */
2004 if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2005 {
2006 Extra = RtlpGetExtraStuffPointer(InUseEntry);
2007 RtlZeroMemory(Extra, sizeof(HEAP_ENTRY_EXTRA));
2008
2009 // TODO: Tagging
2010 }
2011
2012 /* Return pointer to the */
2013 return InUseEntry + 1;
2014 }
2015
2016 /* Really unfortunate, out of memory condition */
2018
2019 /* Generate an exception */
2021 {
2022 EXCEPTION_RECORD ExceptionRecord;
2023
2024 ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
2025 ExceptionRecord.ExceptionRecord = NULL;
2026 ExceptionRecord.NumberParameters = 1;
2027 ExceptionRecord.ExceptionFlags = 0;
2028 ExceptionRecord.ExceptionInformation[0] = AllocationSize;
2029
2030 RtlRaiseException(&ExceptionRecord);
2031 }
2032
2033 /* Release the lock */
2034 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
2035 DPRINT1("HEAP: Allocation failed!\n");
2036 DPRINT1("Flags %x\n", Heap->Flags);
2037 return NULL;
2038}
2039
2040/***********************************************************************
2041 * HeapAlloc (KERNEL32.334)
2042 * RETURNS
2043 * Pointer to allocated memory block
2044 * NULL: Failure
2045 * 0x7d030f60--invalid flags in RtlHeapAllocate
2046 * @implemented
2047 */
2050 IN ULONG Flags,
2051 IN SIZE_T Size)
2052{
2053 PHEAP Heap = (PHEAP)HeapPtr;
2055 SIZE_T Index;
2056 UCHAR EntryFlags = HEAP_ENTRY_BUSY;
2057 BOOLEAN HeapLocked = FALSE;
2058 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualBlock = NULL;
2059 PHEAP_ENTRY_EXTRA Extra;
2061
2062 /* Force flags */
2063 Flags |= Heap->ForceFlags;
2064
2065 /* Call special heap */
2067 return RtlDebugAllocateHeap(Heap, Flags, Size);
2068
2069 /* Check for the maximum size */
2070 if (Size >= 0x80000000)
2071 {
2073 DPRINT1("HEAP: Allocation failed!\n");
2074 return NULL;
2075 }
2076
2078 {
2079 DPRINT1("HEAP: RtlAllocateHeap is called with unsupported flags %x, ignoring\n", Flags);
2080 }
2081
2082 //DPRINT("RtlAllocateHeap(%p %x %x)\n", Heap, Flags, Size);
2083
2084 /* Calculate allocation size and index */
2085 if (Size)
2087 else
2088 AllocationSize = 1;
2090
2091 /* Add extra flags in case of settable user value feature is requested,
2092 or there is a tag (small or normal) or there is a request to
2093 capture stack backtraces */
2095 Heap->PseudoTagEntries)
2096 {
2097 /* Add flag which means that the entry will have extra stuff attached */
2098 EntryFlags |= HEAP_ENTRY_EXTRA_PRESENT;
2099
2100 /* Account for extra stuff size */
2102 }
2103
2104 /* Add settable user flags, if any */
2105 EntryFlags |= (Flags & HEAP_SETTABLE_USER_FLAGS) >> 4;
2106
2108
2109 /* Acquire the lock if necessary */
2110 if (!(Flags & HEAP_NO_SERIALIZE))
2111 {
2113 HeapLocked = TRUE;
2114 }
2115
2116 /* Depending on the size, the allocation is going to be done from dedicated,
2117 non-dedicated lists or a virtual block of memory */
2118 if (Index <= Heap->VirtualMemoryThreshold)
2119 {
2120 PHEAP_ENTRY InUseEntry;
2121 PHEAP_FREE_ENTRY FreeEntry;
2122
2123 /* First quick check: Anybody here ? */
2124 if (IsListEmpty(&Heap->FreeLists))
2125 return RtlpAllocateNonDedicated(Heap, Flags, Size, AllocationSize, Index, HeapLocked);
2126
2127 /* Second quick check: Is there someone for us ? */
2128 FreeEntry = CONTAINING_RECORD(Heap->FreeLists.Blink, HEAP_FREE_ENTRY, FreeList);
2129 if (FreeEntry->Size < Index)
2130 {
2131 /* Largest entry in the list doesnt fit. */
2132 return RtlpAllocateNonDedicated(Heap, Flags, Size, AllocationSize, Index, HeapLocked);
2133 }
2134
2136 {
2137 /* Find an entry from the non dedicated list */
2138 FreeEntry = CONTAINING_RECORD(Heap->FreeHints[0],
2140 FreeList);
2141
2142 while (FreeEntry->Size < Index)
2143 {
2144 /* We made sure we had the right size available */
2145 ASSERT(FreeEntry->FreeList.Flink != &Heap->FreeLists);
2146 FreeEntry = CONTAINING_RECORD(FreeEntry->FreeList.Flink,
2148 FreeList);
2149 }
2150 }
2151 else
2152 {
2153 /* Get the free entry from the hint */
2155 ASSERT(HintIndex != 0xFFFFFFFF);
2156 ASSERT((HintIndex >= (Index - 1)) || (HintIndex == 0));
2157 FreeEntry = CONTAINING_RECORD(Heap->FreeHints[HintIndex],
2159 FreeList);
2160 }
2161
2162 /* Remove the free block, split, profit. */
2163 RtlpRemoveFreeBlock(Heap, FreeEntry, FALSE);
2164 InUseEntry = RtlpSplitEntry(Heap, Flags, FreeEntry, AllocationSize, Index, Size);
2165
2166 /* Release the lock */
2167 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
2168
2169 /* Zero memory if that was requested */
2170 if (Flags & HEAP_ZERO_MEMORY)
2171 RtlZeroMemory(InUseEntry + 1, Size);
2172 else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
2173 {
2174 /* Fill this block with a special pattern */
2175 RtlFillMemoryUlong(InUseEntry + 1, Size & ~0x3, ARENA_INUSE_FILLER);
2176 }
2177
2178 /* Fill tail of the block with a special pattern too if requested */
2180 {
2181 RtlFillMemory((PCHAR)(InUseEntry + 1) + Size, sizeof(HEAP_ENTRY), HEAP_TAIL_FILL);
2182 InUseEntry->Flags |= HEAP_ENTRY_FILL_PATTERN;
2183 }
2184
2185 /* Prepare extra if it's present */
2186 if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2187 {
2188 Extra = RtlpGetExtraStuffPointer(InUseEntry);
2189 RtlZeroMemory(Extra, sizeof(HEAP_ENTRY_EXTRA));
2190
2191 // TODO: Tagging
2192 }
2193
2194 /* User data starts right after the entry's header */
2195 return InUseEntry + 1;
2196 }
2197
2198 if (Heap->Flags & HEAP_GROWABLE)
2199 {
2200 /* We've got a very big allocation request, satisfy it by directly allocating virtual memory */
2202
2203 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
2204 (PVOID *)&VirtualBlock,
2205 0,
2207 MEM_COMMIT,
2209
2210 if (!NT_SUCCESS(Status))
2211 {
2212 // Set STATUS!
2213 /* Release the lock */
2214 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
2215 DPRINT1("HEAP: Allocation failed!\n");
2216 return NULL;
2217 }
2218
2219 /* Initialize the newly allocated block */
2220 VirtualBlock->BusyBlock.Size = (USHORT)(AllocationSize - Size);
2221 ASSERT(VirtualBlock->BusyBlock.Size >= sizeof(HEAP_VIRTUAL_ALLOC_ENTRY));
2222 VirtualBlock->BusyBlock.Flags = EntryFlags | HEAP_ENTRY_VIRTUAL_ALLOC | HEAP_ENTRY_EXTRA_PRESENT;
2223 VirtualBlock->CommitSize = AllocationSize;
2224 VirtualBlock->ReserveSize = AllocationSize;
2225
2226 /* Insert it into the list of virtual allocations */
2227 InsertTailList(&Heap->VirtualAllocdBlocks, &VirtualBlock->Entry);
2228
2229 /* Release the lock */
2230 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
2231
2232 /* Return pointer to user data */
2233 return VirtualBlock + 1;
2234 }
2235
2236 /* Generate an exception */
2238 {
2239 EXCEPTION_RECORD ExceptionRecord;
2240
2241 ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
2242 ExceptionRecord.ExceptionRecord = NULL;
2243 ExceptionRecord.NumberParameters = 1;
2244 ExceptionRecord.ExceptionFlags = 0;
2245 ExceptionRecord.ExceptionInformation[0] = AllocationSize;
2246
2247 RtlRaiseException(&ExceptionRecord);
2248 }
2249
2251
2252 /* Release the lock */
2253 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
2254 DPRINT1("HEAP: Allocation failed!\n");
2255 return NULL;
2256}
2257
2258
2259/***********************************************************************
2260 * HeapFree (KERNEL32.338)
2261 * RETURNS
2262 * TRUE: Success
2263 * FALSE: Failure
2264 *
2265 * @implemented
2266 */
2268 HANDLE HeapPtr, /* [in] Handle of heap */
2269 ULONG Flags, /* [in] Heap freeing flags */
2270 PVOID Ptr /* [in] Address of memory to free */
2271)
2272{
2273 PHEAP Heap;
2274 PHEAP_ENTRY HeapEntry;
2275 USHORT TagIndex = 0;
2276 SIZE_T BlockSize;
2277 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry;
2280
2281 /* Freeing NULL pointer is a legal operation */
2282 if (!Ptr) return TRUE;
2283
2284 /* Get pointer to the heap and force flags */
2285 Heap = (PHEAP)HeapPtr;
2286 Flags |= Heap->ForceFlags;
2287
2288 /* Call special heap */
2290 return RtlDebugFreeHeap(Heap, Flags, Ptr);
2291
2292 /* Get pointer to the heap entry */
2293 HeapEntry = (PHEAP_ENTRY)Ptr - 1;
2294
2295 /* Protect with SEH in case the pointer is not valid */
2296 _SEH2_TRY
2297 {
2298 /* Check this entry, fail if it's invalid */
2299 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY) ||
2300 (((ULONG_PTR)Ptr & 0x7) != 0) ||
2301 (HeapEntry->SegmentOffset >= HEAP_SEGMENTS))
2302 {
2303 /* This is an invalid block */
2304 DPRINT1("HEAP: Trying to free an invalid address %p!\n", Ptr);
2306 _SEH2_YIELD(return FALSE);
2307 }
2308 }
2310 {
2311 /* The pointer was invalid */
2312 DPRINT1("HEAP: Trying to free an invalid address %p!\n", Ptr);
2314 _SEH2_YIELD(return FALSE);
2315 }
2316 _SEH2_END;
2317
2318 /* Lock if necessary */
2319 if (!(Flags & HEAP_NO_SERIALIZE))
2320 {
2322 Locked = TRUE;
2323 }
2324
2325 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2326 {
2327 /* Big allocation */
2328 VirtualEntry = CONTAINING_RECORD(HeapEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
2329
2330 /* Remove it from the list */
2331 RemoveEntryList(&VirtualEntry->Entry);
2332
2333 // TODO: Tagging
2334
2335 BlockSize = 0;
2336 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
2337 (PVOID *)&VirtualEntry,
2338 &BlockSize,
2339 MEM_RELEASE);
2340
2341 if (!NT_SUCCESS(Status))
2342 {
2343 DPRINT1("HEAP: Failed releasing memory with Status 0x%08X. Heap %p, ptr %p, base address %p\n",
2344 Status, Heap, Ptr, VirtualEntry);
2346 }
2347 }
2348 else
2349 {
2350 /* Normal allocation */
2351 BlockSize = HeapEntry->Size;
2352
2353 // TODO: Tagging
2354
2355 /* Coalesce in kernel mode, and in usermode if it's not disabled */
2356 if (RtlpGetMode() == KernelMode ||
2358 {
2359 HeapEntry = (PHEAP_ENTRY)RtlpCoalesceFreeBlocks(Heap,
2360 (PHEAP_FREE_ENTRY)HeapEntry,
2361 &BlockSize,
2362 FALSE);
2363 }
2364
2365 /* See if we should decommit this block */
2366 if ((BlockSize >= Heap->DeCommitFreeBlockThreshold) ||
2367 (Heap->TotalFreeSize + BlockSize >= Heap->DeCommitTotalFreeThreshold))
2368 {
2369 RtlpDeCommitFreeBlock(Heap, (PHEAP_FREE_ENTRY)HeapEntry, BlockSize);
2370 }
2371 else
2372 {
2373 /* Insert into the free list */
2374 RtlpInsertFreeBlock(Heap, (PHEAP_FREE_ENTRY)HeapEntry, BlockSize);
2375
2376 if (RtlpGetMode() == UserMode &&
2377 TagIndex != 0)
2378 {
2379 // FIXME: Tagging
2381 }
2382 }
2383 }
2384
2385 /* Release the heap lock */
2387
2388 return TRUE;
2389}
2390
2393 IN ULONG Flags,
2394 IN PHEAP_ENTRY InUseEntry,
2395 IN SIZE_T Size,
2396 IN SIZE_T Index)
2397{
2398 UCHAR EntryFlags, RememberFlags;
2399 PHEAP_FREE_ENTRY FreeEntry, UnusedEntry, FollowingEntry;
2400 SIZE_T FreeSize, PrevSize, TailPart, AddedSize = 0;
2401 PHEAP_ENTRY_EXTRA OldExtra, NewExtra;
2402 UCHAR SegmentOffset;
2403
2404 /* We can't grow beyond specified threshold */
2405 if (Index > Heap->VirtualMemoryThreshold)
2406 return FALSE;
2407
2408 /* Get entry flags */
2409 EntryFlags = InUseEntry->Flags;
2410
2411 if (RtlpIsLastCommittedEntry(InUseEntry))
2412 {
2413 /* There is no next block, just uncommitted space. Calculate how much is needed */
2414 FreeSize = (Index - InUseEntry->Size) << HEAP_ENTRY_SHIFT;
2415 FreeSize = ROUND_UP(FreeSize, PAGE_SIZE);
2416
2417 /* Find and commit those pages */
2418 FreeEntry = RtlpFindAndCommitPages(Heap,
2419 Heap->Segments[InUseEntry->SegmentOffset],
2420 &FreeSize,
2421 (PVOID)PAGE_ROUND_UP(InUseEntry + InUseEntry->Size));
2422
2423 /* Fail if it failed... */
2424 if (!FreeEntry) return FALSE;
2425
2426 /* It was successful, perform coalescing */
2427 FreeSize = FreeSize >> HEAP_ENTRY_SHIFT;
2428 FreeEntry = RtlpCoalesceFreeBlocks(Heap, FreeEntry, &FreeSize, FALSE);
2429
2430 /* Check if it's enough */
2431 if (FreeSize + InUseEntry->Size < Index)
2432 {
2433 /* Still not enough */
2434 RtlpInsertFreeBlock(Heap, FreeEntry, FreeSize);
2435 Heap->TotalFreeSize += FreeSize;
2436 return FALSE;
2437 }
2438
2439 /* Remember flags of this free entry */
2440 RememberFlags = FreeEntry->Flags;
2441
2442 /* Sum up sizes */
2443 FreeSize += InUseEntry->Size;
2444 }
2445 else
2446 {
2447 FreeEntry = (PHEAP_FREE_ENTRY)(InUseEntry + InUseEntry->Size);
2448
2449 /* The next block indeed exists. Check if it's free or in use */
2450 if (FreeEntry->Flags & HEAP_ENTRY_BUSY) return FALSE;
2451
2452 /* Next entry is free, check if it can fit the block we need */
2453 FreeSize = InUseEntry->Size + FreeEntry->Size;
2454 if (FreeSize < Index) return FALSE;
2455
2456 /* Remember flags of this free entry */
2457 RememberFlags = FreeEntry->Flags;
2458
2459 /* Remove this block from the free list */
2460 RtlpRemoveFreeBlock(Heap, FreeEntry, FALSE);
2461 Heap->TotalFreeSize -= FreeEntry->Size;
2462 }
2463
2464 PrevSize = (InUseEntry->Size << HEAP_ENTRY_SHIFT) - InUseEntry->UnusedBytes;
2465 FreeSize -= Index;
2466
2467 /* Don't produce too small blocks */
2468 if (FreeSize <= 2)
2469 {
2470 Index += FreeSize;
2471 FreeSize = 0;
2472 }
2473
2474 /* Process extra stuff */
2475 if (EntryFlags & HEAP_ENTRY_EXTRA_PRESENT)
2476 {
2477 /* Calculate pointers */
2478 OldExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + InUseEntry->Size - 1);
2479 NewExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + Index - 1);
2480
2481 /* Copy contents */
2482 *NewExtra = *OldExtra;
2483
2484 // FIXME Tagging
2485 }
2486
2487 /* Update sizes */
2488 InUseEntry->Size = (USHORT)Index;
2489 InUseEntry->UnusedBytes = (UCHAR)((Index << HEAP_ENTRY_SHIFT) - Size);
2490
2491 /* Check if there is a free space remaining after merging those blocks */
2492 if (!FreeSize)
2493 {
2494 /* Update flags and sizes */
2495 InUseEntry->Flags |= RememberFlags & HEAP_ENTRY_LAST_ENTRY;
2496
2497 /* Either update previous size of the next entry or mark it as a last
2498 entry in the segment */
2499 if (!(RememberFlags & HEAP_ENTRY_LAST_ENTRY))
2500 {
2501 (InUseEntry + InUseEntry->Size)->PreviousSize = InUseEntry->Size;
2502 }
2503 else
2504 {
2505 SegmentOffset = InUseEntry->SegmentOffset;
2506 ASSERT(SegmentOffset < HEAP_SEGMENTS);
2507 }
2508 }
2509 else
2510 {
2511 /* Complex case, we need to split the block to give unused free space
2512 back to the heap */
2513 UnusedEntry = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
2514 UnusedEntry->PreviousSize = (USHORT)Index;
2515 UnusedEntry->SegmentOffset = InUseEntry->SegmentOffset;
2516
2517 /* Update the following block or set the last entry in the segment */
2518 if (RememberFlags & HEAP_ENTRY_LAST_ENTRY)
2519 {
2520 SegmentOffset = UnusedEntry->SegmentOffset;
2521 ASSERT(SegmentOffset < HEAP_SEGMENTS);
2522
2523 /* Set flags and size */
2524 UnusedEntry->Flags = RememberFlags;
2525 UnusedEntry->Size = (USHORT)FreeSize;
2526
2527 /* Insert it to the heap and update total size */
2528 RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
2529 Heap->TotalFreeSize += FreeSize;
2530 }
2531 else
2532 {
2533 /* There is a block after this one */
2534 FollowingEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)UnusedEntry + FreeSize);
2535
2536 if (FollowingEntry->Flags & HEAP_ENTRY_BUSY)
2537 {
2538 /* Update flags and set size of the unused space entry */
2539 UnusedEntry->Flags = RememberFlags & (~HEAP_ENTRY_LAST_ENTRY);
2540 UnusedEntry->Size = (USHORT)FreeSize;
2541
2542 /* Update previous size of the following entry */
2543 FollowingEntry->PreviousSize = (USHORT)FreeSize;
2544
2545 /* Insert it to the heap and update total free size */
2546 RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
2547 Heap->TotalFreeSize += FreeSize;
2548 }
2549 else
2550 {
2551 /* That following entry is also free, what a fortune! */
2552 RememberFlags = FollowingEntry->Flags;
2553
2554 /* Remove it */
2555 RtlpRemoveFreeBlock(Heap, FollowingEntry, FALSE);
2556 Heap->TotalFreeSize -= FollowingEntry->Size;
2557
2558 /* And make up a new combined block */
2559 FreeSize += FollowingEntry->Size;
2560 UnusedEntry->Flags = RememberFlags;
2561
2562 /* Check where to put it */
2563 if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
2564 {
2565 /* Fine for a dedicated list */
2566 UnusedEntry->Size = (USHORT)FreeSize;
2567
2568 if (!(RememberFlags & HEAP_ENTRY_LAST_ENTRY))
2569 {
2570 ((PHEAP_ENTRY)UnusedEntry + FreeSize)->PreviousSize = (USHORT)FreeSize;
2571 }
2572 else
2573 {
2574 SegmentOffset = UnusedEntry->SegmentOffset;
2575 ASSERT(SegmentOffset < HEAP_SEGMENTS);
2576 }
2577
2578 /* Insert it back and update total size */
2579 RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
2580 Heap->TotalFreeSize += FreeSize;
2581 }
2582 else
2583 {
2584 /* The block is very large, leave all the hassle to the insertion routine */
2585 RtlpInsertFreeBlock(Heap, UnusedEntry, FreeSize);
2586 }
2587 }
2588 }
2589 }
2590
2591 /* Properly "zero out" (and fill!) the space */
2592 if (Flags & HEAP_ZERO_MEMORY)
2593 {
2594 RtlZeroMemory((PCHAR)(InUseEntry + 1) + PrevSize, Size - PrevSize);
2595 }
2596 else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
2597 {
2598 /* Calculate tail part which we need to fill */
2599 TailPart = PrevSize & (sizeof(ULONG) - 1);
2600
2601 /* "Invert" it as usual */
2602 if (TailPart) TailPart = 4 - TailPart;
2603
2604 if (Size > (PrevSize + TailPart))
2605 AddedSize = (Size - (PrevSize + TailPart)) & ~(sizeof(ULONG) - 1);
2606
2607 if (AddedSize)
2608 {
2609 RtlFillMemoryUlong((PCHAR)(InUseEntry + 1) + PrevSize + TailPart,
2610 AddedSize,
2612 }
2613 }
2614
2615 /* Fill the new tail */
2616 if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
2617 {
2618 RtlFillMemory((PCHAR)(InUseEntry + 1) + Size,
2621 }
2622
2623 /* Copy user settable flags */
2624 InUseEntry->Flags &= ~HEAP_ENTRY_SETTABLE_FLAGS;
2625 InUseEntry->Flags |= ((Flags & HEAP_SETTABLE_USER_FLAGS) >> 4);
2626
2627 /* Return success */
2628 return TRUE;
2629}
2630
2633{
2634 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry;
2635
2636 /* Check if it's a big block */
2637 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2638 {
2639 VirtualEntry = CONTAINING_RECORD(HeapEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
2640
2641 /* Return a pointer to the extra stuff*/
2642 return &VirtualEntry->ExtraStuff;
2643 }
2644 else
2645 {
2646 /* This is a usual entry, which means extra stuff follows this block */
2647 return (PHEAP_ENTRY_EXTRA)(HeapEntry + HeapEntry->Size - 1);
2648 }
2649}
2650
2651
2652/***********************************************************************
2653 * RtlReAllocateHeap
2654 * PARAMS
2655 * Heap [in] Handle of heap block
2656 * Flags [in] Heap reallocation flags
2657 * Ptr, [in] Address of memory to reallocate
2658 * Size [in] Number of bytes to reallocate
2659 *
2660 * RETURNS
2661 * Pointer to reallocated memory block
2662 * NULL: Failure
2663 * 0x7d030f60--invalid flags in RtlHeapAllocate
2664 * @implemented
2665 */
2668 ULONG Flags,
2669 PVOID Ptr,
2670 SIZE_T Size)
2671{
2672 PHEAP Heap = (PHEAP)HeapPtr;
2673 PHEAP_ENTRY InUseEntry, NewInUseEntry;
2674 PHEAP_ENTRY_EXTRA OldExtra, NewExtra;
2675 SIZE_T AllocationSize, FreeSize, DecommitSize;
2676 BOOLEAN HeapLocked = FALSE;
2677 PVOID NewBaseAddress;
2678 PHEAP_FREE_ENTRY SplitBlock, SplitBlock2;
2679 SIZE_T OldSize, Index, OldIndex;
2680 UCHAR FreeFlags;
2682 PVOID DecommitBase;
2683 SIZE_T RemainderBytes, ExtraSize;
2684 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
2685 EXCEPTION_RECORD ExceptionRecord;
2686 UCHAR SegmentOffset;
2687
2688 /* Return success in case of a null pointer */
2689 if (!Ptr)
2690 {
2692 return NULL;
2693 }
2694
2695 /* Force heap flags */
2696 Flags |= Heap->ForceFlags;
2697
2698 /* Call special heap */
2700 return RtlDebugReAllocateHeap(Heap, Flags, Ptr, Size);
2701
2702 /* Make sure size is valid */
2703 if (Size >= 0x80000000)
2704 {
2706 return NULL;
2707 }
2708
2709 /* Calculate allocation size and index */
2710 if (Size)
2712 else
2713 AllocationSize = 1;
2715
2716 /* Add up extra stuff, if it is present anywhere */
2719 Heap->PseudoTagEntries)
2720 {
2722 }
2723
2724 /* Acquire the lock if necessary */
2725 if (!(Flags & HEAP_NO_SERIALIZE))
2726 {
2728 HeapLocked = TRUE;
2729 /* Do not acquire the lock anymore for re-entrant call */
2731 }
2732
2733 /* Get the pointer to the in-use entry */
2734 InUseEntry = (PHEAP_ENTRY)Ptr - 1;
2735
2736 /* If that entry is not really in-use, we have a problem */
2737 if (!(InUseEntry->Flags & HEAP_ENTRY_BUSY))
2738 {
2740
2741 /* Release the lock and return */
2742 if (HeapLocked)
2744 return Ptr;
2745 }
2746
2747 if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2748 {
2749 /* This is a virtually allocated block. Get its size */
2750 OldSize = RtlpGetSizeOfBigBlock(InUseEntry);
2751
2752 /* Convert it to an index */
2753 OldIndex = (OldSize + InUseEntry->Size) >> HEAP_ENTRY_SHIFT;
2754
2755 /* Calculate new allocation size and round it to the page size */
2758 }
2759 else
2760 {
2761 /* Usual entry */
2762 OldIndex = InUseEntry->Size;
2763
2764 OldSize = (OldIndex << HEAP_ENTRY_SHIFT) - InUseEntry->UnusedBytes;
2765 }
2766
2767 /* Calculate new index */
2769
2770 /* Check for 4 different scenarios (old size, new size, old index, new index) */
2771 if (Index <= OldIndex)
2772 {
2773 /* Difference must be greater than 1, adjust if it's not so */
2774 if (Index + 1 == OldIndex)
2775 {
2776 Index++;
2777 AllocationSize += sizeof(HEAP_ENTRY);
2778 }
2779
2780 /* Calculate new size */
2781 if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2782 {
2783 /* Simple in case of a virtual alloc - just an unused size */
2784 InUseEntry->Size = (USHORT)(AllocationSize - Size);
2785 ASSERT(InUseEntry->Size >= sizeof(HEAP_VIRTUAL_ALLOC_ENTRY));
2786 }
2787 else if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2788 {
2789 /* There is extra stuff, take it into account */
2790 OldExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + InUseEntry->Size - 1);
2791 NewExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + Index - 1);
2792 *NewExtra = *OldExtra;
2793
2794 // FIXME Tagging, TagIndex
2795
2796 /* Update unused bytes count */
2797 InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
2798 }
2799 else
2800 {
2801 // FIXME Tagging, SmallTagIndex
2802 InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
2803 }
2804
2805 /* If new size is bigger than the old size */
2806 if (Size > OldSize)
2807 {
2808 /* Zero out that additional space if required */
2809 if (Flags & HEAP_ZERO_MEMORY)
2810 {
2811 RtlZeroMemory((PCHAR)Ptr + OldSize, Size - OldSize);
2812 }
2813 else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
2814 {
2815 /* Fill it on free if required */
2816 RemainderBytes = OldSize & (sizeof(ULONG) - 1);
2817
2818 if (RemainderBytes)
2819 RemainderBytes = 4 - RemainderBytes;
2820
2821 if (Size > (OldSize + RemainderBytes))
2822 {
2823 /* Calculate actual amount of extra bytes to fill */
2824 ExtraSize = (Size - (OldSize + RemainderBytes)) & ~(sizeof(ULONG) - 1);
2825
2826 /* Fill them if there are any */
2827 if (ExtraSize != 0)
2828 {
2829 RtlFillMemoryUlong((PCHAR)(InUseEntry + 1) + OldSize + RemainderBytes,
2830 ExtraSize,
2832 }
2833 }
2834 }
2835 }
2836
2837 /* Fill tail of the heap entry if required */
2839 {
2840 RtlFillMemory((PCHAR)(InUseEntry + 1) + Size,
2843 }
2844
2845 /* Check if the difference is significant or not */
2846 if (Index != OldIndex)
2847 {
2848 /* Save flags */
2849 FreeFlags = InUseEntry->Flags & ~HEAP_ENTRY_BUSY;
2850
2851 if (FreeFlags & HEAP_ENTRY_VIRTUAL_ALLOC)
2852 {
2853 /* This is a virtual block allocation */
2854 VirtualAllocBlock = CONTAINING_RECORD(InUseEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
2855
2856 // FIXME Tagging!
2857
2858 DecommitBase = (PCHAR)VirtualAllocBlock + AllocationSize;
2859 DecommitSize = (OldIndex << HEAP_ENTRY_SHIFT) - AllocationSize;
2860
2861 /* Release the memory */
2862 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
2863 (PVOID *)&DecommitBase,
2864 &DecommitSize,
2865 MEM_RELEASE);
2866
2867 if (!NT_SUCCESS(Status))
2868 {
2869 DPRINT1("HEAP: Unable to release memory (pointer %p, size 0x%x), Status %08x\n", DecommitBase, DecommitSize, Status);
2870 }
2871 else
2872 {
2873 /* Otherwise reduce the commit size */
2874 VirtualAllocBlock->CommitSize -= DecommitSize;
2875 }
2876 }
2877 else
2878 {
2879 /* Reduce size of the block and possibly split it */
2880 SplitBlock = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
2881
2882 /* Initialize this entry */
2883 SplitBlock->Flags = FreeFlags;
2884 SplitBlock->PreviousSize = (USHORT)Index;
2885 SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
2886
2887 /* Remember free size */
2888 FreeSize = InUseEntry->Size - Index;
2889
2890 /* Set new size */
2891 InUseEntry->Size = (USHORT)Index;
2892 InUseEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
2893
2894 /* Is that the last entry */
2895 if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
2896 {
2897 SegmentOffset = SplitBlock->SegmentOffset;
2898 ASSERT(SegmentOffset < HEAP_SEGMENTS);
2899
2900 /* Set its size and insert it to the list */
2901 SplitBlock->Size = (USHORT)FreeSize;
2902 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
2903
2904 /* Update total free size */
2905 Heap->TotalFreeSize += FreeSize;
2906 }
2907 else
2908 {
2909 /* Get the block after that one */
2910 SplitBlock2 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize);
2911
2912 if (SplitBlock2->Flags & HEAP_ENTRY_BUSY)
2913 {
2914 /* It's in use, add it here*/
2915 SplitBlock->Size = (USHORT)FreeSize;
2916
2917 /* Update previous size of the next entry */
2918 ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
2919
2920 /* Insert it to the list */
2921 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
2922
2923 /* Update total size */
2924 Heap->TotalFreeSize += FreeSize;
2925 }
2926 else
2927 {
2928 /* Next entry is free, so merge with it */
2929 SplitBlock->Flags = SplitBlock2->Flags;
2930
2931 /* Remove it, update total size */
2932 RtlpRemoveFreeBlock(Heap, SplitBlock2, FALSE);
2933 Heap->TotalFreeSize -= SplitBlock2->Size;
2934
2935 /* Calculate total free size */
2936 FreeSize += SplitBlock2->Size;
2937
2938 if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
2939 {
2940 SplitBlock->Size = (USHORT)FreeSize;
2941
2942 if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
2943 {
2944 /* Update previous size of the next entry */
2945 ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
2946 }
2947 else
2948 {
2949 SegmentOffset = SplitBlock->SegmentOffset;
2950 ASSERT(SegmentOffset < HEAP_SEGMENTS);
2951 }
2952
2953 /* Insert the new one back and update total size */
2954 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
2955 Heap->TotalFreeSize += FreeSize;
2956 }
2957 else
2958 {
2959 /* Just add it */
2960 RtlpInsertFreeBlock(Heap, SplitBlock, FreeSize);
2961 }
2962 }
2963 }
2964 }
2965 }
2966 }
2967 else
2968 {
2969 /* We're growing the block */
2970 if ((InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) ||
2971 !RtlpGrowBlockInPlace(Heap, Flags, InUseEntry, Size, Index))
2972 {
2973 /* Growing in place failed, so growing out of place */
2975 {
2976 DPRINT1("Realloc in place failed, but it was the only option\n");
2977 Ptr = NULL;
2978 }
2979 else
2980 {
2981 /* Clear tag bits */
2982 Flags &= ~HEAP_TAG_MASK;
2983
2984 /* Process extra stuff */
2985 if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2986 {
2987 /* Preserve user settable flags */
2988 Flags &= ~HEAP_SETTABLE_USER_FLAGS;
2989
2990 Flags |= HEAP_SETTABLE_USER_VALUE | ((InUseEntry->Flags & HEAP_ENTRY_SETTABLE_FLAGS) << 4);
2991
2992 /* Get pointer to the old extra data */
2993 OldExtra = RtlpGetExtraStuffPointer(InUseEntry);
2994
2995 /* Save tag index if it was set */
2996 if (OldExtra->TagIndex &&
2997 !(OldExtra->TagIndex & HEAP_PSEUDO_TAG_FLAG))
2998 {
2999 Flags |= OldExtra->TagIndex << HEAP_TAG_SHIFT;
3000 }
3001 }
3002 else if (InUseEntry->SmallTagIndex)
3003 {
3004 /* Take small tag index into account */
3005 Flags |= InUseEntry->SmallTagIndex << HEAP_TAG_SHIFT;
3006 }
3007
3008 /* Allocate new block from the heap */
3009 NewBaseAddress = RtlAllocateHeap(HeapPtr,
3011 Size);
3012
3013 /* Proceed if it didn't fail */
3014 if (NewBaseAddress)
3015 {
3016 /* Get new entry pointer */
3017 NewInUseEntry = (PHEAP_ENTRY)NewBaseAddress - 1;
3018
3019 /* Process extra stuff if it exists */
3020 if (NewInUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
3021 {
3022 NewExtra = RtlpGetExtraStuffPointer(NewInUseEntry);
3023
3024 if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
3025 {
3026 OldExtra = RtlpGetExtraStuffPointer(InUseEntry);
3027 NewExtra->Settable = OldExtra->Settable;
3028 }
3029 else
3030 {
3031 RtlZeroMemory(NewExtra, sizeof(*NewExtra));
3032 }
3033 }
3034
3035 /* Copy actual user bits */
3036 if (Size < OldSize)
3037 RtlMoveMemory(NewBaseAddress, Ptr, Size);
3038 else
3039 RtlMoveMemory(NewBaseAddress, Ptr, OldSize);
3040
3041 /* Zero remaining part if required */
3042 if (Size > OldSize &&
3044 {
3045 RtlZeroMemory((PCHAR)NewBaseAddress + OldSize, Size - OldSize);
3046 }
3047
3048 /* Free the old block */
3049 RtlFreeHeap(HeapPtr, Flags, Ptr);
3050 }
3051
3052 Ptr = NewBaseAddress;
3053 }
3054 }
3055 }
3056
3057 /* Did resizing fail? */
3059 {
3060 /* Generate an exception if required */
3061 ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
3062 ExceptionRecord.ExceptionRecord = NULL;
3063 ExceptionRecord.NumberParameters = 1;
3064 ExceptionRecord.ExceptionFlags = 0;
3065 ExceptionRecord.ExceptionInformation[0] = AllocationSize;
3066
3067 RtlRaiseException(&ExceptionRecord);
3068 }
3069
3070 /* Release the heap lock if it was acquired */
3071 if (HeapLocked)
3073
3074 return Ptr;
3075}
3076
3077
3078/***********************************************************************
3079 * RtlCompactHeap
3080 *
3081 * @unimplemented
3082 */
3085 ULONG Flags)
3086{
3088 return 0;
3089}
3090
3091
3092/***********************************************************************
3093 * RtlLockHeap
3094 * Attempts to acquire the critical section object for a specified heap.
3095 *
3096 * PARAMS
3097 * Heap [in] Handle of heap to lock for exclusive access
3098 *
3099 * RETURNS
3100 * TRUE: Success
3101 * FALSE: Failure
3102 *
3103 * @implemented
3104 */
3107{
3108 PHEAP Heap = (PHEAP)HeapPtr;
3109
3110 /* Check for page heap */
3112 {
3113 return RtlpPageHeapLock(Heap);
3114 }
3115
3116 /* Check if it's really a heap */
3117 if (Heap->Signature != HEAP_SIGNATURE) return FALSE;
3118
3119 /* Lock if it's lockable */
3120 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3121 {
3123 }
3124
3125 return TRUE;
3126}
3127
3128
3129/***********************************************************************
3130 * RtlUnlockHeap
3131 * Releases ownership of the critical section object.
3132 *
3133 * PARAMS
3134 * Heap [in] Handle to the heap to unlock
3135 *
3136 * RETURNS
3137 * TRUE: Success
3138 * FALSE: Failure
3139 *
3140 * @implemented
3141 */
3144{
3145 PHEAP Heap = (PHEAP)HeapPtr;
3146
3147 /* Check for page heap */
3149 {
3150 return RtlpPageHeapUnlock(Heap);
3151 }
3152
3153 /* Check if it's really a heap */
3154 if (Heap->Signature != HEAP_SIGNATURE) return FALSE;
3155
3156 /* Unlock if it's lockable */
3157 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3158 {
3160 }
3161
3162 return TRUE;
3163}
3164
3165
3166/***********************************************************************
3167 * RtlSizeHeap
3168 * PARAMS
3169 * Heap [in] Handle of heap
3170 * Flags [in] Heap size control flags
3171 * Ptr [in] Address of memory to return size for
3172 *
3173 * RETURNS
3174 * Size in bytes of allocated memory
3175 * 0xffffffff: Failure
3176 *
3177 * @implemented
3178 */
3181 HANDLE HeapPtr,
3182 ULONG Flags,
3183 PVOID Ptr
3184)
3185{
3186 PHEAP Heap = (PHEAP)HeapPtr;
3187 PHEAP_ENTRY HeapEntry;
3189
3190 // FIXME This is a hack around missing SEH support!
3191 if (!Heap)
3192 {
3194 return (SIZE_T)-1;
3195 }
3196
3197 /* Force flags */
3198 Flags |= Heap->ForceFlags;
3199
3200 /* Call special heap */
3202 return RtlDebugSizeHeap(Heap, Flags, Ptr);
3203
3204 /* Get the heap entry pointer */
3205 HeapEntry = (PHEAP_ENTRY)Ptr - 1;
3206
3207 /* Return -1 if that entry is free */
3208 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3209 {
3211 return (SIZE_T)-1;
3212 }
3213
3214 /* Get size of this block depending if it's a usual or a big one */
3215 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
3216 {
3217 EntrySize = RtlpGetSizeOfBigBlock(HeapEntry);
3218 }
3219 else
3220 {
3221 /* Calculate it */
3222 EntrySize = (HeapEntry->Size << HEAP_ENTRY_SHIFT) - HeapEntry->UnusedBytes;
3223 }
3224
3225 /* Return calculated size */
3226 return EntrySize;
3227}
3228
3231{
3233 PCHAR TailPart;
3234
3235 /* Calculate size */
3236 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
3237 Size = RtlpGetSizeOfBigBlock(HeapEntry);
3238 else
3239 Size = (HeapEntry->Size << HEAP_ENTRY_SHIFT) - HeapEntry->UnusedBytes;
3240
3241 /* Calculate pointer to the tail part of the block */
3242 TailPart = (PCHAR)(HeapEntry + 1) + Size;
3243
3244 /* Compare tail pattern */
3245 Result = RtlCompareMemory(TailPart,
3248
3249 if (Result != HEAP_ENTRY_SIZE)
3250 {
3251 DPRINT1("HEAP: Heap entry (size %x) %p tail is modified at %p\n", Size, HeapEntry, TailPart + Result);
3252 return FALSE;
3253 }
3254
3255 /* All is fine */
3256 return TRUE;
3257}
3258
3261 PHEAP Heap,
3262 BOOLEAN Recalculate)
3263{
3264 // We skip header validation for now
3265 return TRUE;
3266}
3267
3270 PHEAP Heap,
3271 PHEAP_ENTRY HeapEntry)
3272{
3273 BOOLEAN BigAllocation, EntryFound = FALSE;
3275 ULONG SegmentOffset;
3276
3277 /* Perform various consistency checks of this entry */
3278 if (!HeapEntry) goto invalid_entry;
3279 if ((ULONG_PTR)HeapEntry & (HEAP_ENTRY_SIZE - 1)) goto invalid_entry;
3280 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY)) goto invalid_entry;
3281
3282 BigAllocation = HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC;
3283 Segment = Heap->Segments[HeapEntry->SegmentOffset];
3284
3285 if (BigAllocation &&
3286 (((ULONG_PTR)HeapEntry & (PAGE_SIZE - 1)) != FIELD_OFFSET(HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock)))
3287 goto invalid_entry;
3288
3289 if (!BigAllocation && (HeapEntry->SegmentOffset >= HEAP_SEGMENTS ||
3290 !Segment ||
3291 HeapEntry < Segment->FirstEntry ||
3292 HeapEntry >= Segment->LastValidEntry))
3293 goto invalid_entry;
3294
3295 if ((HeapEntry->Flags & HEAP_ENTRY_FILL_PATTERN) &&
3296 !RtlpCheckInUsePattern(HeapEntry))
3297 goto invalid_entry;
3298
3299 /* Checks are done, if this is a virtual entry, that's all */
3300 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) return TRUE;
3301
3302 /* Go through segments and check if this entry fits into any of them */
3303 for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
3304 {
3305 Segment = Heap->Segments[SegmentOffset];
3306 if (!Segment) continue;
3307
3308 if ((HeapEntry >= Segment->FirstEntry) &&
3309 (HeapEntry < Segment->LastValidEntry))
3310 {
3311 /* Got it */
3312 EntryFound = TRUE;
3313 break;
3314 }
3315 }
3316
3317 /* Return our result of finding entry in the segments */
3318 return EntryFound;
3319
3320invalid_entry:
3321 DPRINT1("HEAP: Invalid heap entry %p in heap %p\n", HeapEntry, Heap);
3322 return FALSE;
3323}
3324
3327 PHEAP Heap,
3329 UCHAR SegmentOffset,
3330 PULONG FreeEntriesCount,
3331 PSIZE_T TotalFreeSize,
3332 PSIZE_T TagEntries,
3333 PSIZE_T PseudoTagEntries)
3334{
3335 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
3336 PLIST_ENTRY UcrEntry;
3338 PHEAP_ENTRY CurrentEntry;
3339 ULONG UnCommittedPages;
3340 ULONG UnCommittedRanges;
3341 ULONG PreviousSize;
3342
3343 UnCommittedPages = 0;
3344 UnCommittedRanges = 0;
3345
3346 if (IsListEmpty(&Segment->UCRSegmentList))
3347 {
3348 UcrEntry = NULL;
3349 UcrDescriptor = NULL;
3350 }
3351 else
3352 {
3353 UcrEntry = Segment->UCRSegmentList.Flink;
3354 UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
3355 }
3356
3357 if (Segment->BaseAddress == Heap)
3358 CurrentEntry = &Heap->Entry;
3359 else
3360 CurrentEntry = &Segment->Entry;
3361
3362 while (CurrentEntry < Segment->LastValidEntry)
3363 {
3364 if (UcrDescriptor &&
3365 ((PVOID)CurrentEntry >= UcrDescriptor->Address))
3366 {
3367 DPRINT1("HEAP: Entry %p is not inside uncommited range [%p .. %p)\n",
3368 CurrentEntry, UcrDescriptor->Address,
3369 (PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
3370
3371 return FALSE;
3372 }
3373
3374 PreviousSize = 0;
3375
3376 while (CurrentEntry < Segment->LastValidEntry)
3377 {
3378 if (PreviousSize != CurrentEntry->PreviousSize)
3379 {
3380 DPRINT1("HEAP: Entry %p has incorrect PreviousSize %x instead of %x\n",
3381 CurrentEntry, CurrentEntry->PreviousSize, PreviousSize);
3382
3383 return FALSE;
3384 }
3385
3386 PreviousSize = CurrentEntry->Size;
3387 Size = CurrentEntry->Size << HEAP_ENTRY_SHIFT;
3388
3389 if (CurrentEntry->Flags & HEAP_ENTRY_BUSY)
3390 {
3391 if (TagEntries)
3392 {
3394 }
3395
3396 /* Check fill pattern */
3397 if (CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN)
3398 {
3399 if (!RtlpCheckInUsePattern(CurrentEntry))
3400 return FALSE;
3401 }
3402 }
3403 else
3404 {
3405 /* The entry is free, increase free entries count and total free size */
3406 *FreeEntriesCount = *FreeEntriesCount + 1;
3407 *TotalFreeSize += CurrentEntry->Size;
3408
3409 if ((Heap->Flags & HEAP_FREE_CHECKING_ENABLED) &&
3410 (CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN))
3411 {
3412 ByteSize = Size - sizeof(HEAP_FREE_ENTRY);
3413
3414 if ((CurrentEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT) &&
3415 (ByteSize > sizeof(HEAP_FREE_ENTRY_EXTRA)))
3416 {
3418 }
3419
3420 Result = RtlCompareMemoryUlong((PCHAR)((PHEAP_FREE_ENTRY)CurrentEntry + 1),
3421 ByteSize,
3423
3424 if (Result != ByteSize)
3425 {
3426 DPRINT1("HEAP: Free heap block %p modified at %p after it was freed\n",
3427 CurrentEntry,
3428 (PCHAR)(CurrentEntry + 1) + Result);
3429
3430 return FALSE;
3431 }
3432 }
3433 }
3434
3435 if (CurrentEntry->SegmentOffset != SegmentOffset)
3436 {
3437 DPRINT1("HEAP: Heap entry %p SegmentOffset is incorrect %x (should be %x)\n",
3438 CurrentEntry, SegmentOffset, CurrentEntry->SegmentOffset);
3439 return FALSE;
3440 }
3441
3442 /* Check if it's the last entry */
3443 if (CurrentEntry->Flags & HEAP_ENTRY_LAST_ENTRY)
3444 {
3445 CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
3446
3447 if (!UcrDescriptor)
3448 {
3449 /* Check if it's not really the last one */
3450 if (CurrentEntry != Segment->LastValidEntry)
3451 {
3452 DPRINT1("HEAP: Heap entry %p is not last block in segment (%p)\n",
3453 CurrentEntry, Segment->LastValidEntry);
3454 return FALSE;
3455 }
3456 }
3457 else if (CurrentEntry != UcrDescriptor->Address)
3458 {
3459 DPRINT1("HEAP: Heap entry %p does not match next uncommitted address (%p)\n",
3460 CurrentEntry, UcrDescriptor->Address);
3461
3462 return FALSE;
3463 }
3464 else
3465 {
3466 UnCommittedPages += (ULONG)(UcrDescriptor->Size / PAGE_SIZE);
3467 UnCommittedRanges++;
3468
3469 CurrentEntry = (PHEAP_ENTRY)((PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
3470
3471 /* Go to the next UCR descriptor */
3472 UcrEntry = UcrEntry->Flink;
3473 if (UcrEntry == &Segment->UCRSegmentList)
3474 {
3475 UcrEntry = NULL;
3476 UcrDescriptor = NULL;
3477 }
3478 else
3479 {
3480 UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
3481 }
3482 }
3483
3484 break;
3485 }
3486
3487 /* Advance to the next entry */
3488 CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
3489 }
3490 }
3491
3492 /* Check total numbers of UCP and UCR */
3493 if (Segment->NumberOfUnCommittedPages != UnCommittedPages)
3494 {
3495 DPRINT1("HEAP: Segment %p NumberOfUnCommittedPages is invalid (%x != %x)\n",
3496 Segment, Segment->NumberOfUnCommittedPages, UnCommittedPages);
3497
3498 return FALSE;
3499 }
3500
3501 if (Segment->NumberOfUnCommittedRanges != UnCommittedRanges)
3502 {
3503 DPRINT1("HEAP: Segment %p NumberOfUnCommittedRanges is invalid (%x != %x)\n",
3504 Segment, Segment->NumberOfUnCommittedRanges, UnCommittedRanges);
3505
3506 return FALSE;
3507 }
3508
3509 return TRUE;
3510}
3511
3514 BOOLEAN ForceValidation)
3515{
3516 UCHAR SegmentOffset;
3517 SIZE_T TotalFreeSize;
3518 PLIST_ENTRY ListHead, NextEntry;
3519 ULONG FreeBlocksCount, FreeListEntriesCount;
3521
3522 /* Check headers */
3523 if (!RtlpValidateHeapHeaders(Heap, FALSE))
3524 return FALSE;
3525
3526 /* Skip validation if it's not needed */
3527 if (!ForceValidation && !(Heap->Flags & HEAP_VALIDATE_ALL_ENABLED))
3528 return TRUE;
3529
3530 /* Check free list */
3531 FreeListEntriesCount = 0;
3532 ListHead = &Heap->FreeLists;
3533 NextEntry = ListHead->Flink;
3534
3535 while (NextEntry != ListHead)
3536 {
3537 PHEAP_FREE_ENTRY FreeEntry = CONTAINING_RECORD(NextEntry, HEAP_FREE_ENTRY, FreeList);
3538
3539 NextEntry = NextEntry->Flink;
3540
3541 if (NextEntry != ListHead)
3542 {
3543 PHEAP_FREE_ENTRY NextFreeEntry = CONTAINING_RECORD(NextEntry, HEAP_FREE_ENTRY, FreeList);
3544 /* Free entries must be sorted */
3545 if (FreeEntry->Size > NextFreeEntry->Size)
3546 {
3547 DPRINT1("Dedicated free entry %p of size %ld is not put in order.\n", FreeEntry, FreeEntry->Size);
3548 }
3549 }
3550
3551 /* Check that the hint is there */
3552 if (FreeEntry->Size > Heap->DeCommitFreeBlockThreshold)
3553 {
3554 if (Heap->FreeHints[0] == NULL)
3555 {
3556 DPRINT1("No hint pointing to the non-dedicated list although there is a free entry %p of size %ld.\n",
3557 FreeEntry, FreeEntry->Size);
3558 }
3559 if (!RtlTestBit(&Heap->FreeHintBitmap, 0))
3560 {
3561 DPRINT1("Hint bit 0 is not set although there is a free entry %p of size %ld.\n",
3562 FreeEntry, FreeEntry->Size);
3563 }
3564 }
3565 else
3566 {
3567 if (Heap->FreeHints[FreeEntry->Size - 1] == NULL)
3568 {
3569 DPRINT1("No hint pointing to the dedicated list although there is a free entry %p of size %ld.\n",
3570 FreeEntry, FreeEntry->Size);
3571 }
3572 if (!RtlTestBit(&Heap->FreeHintBitmap, FreeEntry->Size - 1))
3573 {
3574 DPRINT1("Hint bit 0 is not set although there is a free entry %p of size %ld.\n",
3575 FreeEntry, FreeEntry->Size);
3576 }
3577 }
3578
3579 /* If there is an in-use entry in a free list - that's quite a big problem */
3580 if (FreeEntry->Flags & HEAP_ENTRY_BUSY)
3581 {
3582 DPRINT1("HEAP: Free element %p is marked in-use\n", FreeEntry);
3583 return FALSE;
3584 }
3585
3586 /* Add up to the total amount of free entries */
3587 FreeListEntriesCount++;
3588 }
3589
3590 /* Check free list hints */
3592 {
3593 if (Heap->FreeHints[HintIndex] != NULL)
3594 {
3596
3597 if (!RtlTestBit(&Heap->FreeHintBitmap, HintIndex))
3598 {
3599 DPRINT1("Hint bitmap bit at %u is not set, but there is a hint entry.\n", HintIndex);
3600 }
3601
3602 if (HintIndex == 0)
3603 {
3604 if (FreeEntry->Size <= Heap->DeCommitFreeBlockThreshold)
3605 {
3606 DPRINT1("There is an entry %p of size %lu, smaller than the decommit threshold %lu in the non-dedicated free list hint.\n",
3607 FreeEntry, FreeEntry->Size, Heap->DeCommitFreeBlockThreshold);
3608 }
3609 }
3610 else
3611 {
3612 if (HintIndex != FreeEntry->Size - 1)
3613 {
3614 DPRINT1("There is an entry %p of size %lu at the position %u in the free entry hint array.\n",
3615 FreeEntry, FreeEntry->Size, HintIndex);
3616 }
3617
3618 if (FreeEntry->FreeList.Blink != &Heap->FreeLists)
3619 {
3620 /* The entry right before the hint must be smaller. */
3621 PHEAP_FREE_ENTRY PreviousFreeEntry = CONTAINING_RECORD(FreeEntry->FreeList.Blink,
3623 FreeList);
3624 if (PreviousFreeEntry->Size >= FreeEntry->Size)
3625 {
3626 DPRINT1("Free entry hint %p of size %lu is larger than the entry before it %p, which is of size %lu.\n",
3627 FreeEntry, FreeEntry->Size, PreviousFreeEntry, PreviousFreeEntry->Size);
3628 }
3629 }
3630 }
3631 }
3632 else if (RtlTestBit(&Heap->FreeHintBitmap, HintIndex))
3633 {
3634 DPRINT1("Hint bitmap bit at %u is set, but there is no hint entry.\n", HintIndex);
3635 }
3636 }
3637
3638 /* Check big allocations */
3639 ListHead = &Heap->VirtualAllocdBlocks;
3640 NextEntry = ListHead->Flink;
3641
3642 while (ListHead != NextEntry)
3643 {
3645
3646 /* We can only check the fill pattern */
3647 if (VirtualAllocBlock->BusyBlock.Flags & HEAP_ENTRY_FILL_PATTERN)
3648 {
3649 if (!RtlpCheckInUsePattern(&VirtualAllocBlock->BusyBlock))
3650 return FALSE;
3651 }
3652
3653 NextEntry = NextEntry->Flink;
3654 }
3655
3656 /* Check all segments */
3657 FreeBlocksCount = 0;
3658 TotalFreeSize = 0;
3659
3660 for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
3661 {
3662 PHEAP_SEGMENT Segment = Heap->Segments[SegmentOffset];
3663
3664 /* Go to the next one if there is no segment */
3665 if (!Segment) continue;
3666
3667 if (!RtlpValidateHeapSegment(Heap,
3668 Segment,
3669 SegmentOffset,
3670 &FreeBlocksCount,
3671 &TotalFreeSize,
3672 NULL,
3673 NULL))
3674 {
3675 return FALSE;
3676 }
3677 }
3678
3679 if (FreeListEntriesCount != FreeBlocksCount)
3680 {
3681 DPRINT1("HEAP: Free blocks count in arena (%lu) does not match free blocks number in the free lists (%lu)\n", FreeBlocksCount, FreeListEntriesCount);
3682 return FALSE;
3683 }
3684
3685 if (Heap->TotalFreeSize != TotalFreeSize)
3686 {
3687 DPRINT1("HEAP: Total size of free blocks in arena (%Iu) does not equal to the one in heap header (%Iu)\n", TotalFreeSize, Heap->TotalFreeSize);
3688 return FALSE;
3689 }
3690
3691 return TRUE;
3692}
3693
3694/***********************************************************************
3695 * RtlValidateHeap
3696 * Validates a specified heap.
3697 *
3698 * PARAMS
3699 * Heap [in] Handle to the heap
3700 * Flags [in] Bit flags that control access during operation
3701 * Block [in] Optional pointer to memory block to validate
3702 *
3703 * NOTES
3704 * Flags is ignored.
3705 *
3706 * RETURNS
3707 * TRUE: Success
3708 * FALSE: Failure
3709 *
3710 * @implemented
3711 */
3713 HANDLE HeapPtr,
3714 ULONG Flags,
3715 PVOID Block
3716)
3717{
3718 PHEAP Heap = (PHEAP)HeapPtr;
3719 BOOLEAN HeapLocked = FALSE;
3720 BOOLEAN HeapValid;
3721
3722 /* Check for page heap */
3724 return RtlpDebugPageHeapValidate(HeapPtr, Flags, Block);
3725
3726 /* Check signature */
3727 if (Heap->Signature != HEAP_SIGNATURE)
3728 {
3729 DPRINT1("HEAP: Signature %lx is invalid for heap %p\n", Heap->Signature, Heap);
3730 return FALSE;
3731 }
3732
3733 /* Force flags */
3734 Flags |= Heap->ForceFlags;
3735
3736 /* Acquire the lock if necessary */
3737 if (!(Flags & HEAP_NO_SERIALIZE))
3738 {
3740 HeapLocked = TRUE;
3741 }
3742
3743 /* Either validate whole heap or just one entry */
3744 if (!Block)
3745 HeapValid = RtlpValidateHeap(Heap, TRUE);
3746 else
3747 HeapValid = RtlpValidateHeapEntry(Heap, (PHEAP_ENTRY)Block - 1);
3748
3749 /* Unlock if it's lockable */
3750 if (HeapLocked)
3751 {
3753 }
3754
3755 return HeapValid;
3756}
3757
3758/*
3759 * @unimplemented
3760 */
3763 PVOID lParam)
3764{
3767}
3768
3769/*
3770 * @unimplemented
3771 */
3774{
3776 return TRUE;
3777}
3778
3779
3780/*
3781 * @unimplemented
3782 */
3785 IN PVOID HeapHandle,
3786 IN ULONG Flags
3787 )
3788{
3790 return FALSE;
3791}
3792
3793/*
3794 * @implemented
3795 */
3796BOOLEAN
3797NTAPI
3799 IN ULONG Flags,
3801 IN PVOID UserValue)
3802{
3803 PHEAP Heap = (PHEAP)HeapHandle;
3804 PHEAP_ENTRY HeapEntry;
3805 PHEAP_ENTRY_EXTRA Extra;
3806 BOOLEAN HeapLocked = FALSE, ValueSet = FALSE;
3807
3808 /* Force flags */
3809 Flags |= Heap->ForceFlags;
3810
3811 /* Call special heap */
3813 return RtlDebugSetUserValueHeap(Heap, Flags, BaseAddress, UserValue);
3814
3815 /* Lock if it's lockable */
3816 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3817 {
3819 HeapLocked = TRUE;
3820 }
3821
3822 /* Get a pointer to the entry */
3823 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
3824
3825 /* If it's a free entry - return error */
3826 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3827 {
3829
3830 /* Release the heap lock if it was acquired */
3831 if (HeapLocked)
3833
3834 return FALSE;
3835 }
3836
3837 /* Check if this entry has an extra stuff associated with it */
3838 if (HeapEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
3839 {
3840 /* Use extra to store the value */
3841 Extra = RtlpGetExtraStuffPointer(HeapEntry);
3842 Extra->Settable = (ULONG_PTR)UserValue;
3843
3844 /* Indicate that value was set */
3845 ValueSet = TRUE;
3846 }
3847
3848 /* Release the heap lock if it was acquired */
3849 if (HeapLocked)
3851
3852 return ValueSet;
3853}
3854
3855/*
3856 * @implemented
3857 */
3858BOOLEAN
3859NTAPI
3861 IN ULONG Flags,
3863 IN ULONG UserFlagsReset,
3864 IN ULONG UserFlagsSet)
3865{
3866 PHEAP Heap = (PHEAP)HeapHandle;
3867 PHEAP_ENTRY HeapEntry;
3868 BOOLEAN HeapLocked = FALSE;
3869
3870 /* Force flags */
3871 Flags |= Heap->ForceFlags;
3872
3873 /* Call special heap */
3875 return RtlDebugSetUserFlagsHeap(Heap, Flags, BaseAddress, UserFlagsReset, UserFlagsSet);
3876
3877 /* Lock if it's lockable */
3878 if (!(Flags & HEAP_NO_SERIALIZE))
3879 {
3881 HeapLocked = TRUE;
3882 }
3883
3884 /* Get a pointer to the entry */
3885 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
3886
3887 /* If it's a free entry - return error */
3888 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3889 {
3891
3892 /* Release the heap lock if it was acquired */
3893 if (HeapLocked)
3895
3896 return FALSE;
3897 }
3898
3899 /* Set / reset flags */
3900 HeapEntry->Flags &= ~(UserFlagsReset >> 4);
3901 HeapEntry->Flags |= (UserFlagsSet >> 4);
3902
3903 /* Release the heap lock if it was acquired */
3904 if (HeapLocked)
3906
3907 return TRUE;
3908}
3909
3910/*
3911 * @implemented
3912 */
3913BOOLEAN
3914NTAPI
3916 IN ULONG Flags,
3918 OUT PVOID *UserValue,
3919 OUT PULONG UserFlags)
3920{
3921 PHEAP Heap = (PHEAP)HeapHandle;
3922 PHEAP_ENTRY HeapEntry;
3923 PHEAP_ENTRY_EXTRA Extra;
3924 BOOLEAN HeapLocked = FALSE;
3925
3926 /* Force flags */
3927 Flags |= Heap->ForceFlags;
3928
3929 /* Call special heap */
3931 return RtlDebugGetUserInfoHeap(Heap, Flags, BaseAddress, UserValue, UserFlags);
3932
3933 /* Lock if it's lockable */
3934 if (!(Flags & HEAP_NO_SERIALIZE))
3935 {
3937 HeapLocked = TRUE;
3938 }
3939
3940 /* Get a pointer to the entry */
3941 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
3942
3943 /* If it's a free entry - return error */
3944 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3945 {
3947
3948 /* Release the heap lock if it was acquired */
3949 if (HeapLocked)
3951
3952 return FALSE;
3953 }
3954
3955 /* Check if this entry has an extra stuff associated with it */
3956 if (HeapEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
3957 {
3958 /* Get pointer to extra data */
3959 Extra = RtlpGetExtraStuffPointer(HeapEntry);
3960
3961 /* Pass user value */
3962 if (UserValue)
3963 *UserValue = (PVOID)Extra->Settable;
3964 }
3965
3966 /* Decode and return user flags */
3967 if (UserFlags)
3968 *UserFlags = (HeapEntry->Flags & HEAP_ENTRY_SETTABLE_FLAGS) << 4;
3969
3970 /* Release the heap lock if it was acquired */
3971 if (HeapLocked)
3973
3974 return TRUE;
3975}
3976
3977/*
3978 * @unimplemented
3979 */
3981NTAPI
3983 IN ULONG Flags,
3985{
3986 /* TODO */
3989}
3990
3991PWSTR
3992NTAPI
3994 IN ULONG Flags,
3995 IN USHORT TagIndex,
3996 IN BOOLEAN ResetCounters,
3997 OUT PRTL_HEAP_TAG_INFO HeapTagInfo)
3998{
3999 /* TODO */
4001 return NULL;
4002}
4003
4004ULONG
4005NTAPI
4007 IN ULONG Flags,
4008 IN PVOID P,
4009 IN SIZE_T Size)
4010{
4011 /* TODO */
4013 return 0;
4014}
4015
4016ULONG
4017NTAPI
4020 _In_opt_ PWSTR TagName,
4021 _In_ PWSTR TagSubName)
4022{
4023 /* TODO */
4025 return 0;
4026}
4027
4029NTAPI
4031 IN PVOID HeapEntry)
4032{
4035}
4036
4037PVOID
4038NTAPI
4041{
4043 return NULL;
4044}
4045
4047NTAPI
4049 IN HEAP_INFORMATION_CLASS HeapInformationClass,
4050 IN PVOID HeapInformation,
4051 IN SIZE_T HeapInformationLength)
4052{
4053 /* Setting heap information is not really supported except for enabling LFH */
4054 if (HeapInformationClass == HeapCompatibilityInformation)
4055 {
4056 /* Check buffer length */
4057 if (HeapInformationLength < sizeof(ULONG))
4058 {
4059 /* The provided buffer is too small */
4061 }
4062
4063 /* Check for a special magic value for enabling LFH */
4064 if (*(PULONG)HeapInformation != 2)
4065 {
4066 return STATUS_UNSUCCESSFUL;
4067 }
4068
4069 DPRINT1("RtlSetHeapInformation() needs to enable LFH\n");
4070 return STATUS_SUCCESS;
4071 }
4072
4073 return STATUS_SUCCESS;
4074}
4075
4077NTAPI
4079 HEAP_INFORMATION_CLASS HeapInformationClass,
4080 PVOID HeapInformation,
4081 SIZE_T HeapInformationLength,
4083{
4084 PHEAP Heap = (PHEAP)HeapHandle;
4085
4086 /* Only HeapCompatibilityInformation is supported */
4087 if (HeapInformationClass == HeapCompatibilityInformation)
4088 {
4089 /* Set result length */
4090 if (ReturnLength)
4091 *ReturnLength = sizeof(ULONG);
4092
4093 /* Check buffer length */
4094 if (HeapInformationLength < sizeof(ULONG))
4095 {
4096 /* It's too small, return needed length */
4098 }
4099
4100 /* Return front end heap type */
4101 *(PULONG)HeapInformation = Heap->FrontEndHeapType;
4102
4103 return STATUS_SUCCESS;
4104 }
4105
4106 return STATUS_UNSUCCESSFUL;
4107}
4108
4109/* @implemented */
4110ULONG
4111NTAPI
4113 IN ULONG Flags,
4114 IN SIZE_T Size,
4115 IN ULONG Count,
4116 OUT PVOID *Array)
4117{
4118 ULONG Index;
4119 EXCEPTION_RECORD ExceptionRecord;
4120
4121 for (Index = 0; Index < Count; ++Index)
4122 {
4123 Array[Index] = RtlAllocateHeap(HeapHandle, Flags, Size);
4124 if (Array[Index] == NULL)
4125 {
4126 /* ERROR_NOT_ENOUGH_MEMORY */
4128
4130 {
4131 ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
4132 ExceptionRecord.ExceptionRecord = NULL;
4133 ExceptionRecord.NumberParameters = 0;
4134 ExceptionRecord.ExceptionFlags = 0;
4135
4136 RtlRaiseException(&ExceptionRecord);
4137 }
4138 break;
4139 }
4140 }
4141
4142 return Index;
4143}
4144
4145/* @implemented */
4146ULONG
4147NTAPI
4149 IN ULONG Flags,
4150 IN ULONG Count,
4151 OUT PVOID *Array)
4152{
4153 ULONG Index;
4154
4155 for (Index = 0; Index < Count; ++Index)
4156 {
4157 if (Array[Index] == NULL)
4158 continue;
4159
4160 _SEH2_TRY
4161 {
4162 if (!RtlFreeHeap(HeapHandle, Flags, Array[Index]))
4163 {
4164 /* ERROR_INVALID_PARAMETER */
4166 break;
4167 }
4168 }
4170 {
4171 /* ERROR_INVALID_PARAMETER */
4173 break;
4174 }
4175 _SEH2_END;
4176 }
4177
4178 return Index;
4179}
4180
4181/*
4182 * Info:
4183 * - https://securityxploded.com/enumheaps.php
4184 * - https://evilcodecave.wordpress.com/2009/04/14/rtlqueryprocessheapinformation-as-anti-dbg-trick/
4185 */
4186struct _DEBUG_BUFFER;
4187
4189NTAPI
4191 IN struct _DEBUG_BUFFER *DebugBuffer)
4192{
4195}
4196
4197/* EOF */
4198
#define NtCurrentPeb()
Definition: FLS.c:22
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
HANDLE ProcessHeap
Definition: servman.c:15
#define DPRINT1
Definition: precomp.h:8
#define UNIMPLEMENTED
Definition: debug.h:115
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:590
struct _HEAP * PHEAP
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:608
LPARAM lParam
Definition: combotst.c:139
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
NTSTATUS NTAPI RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock)
Definition: libsupp.c:126
NTSTATUS NTAPI RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
Definition: libsupp.c:108
KPROCESSOR_MODE NTAPI RtlpGetMode(VOID)
Definition: libsupp.c:53
VOID NTAPI RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters)
Definition: libsupp.c:174
NTSTATUS NTAPI RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock)
Definition: libsupp.c:101
NTSTATUS NTAPI RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock)
Definition: libsupp.c:133
#define P(row, col)
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
#define ULONG_PTR
Definition: config.h:101
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:43
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:33
IN PFCB IN PFILE_OBJECT FileObject IN ULONG AllocationSize
Definition: fatprocs.h:322
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInfoClass, OUT PVOID SystemInfoBuffer, IN ULONG SystemInfoBufferSize, OUT PULONG BytesReturned OPTIONAL)
@ SystemBasicInformation
Definition: ntddk_ex.h:11
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_Must_inspect_result_ _In_ USAGE _In_ USHORT _In_ USAGE Usage
Definition: hidpi.h:384
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define FLG_HEAP_DISABLE_COALESCING
Definition: pstypes.h:80
#define FLG_USER_STACK_TRACE_DB
Definition: pstypes.h:67
#define FLG_HEAP_ENABLE_FREE_CHECK
Definition: pstypes.h:61
#define FLG_HEAP_VALIDATE_PARAMETERS
Definition: pstypes.h:62
#define FLG_HEAP_ENABLE_TAIL_CHECK
Definition: pstypes.h:60
#define FLG_HEAP_VALIDATE_ALL
Definition: pstypes.h:63
#define RtlFillMemory(Dest, Length, Fill)
Definition: winternl.h:599
NTSYSAPI void WINAPI RtlInitializeBitMap(PRTL_BITMAP, PULONG, ULONG)
NTSYSAPI void WINAPI RtlSetLastWin32ErrorAndNtStatusFromNtStatus(NTSTATUS)
NTSYSAPI void WINAPI RtlClearAllBits(PRTL_BITMAP)
NTSYSAPI ULONG WINAPI RtlFindSetBits(PCRTL_BITMAP, ULONG, ULONG)
NTSYSAPI ULONG WINAPI RtlGetNtGlobalFlags(void)
Definition: libsupp.c:93
#define LOBYTE(W)
Definition: jmemdos.c:487
#define HIBYTE(W)
Definition: jmemdos.c:486
#define ARENA_FREE_FILLER
Definition: jsutils.c:64
if(dx< 0)
Definition: linetemp.h:194
#define RtlFillMemoryUlong(dst, len, val)
Definition: mkhive.h:55
#define PCHAR
Definition: match.c:90
#define ASSERT(a)
Definition: mode.c:44
static PVOID
Definition: heap.c:41
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
#define KernelMode
Definition: asm.h:34
#define UserMode
Definition: asm.h:35
NTSYSAPI NTSTATUS NTAPI ZwQueryVirtualMemory(_In_ HANDLE ProcessHandle, _In_ PVOID Address, _In_ MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass, _Out_ PVOID VirtualMemoryInformation, _In_ SIZE_T Length, _Out_opt_ PSIZE_T ResultLength)
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T CommitSize
Definition: mmfuncs.h:406
@ MemoryBasicInformation
Definition: mmtypes.h:183
#define PAGE_ROUND_UP(x)
Definition: mmtypes.h:38
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
NTSYSAPI VOID NTAPI RtlRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord)
@ HeapCompatibilityInformation
Definition: rtltypes.h:488
#define HEAP_SKIP_VALIDATION_CHECKS
Definition: rtltypes.h:165
NTSTATUS(NTAPI * PHEAP_ENUMERATION_ROUTINE)(_In_ PVOID HeapHandle, _In_ PVOID UserParam)
Definition: rtltypes.h:558
#define HEAP_LOCK_USER_ALLOCATED
Definition: rtltypes.h:168
struct _HEAP_LOCK * PHEAP_LOCK
#define HEAP_VALIDATE_ALL_ENABLED
Definition: rtltypes.h:166
#define HEAP_CAPTURE_STACK_BACKTRACES
Definition: rtltypes.h:164
#define HEAP_VALIDATE_PARAMETERS_ENABLED
Definition: rtltypes.h:167
struct _HEAP_LOCK HEAP_LOCK
#define HEAP_FLAG_PAGE_ALLOCS
Definition: rtltypes.h:160
enum _HEAP_INFORMATION_CLASS HEAP_INFORMATION_CLASS
_In_ PMEMORY_AREA _In_ PVOID _In_ BOOLEAN Locked
Definition: newmm.h:209
int Count
Definition: noreturn.cpp:7
#define MEM_FREE
Definition: nt_native.h:1317
#define MEM_DECOMMIT
Definition: nt_native.h:1315
#define HEAP_FREE_CHECKING_ENABLED
Definition: nt_native.h:1698
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define HEAP_DISABLE_COALESCE_ON_FREE
Definition: nt_native.h:1699
#define HEAP_GENERATE_EXCEPTIONS
Definition: nt_native.h:1694
#define HEAP_TAIL_CHECKING_ENABLED
Definition: nt_native.h:1697
#define NtCurrentProcess()
Definition: nt_native.h:1657
#define HEAP_GROWABLE
Definition: nt_native.h:1693
#define HEAP_TAG_SHIFT
Definition: nt_native.h:1724
#define HEAP_SETTABLE_USER_VALUE
Definition: nt_native.h:1704
#define HEAP_SETTABLE_USER_FLAGS
Definition: nt_native.h:1708
#define HEAP_CREATE_ALIGN_16
Definition: nt_native.h:1701
#define MEM_RESERVE
Definition: nt_native.h:1314
#define HEAP_PSEUDO_TAG_FLAG
Definition: nt_native.h:1723
#define MEM_RELEASE
Definition: nt_native.h:1316
#define HEAP_CREATE_VALID_MASK
Definition: nt_native.h:1728
#define HEAP_REALLOC_IN_PLACE_ONLY
Definition: nt_native.h:1696
#define HEAP_CREATE_ENABLE_TRACING
Definition: nt_native.h:1702
#define MEM_COMMIT
Definition: nt_native.h:1313
#define HEAP_NO_SERIALIZE
Definition: nt_native.h:1692
#define RTL_BITS_OF(sizeOfArg)
Definition: ntbasedef.h:668
BOOLEAN RtlpPageHeapEnabled
Definition: heappage.c:107
VOID NTAPI RtlpAddHeapToProcessList(struct _HEAP *Heap)
Definition: libsupp.c:230
VOID NTAPI RtlpRemoveHeapFromProcessList(struct _HEAP *Heap)
Definition: libsupp.c:237
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:245
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#define ARENA_INUSE_FILLER
Definition: oleaut.c:105
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
static WCHAR Address[46]
Definition: ping.c:68
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
@ ReadOnly
Definition: arc.h:80
VOID NTAPI RtlClearBit(_In_ PRTL_BITMAP BitMapHeader, _In_ BITMAP_INDEX BitNumber)
Definition: bitmap.c:294
HANDLE NTAPI RtlDestroyHeap(HANDLE HeapPtr)
Definition: heap.c:1729
PHEAP_FREE_ENTRY NTAPI RtlpCoalesceFreeBlocks(PHEAP Heap, PHEAP_FREE_ENTRY FreeEntry, PSIZE_T FreeSize, BOOLEAN Remove)
Definition: heap.c:1150
UCHAR FillPattern[HEAP_ENTRY_SIZE]
Definition: heap.c:72
FORCEINLINE UCHAR RtlpFindLeastSetBit(ULONG Bits)
Definition: heap.c:53
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)
Definition: heap.c:1002
PHEAP_ENTRY NTAPI RtlpSplitEntry(PHEAP Heap, ULONG Flags, PHEAP_FREE_ENTRY FreeBlock, SIZE_T AllocationSize, SIZE_T Index, SIZE_T Size)
Definition: heap.c:1817
NTSTATUS NTAPI RtlSetHeapInformation(IN HANDLE HeapHandle OPTIONAL, IN HEAP_INFORMATION_CLASS HeapInformationClass, IN PVOID HeapInformation, IN SIZE_T HeapInformationLength)
Definition: heap.c:4048
NTSTATUS NTAPI RtlpInitializeHeap(OUT PHEAP Heap, IN ULONG Flags, IN PHEAP_LOCK Lock OPTIONAL, IN PRTL_HEAP_PARAMETERS Parameters)
Definition: heap.c:106
static BOOLEAN RtlpIsLastCommittedEntry(PHEAP_ENTRY Entry)
Definition: heap.c:86
BOOLEAN NTAPI RtlpValidateHeap(PHEAP Heap, BOOLEAN ForceValidation)
Definition: heap.c:3513
BOOLEAN NTAPI RtlGetUserInfoHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID BaseAddress, OUT PVOID *UserValue, OUT PULONG UserFlags)
Definition: heap.c:3915
NTSTATUS NTAPI RtlUsageHeap(IN HANDLE Heap, IN ULONG Flags, OUT PRTL_HEAP_USAGE Usage)
Definition: heap.c:3982
static PVOID RtlpAllocateNonDedicated(PHEAP Heap, ULONG Flags, SIZE_T Size, SIZE_T AllocationSize, SIZE_T Index, BOOLEAN HeapLocked)
Definition: heap.c:1957
ULONG NTAPI RtlMultipleFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN ULONG Count, OUT PVOID *Array)
Definition: heap.c:4148
BOOLEAN NTAPI RtlValidateHeap(HANDLE HeapPtr, ULONG Flags, PVOID Block)
Definition: heap.c:3712
PVOID NTAPI RtlReAllocateHeap(HANDLE HeapPtr, ULONG Flags, PVOID Ptr, SIZE_T Size)
Definition: heap.c:2667
NTSTATUS NTAPI RtlWalkHeap(IN HANDLE HeapHandle, IN PVOID HeapEntry)
Definition: heap.c:4030
BOOLEAN NTAPI RtlSetUserFlagsHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID BaseAddress, IN ULONG UserFlagsReset, IN ULONG UserFlagsSet)
Definition: heap.c:3860
static PHEAP_FREE_ENTRY RtlpExtendHeap(PHEAP Heap, SIZE_T Size)
Definition: heap.c:1247
BOOLEAN NTAPI RtlpCheckInUsePattern(PHEAP_ENTRY HeapEntry)
Definition: heap.c:3230
VOID NTAPI RtlpInsertUnCommittedPages(PHEAP_SEGMENT Segment, ULONG_PTR Address, SIZE_T Size)
Definition: heap.c:620
PWSTR NTAPI RtlQueryTagHeap(IN PVOID HeapHandle, IN ULONG Flags, IN USHORT TagIndex, IN BOOLEAN ResetCounters, OUT PRTL_HEAP_TAG_INFO HeapTagInfo)
Definition: heap.c:3993
ULONG NTAPI RtlCreateTagHeap(_In_ HANDLE HeapHandle, _In_ ULONG Flags, _In_opt_ PWSTR TagName, _In_ PWSTR TagSubName)
Definition: heap.c:4018
static VOID RtlpDeCommitFreeBlock(PHEAP Heap, PHEAP_FREE_ENTRY FreeEntry, SIZE_T Size)
Definition: heap.c:834
BOOLEAN NTAPI RtlpGrowBlockInPlace(IN PHEAP Heap, IN ULONG Flags, IN PHEAP_ENTRY InUseEntry, IN SIZE_T Size, IN SIZE_T Index)
Definition: heap.c:2392
HANDLE NTAPI RtlCreateHeap(ULONG Flags, PVOID Addr, SIZE_T TotalSize, SIZE_T CommitSize, PVOID Lock, PRTL_HEAP_PARAMETERS Parameters)
Definition: heap.c:1403
SIZE_T NTAPI RtlSizeHeap(HANDLE HeapPtr, ULONG Flags, PVOID Ptr)
Definition: heap.c:3180
VOID NTAPI RtlpInsertFreeBlock(PHEAP Heap, PHEAP_FREE_ENTRY FreeEntry, SIZE_T BlockSize)
Definition: heap.c:357
BOOLEAN NTAPI RtlpValidateHeapHeaders(PHEAP Heap, BOOLEAN Recalculate)
Definition: heap.c:3260
PVOID NTAPI RtlProtectHeap(IN PVOID HeapHandle, IN BOOLEAN ReadOnly)
Definition: heap.c:4039
BOOLEAN NTAPI RtlValidateProcessHeaps(VOID)
Definition: heap.c:3773
VOID NTAPI RtlpInsertFreeBlockHelper(PHEAP Heap, PHEAP_FREE_ENTRY FreeEntry, SIZE_T BlockSize, BOOLEAN NoFill)
Definition: heap.c:238
VOID NTAPI RtlpDestroyUnCommittedRange(PHEAP_SEGMENT Segment, PHEAP_UCR_DESCRIPTOR UcrDescriptor)
Definition: heap.c:608
BOOLEAN NTAPI RtlSetUserValueHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID BaseAddress, IN PVOID UserValue)
Definition: heap.c:3798
BOOLEAN NTAPI RtlUnlockHeap(HANDLE HeapPtr)
Definition: heap.c:3143
PHEAP_UCR_DESCRIPTOR NTAPI RtlpCreateUnCommittedRange(PHEAP_SEGMENT Segment)
Definition: heap.c:513
SIZE_T NTAPI RtlpGetSizeOfBigBlock(PHEAP_ENTRY HeapEntry)
Definition: heap.c:500
ULONG NTAPI RtlExtendHeap(IN HANDLE Heap, IN ULONG Flags, IN PVOID P, IN SIZE_T Size)
Definition: heap.c:4006
PHEAP_FREE_ENTRY NTAPI RtlpCoalesceHeap(PHEAP Heap)
Definition: heap.c:1143
BOOLEAN NTAPI RtlpValidateHeapEntry(PHEAP Heap, PHEAP_ENTRY HeapEntry)
Definition: heap.c:3269
ULONG NTAPI RtlMultipleAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size, IN ULONG Count, OUT PVOID *Array)
Definition: heap.c:4112
NTSTATUS NTAPI RtlQueryProcessHeapInformation(IN struct _DEBUG_BUFFER *DebugBuffer)
Definition: heap.c:4190
UCHAR RtlpBitsClearLow[]
Definition: heap.c:31
PHEAP_ENTRY_EXTRA NTAPI RtlpGetExtraStuffPointer(PHEAP_ENTRY HeapEntry)
Definition: heap.c:2632
NTSTATUS NTAPI RtlQueryHeapInformation(HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength, PSIZE_T ReturnLength OPTIONAL)
Definition: heap.c:4078
VOID NTAPI RtlpDestroyHeapSegment(PHEAP_SEGMENT Segment)
Definition: heap.c:1118
NTSTATUS NTAPI RtlEnumProcessHeaps(PHEAP_ENUMERATION_ROUTINE HeapEnumerationRoutine, PVOID lParam)
Definition: heap.c:3762
BOOLEAN NTAPI RtlpValidateHeapSegment(PHEAP Heap, PHEAP_SEGMENT Segment, UCHAR SegmentOffset, PULONG FreeEntriesCount, PSIZE_T TotalFreeSize, PSIZE_T TagEntries, PSIZE_T PseudoTagEntries)
Definition: heap.c:3326
BOOLEAN NTAPI RtlLockHeap(IN HANDLE HeapPtr)
Definition: heap.c:3106
static PHEAP_FREE_ENTRY RtlpFindAndCommitPages(PHEAP Heap, PHEAP_SEGMENT Segment, PSIZE_T Size, PVOID AddressRequested)
Definition: heap.c:690
ULONG NTAPI RtlCompactHeap(HANDLE Heap, ULONG Flags)
Definition: heap.c:3084
static VOID RtlpRemoveFreeBlock(PHEAP Heap, PHEAP_FREE_ENTRY FreeEntry, BOOLEAN NoFill)
Definition: heap.c:422
BOOLEAN NTAPI RtlZeroHeap(IN PVOID HeapHandle, IN ULONG Flags)
Definition: heap.c:3784
struct _HEAP_ENTRY_EXTRA HEAP_ENTRY_EXTRA
SIZE_T NTAPI RtlDebugSizeHeap(HANDLE HeapPtr, ULONG Flags, PVOID Ptr)
Definition: heapdbg.c:494
PVOID NTAPI RtlDebugAllocateHeap(PVOID HeapPtr, ULONG Flags, SIZE_T Size)
Definition: heapdbg.c:130
BOOLEAN NTAPI RtlDebugSetUserValueHeap(PVOID HeapHandle, ULONG Flags, PVOID BaseAddress, PVOID UserValue)
Definition: heapdbg.c:375
#define HEAP_ENTRY_SHIFT
Definition: heap.h:21
struct _HEAP_UCR_DESCRIPTOR HEAP_UCR_DESCRIPTOR
struct _HEAP_ENTRY * PHEAP_ENTRY
PVOID NTAPI RtlpPageHeapDestroy(HANDLE HeapPtr)
Definition: heappage.c:1674
#define HEAP_ENTRY_EXTRA_PRESENT
Definition: heap.h:41
#define HEAP_EXTRA_FLAGS_MASK
Definition: heap.h:35
BOOLEAN NTAPI RtlpPageHeapLock(HANDLE HeapPtr)
Definition: heappage.c:2415
struct _HEAP_VIRTUAL_ALLOC_ENTRY HEAP_VIRTUAL_ALLOC_ENTRY
struct _HEAP_FREE_ENTRY HEAP_FREE_ENTRY
struct _HEAP_ENTRY_EXTRA * PHEAP_ENTRY_EXTRA
FORCEINLINE BOOLEAN RtlpHeapIsSpecial(ULONG Flags)
Definition: heap.h:59
BOOLEAN NTAPI RtlDebugFreeHeap(HANDLE HeapPtr, ULONG Flags, PVOID Ptr)
Definition: heapdbg.c:267
BOOLEAN NTAPI RtlDebugDestroyHeap(HANDLE HeapPtr)
Definition: heapdbg.c:95
HEAP_ENTRY_EXTRA HEAP_FREE_ENTRY_EXTRA
Definition: heap.h:305
BOOLEAN NTAPI RtlDebugSetUserFlagsHeap(PVOID HeapHandle, ULONG Flags, PVOID BaseAddress, ULONG UserFlagsReset, ULONG UserFlagsSet)
Definition: heapdbg.c:431
NTSYSAPI HANDLE NTAPI RtlDebugCreateHeap(ULONG Flags, PVOID Addr, SIZE_T TotalSize, SIZE_T CommitSize, PVOID Lock, PRTL_HEAP_PARAMETERS Parameters)
Definition: heapdbg.c:20
#define HEAP_TAIL_FILL
Definition: heap.h:27
#define HEAP_SEGMENT_SIGNATURE
Definition: heap.h:52
PVOID NTAPI RtlDebugReAllocateHeap(HANDLE HeapPtr, ULONG Flags, PVOID Ptr, SIZE_T Size)
Definition: heapdbg.c:195
#define HEAP_MAX_BLOCK_SIZE
Definition: heap.h:23
#define HEAP_USER_ALLOCATED
Definition: heap.h:55
#define HEAP_ENTRY_SETTABLE_FLAGS
Definition: heap.h:48
struct _HEAP_UCR_DESCRIPTOR * PHEAP_UCR_DESCRIPTOR
struct _HEAP_FREE_ENTRY * PHEAP_FREE_ENTRY
#define HEAP_SIGNATURE
Definition: heap.h:51
BOOLEAN NTAPI RtlDebugGetUserInfoHeap(PVOID HeapHandle, ULONG Flags, PVOID BaseAddress, PVOID *UserValue, PULONG UserFlags)
Definition: heapdbg.c:322
struct _HEAP_ENTRY HEAP_ENTRY
#define HEAP_ENTRY_SIZE
Definition: heap.h:17
#define HEAP_ENTRY_LAST_ENTRY
Definition: heap.h:44
BOOLEAN NTAPI RtlpPageHeapUnlock(HANDLE HeapPtr)
Definition: heappage.c:2429
BOOLEAN NTAPI RtlpDebugPageHeapValidate(PVOID HeapPtr, ULONG Flags, PVOID Block)
Definition: heappage.c:2351
#define HEAP_SEGMENTS
Definition: heap.h:15
#define HEAP_ENTRY_FILL_PATTERN
Definition: heap.h:42
#define HEAP_ENTRY_VIRTUAL_ALLOC
Definition: heap.h:43
HANDLE NTAPI RtlpPageHeapCreate(ULONG Flags, PVOID Addr, SIZE_T TotalSize, SIZE_T CommitSize, PVOID Lock, PRTL_HEAP_PARAMETERS Parameters)
Definition: heappage.c:1533
#define HEAP_ENTRY_BUSY
Definition: heap.h:40
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define DPRINT
Definition: sndvol32.h:71
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
base of all file and directory entries
Definition: entries.h:83
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: compat.h:210
DWORD ExceptionCode
Definition: compat.h:208
DWORD NumberParameters
Definition: compat.h:212
DWORD ExceptionFlags
Definition: compat.h:209
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]
Definition: compat.h:213
Definition: heap.h:292
ULONG_PTR Settable
Definition: heap.h:299
USHORT TagIndex
Definition: heap.h:298
Definition: heap.h:136
Definition: heap.h:130
LIST_ENTRY FreeList
Definition: heap.h:132
LIST_ENTRY SegmentEntry
Definition: heap.h:279
LIST_ENTRY ListEntry
Definition: heap.h:278
SIZE_T CommittedSize
Definition: heap.h:288
SIZE_T ReservedSize
Definition: heap.h:287
Definition: heap.h:308
LIST_ENTRY Entry
Definition: heap.h:309
HEAP_ENTRY BusyBlock
Definition: heap.h:313
SIZE_T CommitSize
Definition: heap.h:311
HEAP_ENTRY_EXTRA ExtraStuff
Definition: heap.h:310
Definition: heap.c:52
ULONG Flags
Definition: heap.h:226
PRTL_HEAP_COMMIT_ROUTINE CommitRoutine
Definition: heap.h:261
ULONG_PTR AlignRound
Definition: heap.h:249
ULONG ForceFlags
Definition: heap.h:227
PLIST_ENTRY FreeHints[ANYSIZE_ARRAY]
Definition: heap.h:268
SIZE_T TotalFreeSize
Definition: heap.h:239
UCHAR FrontEndHeapType
Definition: heap.h:264
SIZE_T SegmentCommit
Definition: heap.h:236
RTL_BITMAP FreeHintBitmap
Definition: heap.h:267
SIZE_T SegmentReserve
Definition: heap.h:235
ULONG_PTR AlignMask
Definition: heap.h:250
LIST_ENTRY VirtualAllocdBlocks
Definition: heap.h:251
PHEAP_PSEUDO_TAG_ENTRY PseudoTagEntries
Definition: heap.h:258
LIST_ENTRY FreeLists
Definition: heap.h:259
ULONG Signature
Definition: heap.h:234
LIST_ENTRY UCRSegments
Definition: heap.h:248
SIZE_T DeCommitFreeBlockThreshold
Definition: heap.h:237
PHEAP_LOCK LockVariable
Definition: heap.h:260
LIST_ENTRY UCRList
Definition: heap.h:247
SIZE_T DeCommitTotalFreeThreshold
Definition: heap.h:238
struct _HEAP_SEGMENT * Segments[HEAP_SEGMENTS]
Definition: heap.h:253
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
ULONG_PTR * PSIZE_T
Definition: typedefs.h:80
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
char * PCHAR
Definition: typedefs.h:51
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
_Must_inspect_result_ _In_ WDFQUEUE _In_opt_ WDFREQUEST _In_opt_ WDFFILEOBJECT _Inout_opt_ PWDF_REQUEST_PARAMETERS Parameters
Definition: wdfio.h:869
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:127
#define FORCEINLINE
Definition: wdftypes.h:67
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_Inout_ PVOID Segment
Definition: exfuncs.h:1101
_In_ UCHAR EntrySize
Definition: iofuncs.h:642
_In_ BOOLEAN Remove
Definition: psfuncs.h:110
_In_ ULONG _In_ ULONG HintIndex
Definition: rtlfuncs.h:610
_In_opt_ PVOID _In_opt_ SIZE_T ReserveSize
Definition: rtlfuncs.h:2168
NTSYSAPI VOID NTAPI RtlSetBit(_In_ PRTL_BITMAP BitMapHeader, _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber)
Definition: bitmap.c:304
_Must_inspect_result_ NTSYSAPI BOOLEAN NTAPI RtlTestBit(_In_ PRTL_BITMAP BitMapHeader, _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber)
Definition: bitmap.c:434
_Must_inspect_result_ NTSYSAPI SIZE_T NTAPI RtlCompareMemoryUlong(_In_reads_bytes_(Length) PVOID Source, _In_ SIZE_T Length, _In_ ULONG Pattern)
_IRQL_requires_same_ _In_ CLONG ByteSize
Definition: rtltypes.h:399
unsigned char UCHAR
Definition: xmlstorage.h:181