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