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