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