ReactOS  0.4.13-dev-464-g6b95727
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  /* Get pointer to the heap entry */
2184  HeapEntry = (PHEAP_ENTRY)Ptr - 1;
2185 
2186  /* Protect with SEH in case the pointer is not valid */
2187  _SEH2_TRY
2188  {
2189  /* Check this entry, fail if it's invalid */
2190  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY) ||
2191  (((ULONG_PTR)Ptr & 0x7) != 0) ||
2192  (HeapEntry->SegmentOffset >= HEAP_SEGMENTS))
2193  {
2194  /* This is an invalid block */
2195  DPRINT1("HEAP: Trying to free an invalid address %p!\n", Ptr);
2197  _SEH2_YIELD(return FALSE);
2198  }
2199  }
2201  {
2202  /* The pointer was invalid */
2203  DPRINT1("HEAP: Trying to free an invalid address %p!\n", Ptr);
2205  _SEH2_YIELD(return FALSE);
2206  }
2207  _SEH2_END;
2208 
2209  /* Lock if necessary */
2210  if (!(Flags & HEAP_NO_SERIALIZE))
2211  {
2213  Locked = TRUE;
2214  }
2215 
2216  if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2217  {
2218  /* Big allocation */
2219  VirtualEntry = CONTAINING_RECORD(HeapEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
2220 
2221  /* Remove it from the list */
2222  RemoveEntryList(&VirtualEntry->Entry);
2223 
2224  // TODO: Tagging
2225 
2226  BlockSize = 0;
2227  Status = ZwFreeVirtualMemory(NtCurrentProcess(),
2228  (PVOID *)&VirtualEntry,
2229  &BlockSize,
2230  MEM_RELEASE);
2231 
2232  if (!NT_SUCCESS(Status))
2233  {
2234  DPRINT1("HEAP: Failed releasing memory with Status 0x%08X. Heap %p, ptr %p, base address %p\n",
2235  Status, Heap, Ptr, VirtualEntry);
2237  }
2238  }
2239  else
2240  {
2241  /* Normal allocation */
2242  BlockSize = HeapEntry->Size;
2243 
2244  // TODO: Tagging
2245 
2246  /* Coalesce in kernel mode, and in usermode if it's not disabled */
2247  if (RtlpGetMode() == KernelMode ||
2249  {
2250  HeapEntry = (PHEAP_ENTRY)RtlpCoalesceFreeBlocks(Heap,
2251  (PHEAP_FREE_ENTRY)HeapEntry,
2252  &BlockSize,
2253  FALSE);
2254  }
2255 
2256  /* If there is no need to decommit the block - put it into a free list */
2257  if (BlockSize < Heap->DeCommitFreeBlockThreshold ||
2258  (Heap->TotalFreeSize + BlockSize < Heap->DeCommitTotalFreeThreshold))
2259  {
2260  /* Check if it needs to go to a 0 list */
2261  if (BlockSize > HEAP_MAX_BLOCK_SIZE)
2262  {
2263  /* General-purpose 0 list */
2264  RtlpInsertFreeBlock(Heap, (PHEAP_FREE_ENTRY)HeapEntry, BlockSize);
2265  }
2266  else
2267  {
2268  /* Usual free list */
2269  RtlpInsertFreeBlockHelper(Heap, (PHEAP_FREE_ENTRY)HeapEntry, BlockSize, FALSE);
2270 
2271  /* Assert sizes are consistent */
2272  if (!(HeapEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
2273  {
2274  ASSERT((HeapEntry + BlockSize)->PreviousSize == BlockSize);
2275  }
2276 
2277  /* Increase the free size */
2278  Heap->TotalFreeSize += BlockSize;
2279  }
2280 
2281 
2282  if (RtlpGetMode() == UserMode &&
2283  TagIndex != 0)
2284  {
2285  // FIXME: Tagging
2286  UNIMPLEMENTED;
2287  }
2288  }
2289  else
2290  {
2291  /* Decommit this block */
2292  RtlpDeCommitFreeBlock(Heap, (PHEAP_FREE_ENTRY)HeapEntry, BlockSize);
2293  }
2294  }
2295 
2296  /* Release the heap lock */
2297  if (Locked) RtlLeaveHeapLock(Heap->LockVariable);
2298 
2299  return TRUE;
2300 }
2301 
2302 BOOLEAN NTAPI
2304  IN ULONG Flags,
2305  IN PHEAP_ENTRY InUseEntry,
2306  IN SIZE_T Size,
2307  IN SIZE_T Index)
2308 {
2309  UCHAR EntryFlags, RememberFlags;
2310  PHEAP_FREE_ENTRY FreeEntry, UnusedEntry, FollowingEntry;
2311  SIZE_T FreeSize, PrevSize, TailPart, AddedSize = 0;
2312  PHEAP_ENTRY_EXTRA OldExtra, NewExtra;
2313 
2314  /* We can't grow beyond specified threshold */
2315  if (Index > Heap->VirtualMemoryThreshold)
2316  return FALSE;
2317 
2318  /* Get entry flags */
2319  EntryFlags = InUseEntry->Flags;
2320 
2321  /* Get the next free entry */
2322  FreeEntry = (PHEAP_FREE_ENTRY)(InUseEntry + InUseEntry->Size);
2323 
2324  if (EntryFlags & HEAP_ENTRY_LAST_ENTRY)
2325  {
2326  /* There is no next block, just uncommitted space. Calculate how much is needed */
2327  FreeSize = (Index - InUseEntry->Size) << HEAP_ENTRY_SHIFT;
2328  FreeSize = ROUND_UP(FreeSize, PAGE_SIZE);
2329 
2330  /* Find and commit those pages */
2331  FreeEntry = RtlpFindAndCommitPages(Heap,
2332  Heap->Segments[InUseEntry->SegmentOffset],
2333  &FreeSize,
2334  FreeEntry);
2335 
2336  /* Fail if it failed... */
2337  if (!FreeEntry) return FALSE;
2338 
2339  /* It was successful, perform coalescing */
2340  FreeSize = FreeSize >> HEAP_ENTRY_SHIFT;
2341  FreeEntry = RtlpCoalesceFreeBlocks(Heap, FreeEntry, &FreeSize, FALSE);
2342 
2343  /* Check if it's enough */
2344  if (FreeSize + InUseEntry->Size < Index)
2345  {
2346  /* Still not enough */
2347  RtlpInsertFreeBlock(Heap, FreeEntry, FreeSize);
2348  Heap->TotalFreeSize += FreeSize;
2349  return FALSE;
2350  }
2351 
2352  /* Remember flags of this free entry */
2353  RememberFlags = FreeEntry->Flags;
2354 
2355  /* Sum up sizes */
2356  FreeSize += InUseEntry->Size;
2357  }
2358  else
2359  {
2360  /* The next block indeed exists. Check if it's free or in use */
2361  if (FreeEntry->Flags & HEAP_ENTRY_BUSY) return FALSE;
2362 
2363  /* Next entry is free, check if it can fit the block we need */
2364  FreeSize = InUseEntry->Size + FreeEntry->Size;
2365  if (FreeSize < Index) return FALSE;
2366 
2367  /* Remember flags of this free entry */
2368  RememberFlags = FreeEntry->Flags;
2369 
2370  /* Remove this block from the free list */
2371  RtlpRemoveFreeBlock(Heap, FreeEntry, FALSE, FALSE);
2372  Heap->TotalFreeSize -= FreeEntry->Size;
2373  }
2374 
2375  PrevSize = (InUseEntry->Size << HEAP_ENTRY_SHIFT) - InUseEntry->UnusedBytes;
2376  FreeSize -= Index;
2377 
2378  /* Don't produce too small blocks */
2379  if (FreeSize <= 2)
2380  {
2381  Index += FreeSize;
2382  FreeSize = 0;
2383  }
2384 
2385  /* Process extra stuff */
2386  if (EntryFlags & HEAP_ENTRY_EXTRA_PRESENT)
2387  {
2388  /* Calculate pointers */
2389  OldExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + InUseEntry->Size - 1);
2390  NewExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + Index - 1);
2391 
2392  /* Copy contents */
2393  *NewExtra = *OldExtra;
2394 
2395  // FIXME Tagging
2396  }
2397 
2398  /* Update sizes */
2399  InUseEntry->Size = (USHORT)Index;
2400  InUseEntry->UnusedBytes = (UCHAR)((Index << HEAP_ENTRY_SHIFT) - Size);
2401 
2402  /* Check if there is a free space remaining after merging those blocks */
2403  if (!FreeSize)
2404  {
2405  /* Update flags and sizes */
2406  InUseEntry->Flags |= RememberFlags & HEAP_ENTRY_LAST_ENTRY;
2407 
2408  /* Either update previous size of the next entry or mark it as a last
2409  entry in the segment*/
2410  if (!(RememberFlags & HEAP_ENTRY_LAST_ENTRY))
2411  (InUseEntry + InUseEntry->Size)->PreviousSize = InUseEntry->Size;
2412  }
2413  else
2414  {
2415  /* Complex case, we need to split the block to give unused free space
2416  back to the heap */
2417  UnusedEntry = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
2418  UnusedEntry->PreviousSize = (USHORT)Index;
2419  UnusedEntry->SegmentOffset = InUseEntry->SegmentOffset;
2420 
2421  /* Update the following block or set the last entry in the segment */
2422  if (RememberFlags & HEAP_ENTRY_LAST_ENTRY)
2423  {
2424  /* Set flags and size */
2425  UnusedEntry->Flags = RememberFlags;
2426  UnusedEntry->Size = (USHORT)FreeSize;
2427 
2428  /* Insert it to the heap and update total size */
2429  RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
2430  Heap->TotalFreeSize += FreeSize;
2431  }
2432  else
2433  {
2434  /* There is a block after this one */
2435  FollowingEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)UnusedEntry + FreeSize);
2436 
2437  if (FollowingEntry->Flags & HEAP_ENTRY_BUSY)
2438  {
2439  /* Update flags and set size of the unused space entry */
2440  UnusedEntry->Flags = RememberFlags & (~HEAP_ENTRY_LAST_ENTRY);
2441  UnusedEntry->Size = (USHORT)FreeSize;
2442 
2443  /* Update previous size of the following entry */
2444  FollowingEntry->PreviousSize = (USHORT)FreeSize;
2445 
2446  /* Insert it to the heap and update total free size */
2447  RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
2448  Heap->TotalFreeSize += FreeSize;
2449  }
2450  else
2451  {
2452  /* That following entry is also free, what a fortune! */
2453  RememberFlags = FollowingEntry->Flags;
2454 
2455  /* Remove it */
2456  RtlpRemoveFreeBlock(Heap, FollowingEntry, FALSE, FALSE);
2457  Heap->TotalFreeSize -= FollowingEntry->Size;
2458 
2459  /* And make up a new combined block */
2460  FreeSize += FollowingEntry->Size;
2461  UnusedEntry->Flags = RememberFlags;
2462 
2463  /* Check where to put it */
2464  if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
2465  {
2466  /* Fine for a dedicated list */
2467  UnusedEntry->Size = (USHORT)FreeSize;
2468 
2469  if (!(RememberFlags & HEAP_ENTRY_LAST_ENTRY))
2470  ((PHEAP_ENTRY)UnusedEntry + FreeSize)->PreviousSize = (USHORT)FreeSize;
2471 
2472  /* Insert it back and update total size */
2473  RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
2474  Heap->TotalFreeSize += FreeSize;
2475  }
2476  else
2477  {
2478  /* The block is very large, leave all the hassle to the insertion routine */
2479  RtlpInsertFreeBlock(Heap, UnusedEntry, FreeSize);
2480  }
2481  }
2482  }
2483  }
2484 
2485  /* Properly "zero out" (and fill!) the space */
2486  if (Flags & HEAP_ZERO_MEMORY)
2487  {
2488  RtlZeroMemory((PCHAR)(InUseEntry + 1) + PrevSize, Size - PrevSize);
2489  }
2490  else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
2491  {
2492  /* Calculate tail part which we need to fill */
2493  TailPart = PrevSize & (sizeof(ULONG) - 1);
2494 
2495  /* "Invert" it as usual */
2496  if (TailPart) TailPart = 4 - TailPart;
2497 
2498  if (Size > (PrevSize + TailPart))
2499  AddedSize = (Size - (PrevSize + TailPart)) & ~(sizeof(ULONG) - 1);
2500 
2501  if (AddedSize)
2502  {
2503  RtlFillMemoryUlong((PCHAR)(InUseEntry + 1) + PrevSize + TailPart,
2504  AddedSize,
2506  }
2507  }
2508 
2509  /* Fill the new tail */
2510  if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
2511  {
2512  RtlFillMemory((PCHAR)(InUseEntry + 1) + Size,
2514  HEAP_TAIL_FILL);
2515  }
2516 
2517  /* Copy user settable flags */
2518  InUseEntry->Flags &= ~HEAP_ENTRY_SETTABLE_FLAGS;
2519  InUseEntry->Flags |= ((Flags & HEAP_SETTABLE_USER_FLAGS) >> 4);
2520 
2521  /* Return success */
2522  return TRUE;
2523 }
2524 
2527 {
2528  PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry;
2529 
2530  /* Check if it's a big block */
2531  if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2532  {
2533  VirtualEntry = CONTAINING_RECORD(HeapEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
2534 
2535  /* Return a pointer to the extra stuff*/
2536  return &VirtualEntry->ExtraStuff;
2537  }
2538  else
2539  {
2540  /* This is a usual entry, which means extra stuff follows this block */
2541  return (PHEAP_ENTRY_EXTRA)(HeapEntry + HeapEntry->Size - 1);
2542  }
2543 }
2544 
2545 
2546 /***********************************************************************
2547  * RtlReAllocateHeap
2548  * PARAMS
2549  * Heap [in] Handle of heap block
2550  * Flags [in] Heap reallocation flags
2551  * Ptr, [in] Address of memory to reallocate
2552  * Size [in] Number of bytes to reallocate
2553  *
2554  * RETURNS
2555  * Pointer to reallocated memory block
2556  * NULL: Failure
2557  * 0x7d030f60--invalid flags in RtlHeapAllocate
2558  * @implemented
2559  */
2560 PVOID NTAPI
2562  ULONG Flags,
2563  PVOID Ptr,
2564  SIZE_T Size)
2565 {
2566  PHEAP Heap = (PHEAP)HeapPtr;
2567  PHEAP_ENTRY InUseEntry, NewInUseEntry;
2568  PHEAP_ENTRY_EXTRA OldExtra, NewExtra;
2569  SIZE_T AllocationSize, FreeSize, DecommitSize;
2570  BOOLEAN HeapLocked = FALSE;
2571  PVOID NewBaseAddress;
2572  PHEAP_FREE_ENTRY SplitBlock, SplitBlock2;
2573  SIZE_T OldSize, Index, OldIndex;
2574  UCHAR FreeFlags;
2575  NTSTATUS Status;
2576  PVOID DecommitBase;
2577  SIZE_T RemainderBytes, ExtraSize;
2578  PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
2579  EXCEPTION_RECORD ExceptionRecord;
2580 
2581  /* Return success in case of a null pointer */
2582  if (!Ptr)
2583  {
2585  return NULL;
2586  }
2587 
2588  /* Force heap flags */
2589  Flags |= Heap->ForceFlags;
2590 
2591  /* Call special heap */
2592  if (RtlpHeapIsSpecial(Flags))
2593  return RtlDebugReAllocateHeap(Heap, Flags, Ptr, Size);
2594 
2595  /* Make sure size is valid */
2596  if (Size >= 0x80000000)
2597  {
2599  return NULL;
2600  }
2601 
2602  /* Calculate allocation size and index */
2603  if (Size)
2604  AllocationSize = Size;
2605  else
2606  AllocationSize = 1;
2607  AllocationSize = (AllocationSize + Heap->AlignRound) & Heap->AlignMask;
2608 
2609  /* Add up extra stuff, if it is present anywhere */
2612  Heap->PseudoTagEntries)
2613  {
2614  AllocationSize += sizeof(HEAP_ENTRY_EXTRA);
2615  }
2616 
2617  /* Acquire the lock if necessary */
2618  if (!(Flags & HEAP_NO_SERIALIZE))
2619  {
2621  HeapLocked = TRUE;
2623  }
2624 
2625  /* Get the pointer to the in-use entry */
2626  InUseEntry = (PHEAP_ENTRY)Ptr - 1;
2627 
2628  /* If that entry is not really in-use, we have a problem */
2629  if (!(InUseEntry->Flags & HEAP_ENTRY_BUSY))
2630  {
2632 
2633  /* Release the lock and return */
2634  if (HeapLocked)
2636  return Ptr;
2637  }
2638 
2639  if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2640  {
2641  /* This is a virtually allocated block. Get its size */
2642  OldSize = RtlpGetSizeOfBigBlock(InUseEntry);
2643 
2644  /* Convert it to an index */
2645  OldIndex = (OldSize + InUseEntry->Size) >> HEAP_ENTRY_SHIFT;
2646 
2647  /* Calculate new allocation size and round it to the page size */
2650  }
2651  else
2652  {
2653  /* Usual entry */
2654  OldIndex = InUseEntry->Size;
2655 
2656  OldSize = (OldIndex << HEAP_ENTRY_SHIFT) - InUseEntry->UnusedBytes;
2657  }
2658 
2659  /* Calculate new index */
2661 
2662  /* Check for 4 different scenarios (old size, new size, old index, new index) */
2663  if (Index <= OldIndex)
2664  {
2665  /* Difference must be greater than 1, adjust if it's not so */
2666  if (Index + 1 == OldIndex)
2667  {
2668  Index++;
2669  AllocationSize += sizeof(HEAP_ENTRY);
2670  }
2671 
2672  /* Calculate new size */
2673  if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2674  {
2675  /* Simple in case of a virtual alloc - just an unused size */
2676  InUseEntry->Size = (USHORT)(AllocationSize - Size);
2677  ASSERT(InUseEntry->Size >= sizeof(HEAP_VIRTUAL_ALLOC_ENTRY));
2678  }
2679  else if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2680  {
2681  /* There is extra stuff, take it into account */
2682  OldExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + InUseEntry->Size - 1);
2683  NewExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + Index - 1);
2684  *NewExtra = *OldExtra;
2685 
2686  // FIXME Tagging, TagIndex
2687 
2688  /* Update unused bytes count */
2689  InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
2690  }
2691  else
2692  {
2693  // FIXME Tagging, SmallTagIndex
2694  InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
2695  }
2696 
2697  /* If new size is bigger than the old size */
2698  if (Size > OldSize)
2699  {
2700  /* Zero out that additional space if required */
2701  if (Flags & HEAP_ZERO_MEMORY)
2702  {
2703  RtlZeroMemory((PCHAR)Ptr + OldSize, Size - OldSize);
2704  }
2705  else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
2706  {
2707  /* Fill it on free if required */
2708  RemainderBytes = OldSize & (sizeof(ULONG) - 1);
2709 
2710  if (RemainderBytes)
2711  RemainderBytes = 4 - RemainderBytes;
2712 
2713  if (Size > (OldSize + RemainderBytes))
2714  {
2715  /* Calculate actual amount of extra bytes to fill */
2716  ExtraSize = (Size - (OldSize + RemainderBytes)) & ~(sizeof(ULONG) - 1);
2717 
2718  /* Fill them if there are any */
2719  if (ExtraSize != 0)
2720  {
2721  RtlFillMemoryUlong((PCHAR)(InUseEntry + 1) + OldSize + RemainderBytes,
2722  ExtraSize,
2724  }
2725  }
2726  }
2727  }
2728 
2729  /* Fill tail of the heap entry if required */
2730  if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
2731  {
2732  RtlFillMemory((PCHAR)(InUseEntry + 1) + Size,
2734  HEAP_TAIL_FILL);
2735  }
2736 
2737  /* Check if the difference is significant or not */
2738  if (Index != OldIndex)
2739  {
2740  /* Save flags */
2741  FreeFlags = InUseEntry->Flags & ~HEAP_ENTRY_BUSY;
2742 
2743  if (FreeFlags & HEAP_ENTRY_VIRTUAL_ALLOC)
2744  {
2745  /* This is a virtual block allocation */
2746  VirtualAllocBlock = CONTAINING_RECORD(InUseEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
2747 
2748  // FIXME Tagging!
2749 
2750  DecommitBase = (PCHAR)VirtualAllocBlock + AllocationSize;
2751  DecommitSize = (OldIndex << HEAP_ENTRY_SHIFT) - AllocationSize;
2752 
2753  /* Release the memory */
2754  Status = ZwFreeVirtualMemory(NtCurrentProcess(),
2755  (PVOID *)&DecommitBase,
2756  &DecommitSize,
2757  MEM_RELEASE);
2758 
2759  if (!NT_SUCCESS(Status))
2760  {
2761  DPRINT1("HEAP: Unable to release memory (pointer %p, size 0x%x), Status %08x\n", DecommitBase, DecommitSize, Status);
2762  }
2763  else
2764  {
2765  /* Otherwise reduce the commit size */
2766  VirtualAllocBlock->CommitSize -= DecommitSize;
2767  }
2768  }
2769  else
2770  {
2771  /* Reduce size of the block and possibly split it */
2772  SplitBlock = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
2773 
2774  /* Initialize this entry */
2775  SplitBlock->Flags = FreeFlags;
2776  SplitBlock->PreviousSize = (USHORT)Index;
2777  SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
2778 
2779  /* Remember free size */
2780  FreeSize = InUseEntry->Size - Index;
2781 
2782  /* Set new size */
2783  InUseEntry->Size = (USHORT)Index;
2784  InUseEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
2785 
2786  /* Is that the last entry */
2787  if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
2788  {
2789  /* Set its size and insert it to the list */
2790  SplitBlock->Size = (USHORT)FreeSize;
2791  RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
2792 
2793  /* Update total free size */
2794  Heap->TotalFreeSize += FreeSize;
2795  }
2796  else
2797  {
2798  /* Get the block after that one */
2799  SplitBlock2 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize);
2800 
2801  if (SplitBlock2->Flags & HEAP_ENTRY_BUSY)
2802  {
2803  /* It's in use, add it here*/
2804  SplitBlock->Size = (USHORT)FreeSize;
2805 
2806  /* Update previous size of the next entry */
2807  ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
2808 
2809  /* Insert it to the list */
2810  RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
2811 
2812  /* Update total size */
2813  Heap->TotalFreeSize += FreeSize;
2814  }
2815  else
2816  {
2817  /* Next entry is free, so merge with it */
2818  SplitBlock->Flags = SplitBlock2->Flags;
2819 
2820  /* Remove it, update total size */
2821  RtlpRemoveFreeBlock(Heap, SplitBlock2, FALSE, FALSE);
2822  Heap->TotalFreeSize -= SplitBlock2->Size;
2823 
2824  /* Calculate total free size */
2825  FreeSize += SplitBlock2->Size;
2826 
2827  if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
2828  {
2829  SplitBlock->Size = (USHORT)FreeSize;
2830 
2831  if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
2832  {
2833  /* Update previous size of the next entry */
2834  ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
2835  }
2836 
2837  /* Insert the new one back and update total size */
2838  RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
2839  Heap->TotalFreeSize += FreeSize;
2840  }
2841  else
2842  {
2843  /* Just add it */
2844  RtlpInsertFreeBlock(Heap, SplitBlock, FreeSize);
2845  }
2846  }
2847  }
2848  }
2849  }
2850  }
2851  else
2852  {
2853  /* We're growing the block */
2854  if ((InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) ||
2855  !RtlpGrowBlockInPlace(Heap, Flags, InUseEntry, Size, Index))
2856  {
2857  /* Growing in place failed, so growing out of place */
2859  {
2860  DPRINT1("Realloc in place failed, but it was the only option\n");
2861  Ptr = NULL;
2862  }
2863  else
2864  {
2865  /* Clear tag bits */
2866  Flags &= ~HEAP_TAG_MASK;
2867 
2868  /* Process extra stuff */
2869  if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2870  {
2871  /* Preserve user settable flags */
2873 
2874  Flags |= HEAP_SETTABLE_USER_VALUE | ((InUseEntry->Flags & HEAP_ENTRY_SETTABLE_FLAGS) << 4);
2875 
2876  /* Get pointer to the old extra data */
2877  OldExtra = RtlpGetExtraStuffPointer(InUseEntry);
2878 
2879  /* Save tag index if it was set */
2880  if (OldExtra->TagIndex &&
2881  !(OldExtra->TagIndex & HEAP_PSEUDO_TAG_FLAG))
2882  {
2883  Flags |= OldExtra->TagIndex << HEAP_TAG_SHIFT;
2884  }
2885  }
2886  else if (InUseEntry->SmallTagIndex)
2887  {
2888  /* Take small tag index into account */
2889  Flags |= InUseEntry->SmallTagIndex << HEAP_TAG_SHIFT;
2890  }
2891 
2892  /* Allocate new block from the heap */
2893  NewBaseAddress = RtlAllocateHeap(HeapPtr,
2895  Size);
2896 
2897  /* Proceed if it didn't fail */
2898  if (NewBaseAddress)
2899  {
2900  /* Get new entry pointer */
2901  NewInUseEntry = (PHEAP_ENTRY)NewBaseAddress - 1;
2902 
2903  /* Process extra stuff if it exists */
2904  if (NewInUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2905  {
2906  NewExtra = RtlpGetExtraStuffPointer(NewInUseEntry);
2907 
2908  if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2909  {
2910  OldExtra = RtlpGetExtraStuffPointer(InUseEntry);
2911  NewExtra->Settable = OldExtra->Settable;
2912  }
2913  else
2914  {
2915  RtlZeroMemory(NewExtra, sizeof(*NewExtra));
2916  }
2917  }
2918 
2919  /* Copy actual user bits */
2920  if (Size < OldSize)
2921  RtlMoveMemory(NewBaseAddress, Ptr, Size);
2922  else
2923  RtlMoveMemory(NewBaseAddress, Ptr, OldSize);
2924 
2925  /* Zero remaining part if required */
2926  if (Size > OldSize &&
2927  (Flags & HEAP_ZERO_MEMORY))
2928  {
2929  RtlZeroMemory((PCHAR)NewBaseAddress + OldSize, Size - OldSize);
2930  }
2931 
2932  /* Free the old block */
2933  RtlFreeHeap(HeapPtr, Flags, Ptr);
2934  }
2935 
2936  Ptr = NewBaseAddress;
2937  }
2938  }
2939  }
2940 
2941  /* Did resizing fail? */
2942  if (!Ptr && (Flags & HEAP_GENERATE_EXCEPTIONS))
2943  {
2944  /* Generate an exception if required */
2945  ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
2946  ExceptionRecord.ExceptionRecord = NULL;
2947  ExceptionRecord.NumberParameters = 1;
2948  ExceptionRecord.ExceptionFlags = 0;
2949  ExceptionRecord.ExceptionInformation[0] = AllocationSize;
2950 
2951  RtlRaiseException(&ExceptionRecord);
2952  }
2953 
2954  /* Release the heap lock if it was acquired */
2955  if (HeapLocked)
2957 
2958  return Ptr;
2959 }
2960 
2961 
2962 /***********************************************************************
2963  * RtlCompactHeap
2964  *
2965  * @unimplemented
2966  */
2967 ULONG NTAPI
2969  ULONG Flags)
2970 {
2971  UNIMPLEMENTED;
2972  return 0;
2973 }
2974 
2975 
2976 /***********************************************************************
2977  * RtlLockHeap
2978  * Attempts to acquire the critical section object for a specified heap.
2979  *
2980  * PARAMS
2981  * Heap [in] Handle of heap to lock for exclusive access
2982  *
2983  * RETURNS
2984  * TRUE: Success
2985  * FALSE: Failure
2986  *
2987  * @implemented
2988  */
2989 BOOLEAN NTAPI
2991 {
2992  PHEAP Heap = (PHEAP)HeapPtr;
2993 
2994  /* Check for page heap */
2995  if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
2996  {
2997  return RtlpPageHeapLock(Heap);
2998  }
2999 
3000  /* Check if it's really a heap */
3001  if (Heap->Signature != HEAP_SIGNATURE) return FALSE;
3002 
3003  /* Lock if it's lockable */
3004  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3005  {
3007  }
3008 
3009  return TRUE;
3010 }
3011 
3012 
3013 /***********************************************************************
3014  * RtlUnlockHeap
3015  * Releases ownership of the critical section object.
3016  *
3017  * PARAMS
3018  * Heap [in] Handle to the heap to unlock
3019  *
3020  * RETURNS
3021  * TRUE: Success
3022  * FALSE: Failure
3023  *
3024  * @implemented
3025  */
3026 BOOLEAN NTAPI
3028 {
3029  PHEAP Heap = (PHEAP)HeapPtr;
3030 
3031  /* Check for page heap */
3032  if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
3033  {
3034  return RtlpPageHeapUnlock(Heap);
3035  }
3036 
3037  /* Check if it's really a heap */
3038  if (Heap->Signature != HEAP_SIGNATURE) return FALSE;
3039 
3040  /* Unlock if it's lockable */
3041  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3042  {
3044  }
3045 
3046  return TRUE;
3047 }
3048 
3049 
3050 /***********************************************************************
3051  * RtlSizeHeap
3052  * PARAMS
3053  * Heap [in] Handle of heap
3054  * Flags [in] Heap size control flags
3055  * Ptr [in] Address of memory to return size for
3056  *
3057  * RETURNS
3058  * Size in bytes of allocated memory
3059  * 0xffffffff: Failure
3060  *
3061  * @implemented
3062  */
3063 SIZE_T NTAPI
3065  HANDLE HeapPtr,
3066  ULONG Flags,
3067  PVOID Ptr
3068 )
3069 {
3070  PHEAP Heap = (PHEAP)HeapPtr;
3071  PHEAP_ENTRY HeapEntry;
3072  SIZE_T EntrySize;
3073 
3074  // FIXME This is a hack around missing SEH support!
3075  if (!Heap)
3076  {
3078  return (SIZE_T)-1;
3079  }
3080 
3081  /* Force flags */
3082  Flags |= Heap->ForceFlags;
3083 
3084  /* Call special heap */
3085  if (RtlpHeapIsSpecial(Flags))
3086  return RtlDebugSizeHeap(Heap, Flags, Ptr);
3087 
3088  /* Get the heap entry pointer */
3089  HeapEntry = (PHEAP_ENTRY)Ptr - 1;
3090 
3091  /* Return -1 if that entry is free */
3092  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3093  {
3095  return (SIZE_T)-1;
3096  }
3097 
3098  /* Get size of this block depending if it's a usual or a big one */
3099  if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
3100  {
3101  EntrySize = RtlpGetSizeOfBigBlock(HeapEntry);
3102  }
3103  else
3104  {
3105  /* Calculate it */
3106  EntrySize = (HeapEntry->Size << HEAP_ENTRY_SHIFT) - HeapEntry->UnusedBytes;
3107  }
3108 
3109  /* Return calculated size */
3110  return EntrySize;
3111 }
3112 
3113 BOOLEAN NTAPI
3115 {
3116  SIZE_T Size, Result;
3117  PCHAR TailPart;
3118 
3119  /* Calculate size */
3120  if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
3121  Size = RtlpGetSizeOfBigBlock(HeapEntry);
3122  else
3123  Size = (HeapEntry->Size << HEAP_ENTRY_SHIFT) - HeapEntry->UnusedBytes;
3124 
3125  /* Calculate pointer to the tail part of the block */
3126  TailPart = (PCHAR)(HeapEntry + 1) + Size;
3127 
3128  /* Compare tail pattern */
3129  Result = RtlCompareMemory(TailPart,
3130  FillPattern,
3131  HEAP_ENTRY_SIZE);
3132 
3133  if (Result != HEAP_ENTRY_SIZE)
3134  {
3135  DPRINT1("HEAP: Heap entry (size %x) %p tail is modified at %p\n", Size, HeapEntry, TailPart + Result);
3136  return FALSE;
3137  }
3138 
3139  /* All is fine */
3140  return TRUE;
3141 }
3142 
3143 BOOLEAN NTAPI
3145  PHEAP Heap,
3146  BOOLEAN Recalculate)
3147 {
3148  // We skip header validation for now
3149  return TRUE;
3150 }
3151 
3152 BOOLEAN NTAPI
3154  PHEAP Heap,
3155  PHEAP_ENTRY HeapEntry)
3156 {
3157  BOOLEAN BigAllocation, EntryFound = FALSE;
3159  ULONG SegmentOffset;
3160 
3161  /* Perform various consistency checks of this entry */
3162  if (!HeapEntry) goto invalid_entry;
3163  if ((ULONG_PTR)HeapEntry & (HEAP_ENTRY_SIZE - 1)) goto invalid_entry;
3164  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY)) goto invalid_entry;
3165 
3166  BigAllocation = HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC;
3167  Segment = Heap->Segments[HeapEntry->SegmentOffset];
3168 
3169  if (BigAllocation &&
3170  (((ULONG_PTR)HeapEntry & (PAGE_SIZE - 1)) != FIELD_OFFSET(HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock)))
3171  goto invalid_entry;
3172 
3173  if (!BigAllocation && (HeapEntry->SegmentOffset >= HEAP_SEGMENTS ||
3174  !Segment ||
3175  HeapEntry < Segment->FirstEntry ||
3176  HeapEntry >= Segment->LastValidEntry))
3177  goto invalid_entry;
3178 
3179  if ((HeapEntry->Flags & HEAP_ENTRY_FILL_PATTERN) &&
3180  !RtlpCheckInUsePattern(HeapEntry))
3181  goto invalid_entry;
3182 
3183  /* Checks are done, if this is a virtual entry, that's all */
3184  if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) return TRUE;
3185 
3186  /* Go through segments and check if this entry fits into any of them */
3187  for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
3188  {
3189  Segment = Heap->Segments[SegmentOffset];
3190  if (!Segment) continue;
3191 
3192  if ((HeapEntry >= Segment->FirstEntry) &&
3193  (HeapEntry < Segment->LastValidEntry))
3194  {
3195  /* Got it */
3196  EntryFound = TRUE;
3197  break;
3198  }
3199  }
3200 
3201  /* Return our result of finding entry in the segments */
3202  return EntryFound;
3203 
3204 invalid_entry:
3205  DPRINT1("HEAP: Invalid heap entry %p in heap %p\n", HeapEntry, Heap);
3206  return FALSE;
3207 }
3208 
3209 BOOLEAN NTAPI
3211  PHEAP Heap,
3213  UCHAR SegmentOffset,
3214  PULONG FreeEntriesCount,
3215  PSIZE_T TotalFreeSize,
3216  PSIZE_T TagEntries,
3217  PSIZE_T PseudoTagEntries)
3218 {
3219  PHEAP_UCR_DESCRIPTOR UcrDescriptor;
3220  PLIST_ENTRY UcrEntry;
3222  PHEAP_ENTRY CurrentEntry;
3223  ULONG UnCommittedPages;
3224  ULONG UnCommittedRanges;
3225  ULONG PreviousSize;
3226 
3227  UnCommittedPages = 0;
3228  UnCommittedRanges = 0;
3229 
3230  if (IsListEmpty(&Segment->UCRSegmentList))
3231  {
3232  UcrEntry = NULL;
3233  UcrDescriptor = NULL;
3234  }
3235  else
3236  {
3237  UcrEntry = Segment->UCRSegmentList.Flink;
3238  UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
3239  }
3240 
3241  if (Segment->BaseAddress == Heap)
3242  CurrentEntry = &Heap->Entry;
3243  else
3244  CurrentEntry = &Segment->Entry;
3245 
3246  while (CurrentEntry < Segment->LastValidEntry)
3247  {
3248  if (UcrDescriptor &&
3249  ((PVOID)CurrentEntry >= UcrDescriptor->Address))
3250  {
3251  DPRINT1("HEAP: Entry %p is not inside uncommited range [%p .. %p)\n",
3252  CurrentEntry, UcrDescriptor->Address,
3253  (PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
3254 
3255  return FALSE;
3256  }
3257 
3258  PreviousSize = 0;
3259 
3260  while (CurrentEntry < Segment->LastValidEntry)
3261  {
3262  if (PreviousSize != CurrentEntry->PreviousSize)
3263  {
3264  DPRINT1("HEAP: Entry %p has incorrect PreviousSize %x instead of %x\n",
3265  CurrentEntry, CurrentEntry->PreviousSize, PreviousSize);
3266 
3267  return FALSE;
3268  }
3269 
3270  PreviousSize = CurrentEntry->Size;
3271  Size = CurrentEntry->Size << HEAP_ENTRY_SHIFT;
3272 
3273  if (CurrentEntry->Flags & HEAP_ENTRY_BUSY)
3274  {
3275  if (TagEntries)
3276  {
3277  UNIMPLEMENTED;
3278  }
3279 
3280  /* Check fill pattern */
3281  if (CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN)
3282  {
3283  if (!RtlpCheckInUsePattern(CurrentEntry))
3284  return FALSE;
3285  }
3286  }
3287  else
3288  {
3289  /* The entry is free, increase free entries count and total free size */
3290  *FreeEntriesCount = *FreeEntriesCount + 1;
3291  *TotalFreeSize += CurrentEntry->Size;
3292 
3293  if ((Heap->Flags & HEAP_FREE_CHECKING_ENABLED) &&
3294  (CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN))
3295  {
3296  ByteSize = Size - sizeof(HEAP_FREE_ENTRY);
3297 
3298  if ((CurrentEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT) &&
3299  (ByteSize > sizeof(HEAP_FREE_ENTRY_EXTRA)))
3300  {
3301  ByteSize -= sizeof(HEAP_FREE_ENTRY_EXTRA);
3302  }
3303 
3304  Result = RtlCompareMemoryUlong((PCHAR)((PHEAP_FREE_ENTRY)CurrentEntry + 1),
3305  ByteSize,
3307 
3308  if (Result != ByteSize)
3309  {
3310  DPRINT1("HEAP: Free heap block %p modified at %p after it was freed\n",
3311  CurrentEntry,
3312  (PCHAR)(CurrentEntry + 1) + Result);
3313 
3314  return FALSE;
3315  }
3316  }
3317  }
3318 
3319  if (CurrentEntry->SegmentOffset != SegmentOffset)
3320  {
3321  DPRINT1("HEAP: Heap entry %p SegmentOffset is incorrect %x (should be %x)\n",
3322  CurrentEntry, SegmentOffset, CurrentEntry->SegmentOffset);
3323  return FALSE;
3324  }
3325 
3326  /* Check if it's the last entry */
3327  if (CurrentEntry->Flags & HEAP_ENTRY_LAST_ENTRY)
3328  {
3329  CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
3330 
3331  if (!UcrDescriptor)
3332  {
3333  /* Check if it's not really the last one */
3334  if (CurrentEntry != Segment->LastValidEntry)
3335  {
3336  DPRINT1("HEAP: Heap entry %p is not last block in segment (%p)\n",
3337  CurrentEntry, Segment->LastValidEntry);
3338  return FALSE;
3339  }
3340  }
3341  else if (CurrentEntry != UcrDescriptor->Address)
3342  {
3343  DPRINT1("HEAP: Heap entry %p does not match next uncommitted address (%p)\n",
3344  CurrentEntry, UcrDescriptor->Address);
3345 
3346  return FALSE;
3347  }
3348  else
3349  {
3350  UnCommittedPages += (ULONG)(UcrDescriptor->Size / PAGE_SIZE);
3351  UnCommittedRanges++;
3352 
3353  CurrentEntry = (PHEAP_ENTRY)((PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
3354 
3355  /* Go to the next UCR descriptor */
3356  UcrEntry = UcrEntry->Flink;
3357  if (UcrEntry == &Segment->UCRSegmentList)
3358  {
3359  UcrEntry = NULL;
3360  UcrDescriptor = NULL;
3361  }
3362  else
3363  {
3364  UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
3365  }
3366  }
3367 
3368  break;
3369  }
3370 
3371  /* Advance to the next entry */
3372  CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
3373  }
3374  }
3375 
3376  /* Check total numbers of UCP and UCR */
3377  if (Segment->NumberOfUnCommittedPages != UnCommittedPages)
3378  {
3379  DPRINT1("HEAP: Segment %p NumberOfUnCommittedPages is invalid (%x != %x)\n",
3380  Segment, Segment->NumberOfUnCommittedPages, UnCommittedPages);
3381 
3382  return FALSE;
3383  }
3384 
3385  if (Segment->NumberOfUnCommittedRanges != UnCommittedRanges)
3386  {
3387  DPRINT1("HEAP: Segment %p NumberOfUnCommittedRanges is invalid (%x != %x)\n",
3388  Segment, Segment->NumberOfUnCommittedRanges, UnCommittedRanges);
3389 
3390  return FALSE;
3391  }
3392 
3393  return TRUE;
3394 }
3395 
3396 BOOLEAN NTAPI
3398  BOOLEAN ForceValidation)
3399 {
3401  BOOLEAN EmptyList;
3402  UCHAR SegmentOffset;
3403  SIZE_T Size, TotalFreeSize;
3404  ULONG PreviousSize;
3405  PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
3406  PLIST_ENTRY ListHead, NextEntry;
3407  PHEAP_FREE_ENTRY FreeEntry;
3408  ULONG FreeBlocksCount, FreeListEntriesCount;
3409 
3410  /* Check headers */
3411  if (!RtlpValidateHeapHeaders(Heap, FALSE))
3412  return FALSE;
3413 
3414  /* Skip validation if it's not needed */
3415  if (!ForceValidation && !(Heap->Flags & HEAP_VALIDATE_ALL_ENABLED))
3416  return TRUE;
3417 
3418  /* Check free lists bitmaps */
3419  FreeListEntriesCount = 0;
3420  ListHead = &Heap->FreeLists[0];
3421 
3422  for (Size = 0; Size < HEAP_FREELISTS; Size++)
3423  {
3424  if (Size)
3425  {
3426  /* This is a dedicated list. Check if it's empty */
3427  EmptyList = IsListEmpty(ListHead);
3428 
3429  if (Heap->u.FreeListsInUseBytes[Size >> 3] & (1 << (Size & 7)))
3430  {
3431  if (EmptyList)
3432  {
3433  DPRINT1("HEAP: Empty %x-free list marked as non-empty\n", Size);
3434  return FALSE;
3435  }
3436  }
3437  else
3438  {
3439  if (!EmptyList)
3440  {
3441  DPRINT1("HEAP: Non-empty %x-free list marked as empty\n", Size);
3442  return FALSE;
3443  }
3444  }
3445  }
3446 
3447  /* Now check this list entries */
3448  NextEntry = ListHead->Flink;
3449  PreviousSize = 0;
3450 
3451  while (ListHead != NextEntry)
3452  {
3453  FreeEntry = CONTAINING_RECORD(NextEntry, HEAP_FREE_ENTRY, FreeList);
3454  NextEntry = NextEntry->Flink;
3455 
3456  /* If there is an in-use entry in a free list - that's quite a big problem */
3457  if (FreeEntry->Flags & HEAP_ENTRY_BUSY)
3458  {
3459  DPRINT1("HEAP: %Ix-dedicated list free element %p is marked in-use\n", Size, FreeEntry);
3460  return FALSE;
3461  }
3462 
3463  /* Check sizes according to that specific list's size */
3464  if ((Size == 0) && (FreeEntry->Size < HEAP_FREELISTS))
3465  {
3466  DPRINT1("HEAP: Non dedicated list free element %p has size %x which would fit a dedicated list\n", FreeEntry, FreeEntry->Size);
3467  return FALSE;
3468  }
3469  else if (Size && (FreeEntry->Size != Size))
3470  {
3471  DPRINT1("HEAP: %Ix-dedicated list free element %p has incorrect size %x\n", Size, FreeEntry, FreeEntry->Size);
3472  return FALSE;
3473  }
3474  else if ((Size == 0) && (FreeEntry->Size < PreviousSize))
3475  {
3476  DPRINT1("HEAP: Non dedicated list free element %p is not put in order\n", FreeEntry);
3477  return FALSE;
3478  }
3479 
3480  /* Remember previous size*/
3481  PreviousSize = FreeEntry->Size;
3482 
3483  /* Add up to the total amount of free entries */
3484  FreeListEntriesCount++;
3485  }
3486 
3487  /* Go to the head of the next free list */
3488  ListHead++;
3489  }
3490 
3491  /* Check big allocations */
3492  ListHead = &Heap->VirtualAllocdBlocks;
3493  NextEntry = ListHead->Flink;
3494 
3495  while (ListHead != NextEntry)
3496  {
3497  VirtualAllocBlock = CONTAINING_RECORD(NextEntry, HEAP_VIRTUAL_ALLOC_ENTRY, Entry);
3498 
3499  /* We can only check the fill pattern */
3500  if (VirtualAllocBlock->BusyBlock.Flags & HEAP_ENTRY_FILL_PATTERN)
3501  {
3502  if (!RtlpCheckInUsePattern(&VirtualAllocBlock->BusyBlock))
3503  return FALSE;
3504  }
3505 
3506  NextEntry = NextEntry->Flink;
3507  }
3508 
3509  /* Check all segments */
3510  FreeBlocksCount = 0;
3511  TotalFreeSize = 0;
3512 
3513  for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
3514  {
3515  Segment = Heap->Segments[SegmentOffset];
3516 
3517  /* Go to the next one if there is no segment */
3518  if (!Segment) continue;
3519 
3520  if (!RtlpValidateHeapSegment(Heap,
3521  Segment,
3522  SegmentOffset,
3523  &FreeBlocksCount,
3524  &TotalFreeSize,
3525  NULL,
3526  NULL))
3527  {
3528  return FALSE;
3529  }
3530  }
3531 
3532  if (FreeListEntriesCount != FreeBlocksCount)
3533  {
3534  DPRINT1("HEAP: Free blocks count in arena (%lu) does not match free blocks number in the free lists (%lu)\n", FreeBlocksCount, FreeListEntriesCount);
3535  return FALSE;
3536  }
3537 
3538  if (Heap->TotalFreeSize != TotalFreeSize)
3539  {
3540  DPRINT1("HEAP: Total size of free blocks in arena (%Iu) does not equal to the one in heap header (%Iu)\n", TotalFreeSize, Heap->TotalFreeSize);
3541  return FALSE;
3542  }
3543 
3544  return TRUE;
3545 }
3546 
3547 /***********************************************************************
3548  * RtlValidateHeap
3549  * Validates a specified heap.
3550  *
3551  * PARAMS
3552  * Heap [in] Handle to the heap
3553  * Flags [in] Bit flags that control access during operation
3554  * Block [in] Optional pointer to memory block to validate
3555  *
3556  * NOTES
3557  * Flags is ignored.
3558  *
3559  * RETURNS
3560  * TRUE: Success
3561  * FALSE: Failure
3562  *
3563  * @implemented
3564  */
3566  HANDLE HeapPtr,
3567  ULONG Flags,
3568  PVOID Block
3569 )
3570 {
3571  PHEAP Heap = (PHEAP)HeapPtr;
3572  BOOLEAN HeapLocked = FALSE;
3573  BOOLEAN HeapValid;
3574 
3575  /* Check for page heap */
3576  if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
3577  return RtlpDebugPageHeapValidate(HeapPtr, Flags, Block);
3578 
3579  /* Check signature */
3580  if (Heap->Signature != HEAP_SIGNATURE)
3581  {
3582  DPRINT1("HEAP: Signature %lx is invalid for heap %p\n", Heap->Signature, Heap);
3583  return FALSE;
3584  }
3585 
3586  /* Force flags */
3587  Flags = Heap->ForceFlags;
3588 
3589  /* Acquire the lock if necessary */
3590  if (!(Flags & HEAP_NO_SERIALIZE))
3591  {
3593  HeapLocked = TRUE;
3594  }
3595 
3596  /* Either validate whole heap or just one entry */
3597  if (!Block)
3598  HeapValid = RtlpValidateHeap(Heap, TRUE);
3599  else
3600  HeapValid = RtlpValidateHeapEntry(Heap, (PHEAP_ENTRY)Block - 1);
3601 
3602  /* Unlock if it's lockable */
3603  if (HeapLocked)
3604  {
3606  }
3607 
3608  return HeapValid;
3609 }
3610 
3611 /*
3612  * @implemented
3613  */
3616  PVOID lParam)
3617 {
3618  UNIMPLEMENTED;
3619  return STATUS_NOT_IMPLEMENTED;
3620 }
3621 
3622 
3623 /*
3624  * @implemented
3625  */
3626 ULONG NTAPI
3628  HANDLE *heaps)
3629 {
3630  UNIMPLEMENTED;
3631  return 0;
3632 }
3633 
3634 
3635 /*
3636  * @implemented
3637  */
3638 BOOLEAN NTAPI
3640 {
3641  UNIMPLEMENTED;
3642  return TRUE;
3643 }
3644 
3645 
3646 /*
3647  * @unimplemented
3648  */
3649 BOOLEAN NTAPI
3651  IN PVOID HeapHandle,
3652  IN ULONG Flags
3653  )
3654 {
3655  UNIMPLEMENTED;
3656  return FALSE;
3657 }
3658 
3659 /*
3660  * @implemented
3661  */
3662 BOOLEAN
3663 NTAPI
3665  IN ULONG Flags,
3667  IN PVOID UserValue)
3668 {
3669  PHEAP Heap = (PHEAP)HeapHandle;
3670  PHEAP_ENTRY HeapEntry;
3671  PHEAP_ENTRY_EXTRA Extra;
3672  BOOLEAN HeapLocked = FALSE, ValueSet = FALSE;
3673 
3674  /* Force flags */
3675  Flags |= Heap->Flags;
3676 
3677  /* Call special heap */
3678  if (RtlpHeapIsSpecial(Flags))
3679  return RtlDebugSetUserValueHeap(Heap, Flags, BaseAddress, UserValue);
3680 
3681  /* Lock if it's lockable */
3682  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3683  {
3685  HeapLocked = TRUE;
3686  }
3687 
3688  /* Get a pointer to the entry */
3689  HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
3690 
3691  /* If it's a free entry - return error */
3692  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3693  {
3695 
3696  /* Release the heap lock if it was acquired */
3697  if (HeapLocked)
3699 
3700  return FALSE;
3701  }
3702 
3703  /* Check if this entry has an extra stuff associated with it */
3704  if (HeapEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
3705  {
3706  /* Use extra to store the value */
3707  Extra = RtlpGetExtraStuffPointer(HeapEntry);
3708  Extra->Settable = (ULONG_PTR)UserValue;
3709 
3710  /* Indicate that value was set */
3711  ValueSet = TRUE;
3712  }
3713 
3714  /* Release the heap lock if it was acquired */
3715  if (HeapLocked)
3717 
3718  return ValueSet;
3719 }
3720 
3721 /*
3722  * @implemented
3723  */
3724 BOOLEAN
3725 NTAPI
3727  IN ULONG Flags,
3729  IN ULONG UserFlagsReset,
3730  IN ULONG UserFlagsSet)
3731 {
3732  PHEAP Heap = (PHEAP)HeapHandle;
3733  PHEAP_ENTRY HeapEntry;
3734  BOOLEAN HeapLocked = FALSE;
3735 
3736  /* Force flags */
3737  Flags |= Heap->Flags;
3738 
3739  /* Call special heap */
3740  if (RtlpHeapIsSpecial(Flags))
3741  return RtlDebugSetUserFlagsHeap(Heap, Flags, BaseAddress, UserFlagsReset, UserFlagsSet);
3742 
3743  /* Lock if it's lockable */
3744  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3745  {
3747  HeapLocked = TRUE;
3748  }
3749 
3750  /* Get a pointer to the entry */
3751  HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
3752 
3753  /* If it's a free entry - return error */
3754  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3755  {
3757 
3758  /* Release the heap lock if it was acquired */
3759  if (HeapLocked)
3761 
3762  return FALSE;
3763  }
3764 
3765  /* Set / reset flags */
3766  HeapEntry->Flags &= ~(UserFlagsReset >> 4);
3767  HeapEntry->Flags |= (UserFlagsSet >> 4);
3768 
3769  /* Release the heap lock if it was acquired */
3770  if (HeapLocked)
3772 
3773  return TRUE;
3774 }
3775 
3776 /*
3777  * @implemented
3778  */
3779 BOOLEAN
3780 NTAPI
3782  IN ULONG Flags,
3784  OUT PVOID *UserValue,
3785  OUT PULONG UserFlags)
3786 {
3787  PHEAP Heap = (PHEAP)HeapHandle;
3788  PHEAP_ENTRY HeapEntry;
3789  PHEAP_ENTRY_EXTRA Extra;
3790  BOOLEAN HeapLocked = FALSE;
3791 
3792  /* Force flags */
3793  Flags |= Heap->Flags;
3794 
3795  /* Call special heap */
3796  if (RtlpHeapIsSpecial(Flags))
3797  return RtlDebugGetUserInfoHeap(Heap, Flags, BaseAddress, UserValue, UserFlags);
3798 
3799  /* Lock if it's lockable */
3800  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3801  {
3803  HeapLocked = TRUE;
3804  }
3805 
3806  /* Get a pointer to the entry */
3807  HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
3808 
3809  /* If it's a free entry - return error */
3810  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3811  {
3813 
3814  /* Release the heap lock if it was acquired */
3815  if (HeapLocked)
3817 
3818  return FALSE;
3819  }
3820 
3821  /* Check if this entry has an extra stuff associated with it */
3822  if (HeapEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
3823  {
3824  /* Get pointer to extra data */
3825  Extra = RtlpGetExtraStuffPointer(HeapEntry);
3826 
3827  /* Pass user value */
3828  if (UserValue)
3829  *UserValue = (PVOID)Extra->Settable;
3830  }
3831 
3832  /* Decode and return user flags */
3833  if (UserFlags)
3834  *UserFlags = (HeapEntry->Flags & HEAP_ENTRY_SETTABLE_FLAGS) << 4;
3835 
3836  /* Release the heap lock if it was acquired */
3837  if (HeapLocked)
3839 
3840  return TRUE;
3841 }
3842 
3843 /*
3844  * @unimplemented
3845  */
3846 NTSTATUS
3847 NTAPI
3849  IN ULONG Flags,
3851 {
3852  /* TODO */
3853  UNIMPLEMENTED;
3854  return STATUS_NOT_IMPLEMENTED;
3855 }
3856 
3857 PWSTR
3858 NTAPI
3860  IN ULONG Flags,
3861  IN USHORT TagIndex,
3862  IN BOOLEAN ResetCounters,
3863  OUT PRTL_HEAP_TAG_INFO HeapTagInfo)
3864 {
3865  /* TODO */
3866  UNIMPLEMENTED;
3867  return NULL;
3868 }
3869 
3870 ULONG
3871 NTAPI
3873  IN ULONG Flags,
3874  IN PVOID P,
3875  IN SIZE_T Size)
3876 {
3877  /* TODO */
3878  UNIMPLEMENTED;
3879  return 0;
3880 }
3881 
3882 ULONG
3883 NTAPI
3885  IN ULONG Flags,
3886  IN PWSTR TagName,
3887  IN PWSTR TagSubName)
3888 {
3889  /* TODO */
3890  UNIMPLEMENTED;
3891  return 0;
3892 }
3893 
3894 NTSTATUS
3895 NTAPI
3896 RtlWalkHeap(IN HANDLE HeapHandle,
3897  IN PVOID HeapEntry)
3898 {
3899  UNIMPLEMENTED;
3900  return STATUS_NOT_IMPLEMENTED;
3901 }
3902 
3903 PVOID
3904 NTAPI
3907 {
3908  UNIMPLEMENTED;
3909  return NULL;
3910 }
3911 
3912 NTSTATUS
3913 NTAPI
3915  IN HEAP_INFORMATION_CLASS HeapInformationClass,
3916  IN PVOID HeapInformation,
3917  IN SIZE_T HeapInformationLength)
3918 {
3919  /* Setting heap information is not really supported except for enabling LFH */
3920  if (HeapInformationClass == HeapCompatibilityInformation)
3921  {
3922  /* Check buffer length */
3923  if (HeapInformationLength < sizeof(ULONG))
3924  {
3925  /* The provided buffer is too small */
3926  return STATUS_BUFFER_TOO_SMALL;
3927  }
3928 
3929  /* Check for a special magic value for enabling LFH */
3930  if (*(PULONG)HeapInformation != 2)
3931  {
3932  return STATUS_UNSUCCESSFUL;
3933  }
3934 
3935  DPRINT1("RtlSetHeapInformation() needs to enable LFH\n");
3936  return STATUS_SUCCESS;
3937  }
3938 
3939  return STATUS_SUCCESS;
3940 }
3941 
3942 NTSTATUS
3943 NTAPI
3945  HEAP_INFORMATION_CLASS HeapInformationClass,
3946  PVOID HeapInformation,
3947  SIZE_T HeapInformationLength,
3949 {
3950  PHEAP Heap = (PHEAP)HeapHandle;
3951 
3952  /* Only HeapCompatibilityInformation is supported */
3953  if (HeapInformationClass == HeapCompatibilityInformation)
3954  {
3955  /* Set result length */
3956  if (ReturnLength)
3957  *ReturnLength = sizeof(ULONG);
3958 
3959  /* Check buffer length */
3960  if (HeapInformationLength < sizeof(ULONG))
3961  {
3962  /* It's too small, return needed length */
3963  return STATUS_BUFFER_TOO_SMALL;
3964  }
3965 
3966  /* Return front end heap type */
3967  *(PULONG)HeapInformation = Heap->FrontEndHeapType;
3968 
3969  return STATUS_SUCCESS;
3970  }
3971 
3972  return STATUS_UNSUCCESSFUL;
3973 }
3974 
3975 NTSTATUS
3976 NTAPI
3978  IN ULONG Flags,
3979  IN SIZE_T Size,
3980  IN ULONG Count,
3981  OUT PVOID *Array)
3982 {
3983  UNIMPLEMENTED;
3984  return 0;
3985 }
3986 
3987 NTSTATUS
3988 NTAPI
3990  IN ULONG Flags,
3991  IN ULONG Count,
3992  OUT PVOID *Array)
3993 {
3994  UNIMPLEMENTED;
3995  return 0;
3996 }
3997 
3998 /* 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:2561
#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
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:3848
#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:3153
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:3859
#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:2526
_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:3064
BOOLEAN RtlpPageHeapEnabled
Definition: heappage.c:106
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:231
BOOLEAN NTAPI RtlpValidateHeap(PHEAP Heap, BOOLEAN ForceValidation)
Definition: heap.c:3397
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:3144
#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:3664
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
union _HEAP::@3995 u
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:3884
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:3781
#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:3872
#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:3650
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:3944
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:2968
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:32
PVOID NTAPI RtlProtectHeap(IN PVOID HeapHandle, IN BOOLEAN ReadOnly)
Definition: heap.c:3905
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:3896
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:3989
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:3914
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:3114
#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:3726
#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:20
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:2303
#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:3027
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:3627
#define DPRINT1
Definition: precomp.h:8
BOOLEAN NTAPI RtlValidateProcessHeaps(VOID)
Definition: heap.c:3639
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:3977
#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:3615
DWORD NumberParameters
Definition: compat.h:200
BOOLEAN NTAPI RtlLockHeap(IN HANDLE HeapPtr)
Definition: heap.c:2990
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:2777
_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:3210
#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:3565
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