ReactOS  0.4.15-dev-985-gd905dd5
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;
2685  }
2686 
2687  /* Get the pointer to the in-use entry */
2688  InUseEntry = (PHEAP_ENTRY)Ptr - 1;
2689 
2690  /* If that entry is not really in-use, we have a problem */
2691  if (!(InUseEntry->Flags & HEAP_ENTRY_BUSY))
2692  {
2694 
2695  /* Release the lock and return */
2696  if (HeapLocked)
2698  return Ptr;
2699  }
2700 
2701  if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2702  {
2703  /* This is a virtually allocated block. Get its size */
2704  OldSize = RtlpGetSizeOfBigBlock(InUseEntry);
2705 
2706  /* Convert it to an index */
2707  OldIndex = (OldSize + InUseEntry->Size) >> HEAP_ENTRY_SHIFT;
2708 
2709  /* Calculate new allocation size and round it to the page size */
2712  }
2713  else
2714  {
2715  /* Usual entry */
2716  OldIndex = InUseEntry->Size;
2717 
2718  OldSize = (OldIndex << HEAP_ENTRY_SHIFT) - InUseEntry->UnusedBytes;
2719  }
2720 
2721  /* Calculate new index */
2723 
2724  /* Check for 4 different scenarios (old size, new size, old index, new index) */
2725  if (Index <= OldIndex)
2726  {
2727  /* Difference must be greater than 1, adjust if it's not so */
2728  if (Index + 1 == OldIndex)
2729  {
2730  Index++;
2731  AllocationSize += sizeof(HEAP_ENTRY);
2732  }
2733 
2734  /* Calculate new size */
2735  if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
2736  {
2737  /* Simple in case of a virtual alloc - just an unused size */
2738  InUseEntry->Size = (USHORT)(AllocationSize - Size);
2739  ASSERT(InUseEntry->Size >= sizeof(HEAP_VIRTUAL_ALLOC_ENTRY));
2740  }
2741  else if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2742  {
2743  /* There is extra stuff, take it into account */
2744  OldExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + InUseEntry->Size - 1);
2745  NewExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + Index - 1);
2746  *NewExtra = *OldExtra;
2747 
2748  // FIXME Tagging, TagIndex
2749 
2750  /* Update unused bytes count */
2751  InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
2752  }
2753  else
2754  {
2755  // FIXME Tagging, SmallTagIndex
2756  InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
2757  }
2758 
2759  /* If new size is bigger than the old size */
2760  if (Size > OldSize)
2761  {
2762  /* Zero out that additional space if required */
2763  if (Flags & HEAP_ZERO_MEMORY)
2764  {
2765  RtlZeroMemory((PCHAR)Ptr + OldSize, Size - OldSize);
2766  }
2767  else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
2768  {
2769  /* Fill it on free if required */
2770  RemainderBytes = OldSize & (sizeof(ULONG) - 1);
2771 
2772  if (RemainderBytes)
2773  RemainderBytes = 4 - RemainderBytes;
2774 
2775  if (Size > (OldSize + RemainderBytes))
2776  {
2777  /* Calculate actual amount of extra bytes to fill */
2778  ExtraSize = (Size - (OldSize + RemainderBytes)) & ~(sizeof(ULONG) - 1);
2779 
2780  /* Fill them if there are any */
2781  if (ExtraSize != 0)
2782  {
2783  RtlFillMemoryUlong((PCHAR)(InUseEntry + 1) + OldSize + RemainderBytes,
2784  ExtraSize,
2786  }
2787  }
2788  }
2789  }
2790 
2791  /* Fill tail of the heap entry if required */
2792  if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
2793  {
2794  RtlFillMemory((PCHAR)(InUseEntry + 1) + Size,
2796  HEAP_TAIL_FILL);
2797  }
2798 
2799  /* Check if the difference is significant or not */
2800  if (Index != OldIndex)
2801  {
2802  /* Save flags */
2803  FreeFlags = InUseEntry->Flags & ~HEAP_ENTRY_BUSY;
2804 
2805  if (FreeFlags & HEAP_ENTRY_VIRTUAL_ALLOC)
2806  {
2807  /* This is a virtual block allocation */
2808  VirtualAllocBlock = CONTAINING_RECORD(InUseEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
2809 
2810  // FIXME Tagging!
2811 
2812  DecommitBase = (PCHAR)VirtualAllocBlock + AllocationSize;
2813  DecommitSize = (OldIndex << HEAP_ENTRY_SHIFT) - AllocationSize;
2814 
2815  /* Release the memory */
2816  Status = ZwFreeVirtualMemory(NtCurrentProcess(),
2817  (PVOID *)&DecommitBase,
2818  &DecommitSize,
2819  MEM_RELEASE);
2820 
2821  if (!NT_SUCCESS(Status))
2822  {
2823  DPRINT1("HEAP: Unable to release memory (pointer %p, size 0x%x), Status %08x\n", DecommitBase, DecommitSize, Status);
2824  }
2825  else
2826  {
2827  /* Otherwise reduce the commit size */
2828  VirtualAllocBlock->CommitSize -= DecommitSize;
2829  }
2830  }
2831  else
2832  {
2833  /* Reduce size of the block and possibly split it */
2834  SplitBlock = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
2835 
2836  /* Initialize this entry */
2837  SplitBlock->Flags = FreeFlags;
2838  SplitBlock->PreviousSize = (USHORT)Index;
2839  SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
2840 
2841  /* Remember free size */
2842  FreeSize = InUseEntry->Size - Index;
2843 
2844  /* Set new size */
2845  InUseEntry->Size = (USHORT)Index;
2846  InUseEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
2847 
2848  /* Is that the last entry */
2849  if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
2850  {
2851  SegmentOffset = SplitBlock->SegmentOffset;
2852  ASSERT(SegmentOffset < HEAP_SEGMENTS);
2853  Heap->Segments[SegmentOffset]->LastEntryInSegment = SplitBlock;
2854 
2855  /* Set its size and insert it to the list */
2856  SplitBlock->Size = (USHORT)FreeSize;
2857  RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
2858 
2859  /* Update total free size */
2860  Heap->TotalFreeSize += FreeSize;
2861  }
2862  else
2863  {
2864  /* Get the block after that one */
2865  SplitBlock2 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize);
2866 
2867  if (SplitBlock2->Flags & HEAP_ENTRY_BUSY)
2868  {
2869  /* It's in use, add it here*/
2870  SplitBlock->Size = (USHORT)FreeSize;
2871 
2872  /* Update previous size of the next entry */
2873  ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
2874 
2875  /* Insert it to the list */
2876  RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
2877 
2878  /* Update total size */
2879  Heap->TotalFreeSize += FreeSize;
2880  }
2881  else
2882  {
2883  /* Next entry is free, so merge with it */
2884  SplitBlock->Flags = SplitBlock2->Flags;
2885 
2886  /* Remove it, update total size */
2887  RtlpRemoveFreeBlock(Heap, SplitBlock2, FALSE, FALSE);
2888  Heap->TotalFreeSize -= SplitBlock2->Size;
2889 
2890  /* Calculate total free size */
2891  FreeSize += SplitBlock2->Size;
2892 
2893  if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
2894  {
2895  SplitBlock->Size = (USHORT)FreeSize;
2896 
2897  if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
2898  {
2899  /* Update previous size of the next entry */
2900  ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
2901  }
2902  else
2903  {
2904  SegmentOffset = SplitBlock->SegmentOffset;
2905  ASSERT(SegmentOffset < HEAP_SEGMENTS);
2906  Heap->Segments[SegmentOffset]->LastEntryInSegment = SplitBlock;
2907  }
2908 
2909  /* Insert the new one back and update total size */
2910  RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
2911  Heap->TotalFreeSize += FreeSize;
2912  }
2913  else
2914  {
2915  /* Just add it */
2916  RtlpInsertFreeBlock(Heap, SplitBlock, FreeSize);
2917  }
2918  }
2919  }
2920  }
2921  }
2922  }
2923  else
2924  {
2925  /* We're growing the block */
2926  if ((InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) ||
2927  !RtlpGrowBlockInPlace(Heap, Flags, InUseEntry, Size, Index))
2928  {
2929  /* Growing in place failed, so growing out of place */
2931  {
2932  DPRINT1("Realloc in place failed, but it was the only option\n");
2933  Ptr = NULL;
2934  }
2935  else
2936  {
2937  /* Clear tag bits */
2938  Flags &= ~HEAP_TAG_MASK;
2939 
2940  /* Process extra stuff */
2941  if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2942  {
2943  /* Preserve user settable flags */
2945 
2946  Flags |= HEAP_SETTABLE_USER_VALUE | ((InUseEntry->Flags & HEAP_ENTRY_SETTABLE_FLAGS) << 4);
2947 
2948  /* Get pointer to the old extra data */
2949  OldExtra = RtlpGetExtraStuffPointer(InUseEntry);
2950 
2951  /* Save tag index if it was set */
2952  if (OldExtra->TagIndex &&
2953  !(OldExtra->TagIndex & HEAP_PSEUDO_TAG_FLAG))
2954  {
2955  Flags |= OldExtra->TagIndex << HEAP_TAG_SHIFT;
2956  }
2957  }
2958  else if (InUseEntry->SmallTagIndex)
2959  {
2960  /* Take small tag index into account */
2961  Flags |= InUseEntry->SmallTagIndex << HEAP_TAG_SHIFT;
2962  }
2963 
2964  /* Allocate new block from the heap */
2965  NewBaseAddress = RtlAllocateHeap(HeapPtr,
2967  Size);
2968 
2969  /* Proceed if it didn't fail */
2970  if (NewBaseAddress)
2971  {
2972  /* Get new entry pointer */
2973  NewInUseEntry = (PHEAP_ENTRY)NewBaseAddress - 1;
2974 
2975  /* Process extra stuff if it exists */
2976  if (NewInUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2977  {
2978  NewExtra = RtlpGetExtraStuffPointer(NewInUseEntry);
2979 
2980  if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
2981  {
2982  OldExtra = RtlpGetExtraStuffPointer(InUseEntry);
2983  NewExtra->Settable = OldExtra->Settable;
2984  }
2985  else
2986  {
2987  RtlZeroMemory(NewExtra, sizeof(*NewExtra));
2988  }
2989  }
2990 
2991  /* Copy actual user bits */
2992  if (Size < OldSize)
2993  RtlMoveMemory(NewBaseAddress, Ptr, Size);
2994  else
2995  RtlMoveMemory(NewBaseAddress, Ptr, OldSize);
2996 
2997  /* Zero remaining part if required */
2998  if (Size > OldSize &&
2999  (Flags & HEAP_ZERO_MEMORY))
3000  {
3001  RtlZeroMemory((PCHAR)NewBaseAddress + OldSize, Size - OldSize);
3002  }
3003 
3004  /* Free the old block */
3005  RtlFreeHeap(HeapPtr, Flags, Ptr);
3006  }
3007 
3008  Ptr = NewBaseAddress;
3009  }
3010  }
3011  }
3012 
3013  /* Did resizing fail? */
3014  if (!Ptr && (Flags & HEAP_GENERATE_EXCEPTIONS))
3015  {
3016  /* Generate an exception if required */
3017  ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
3018  ExceptionRecord.ExceptionRecord = NULL;
3019  ExceptionRecord.NumberParameters = 1;
3020  ExceptionRecord.ExceptionFlags = 0;
3021  ExceptionRecord.ExceptionInformation[0] = AllocationSize;
3022 
3023  RtlRaiseException(&ExceptionRecord);
3024  }
3025 
3026  /* Release the heap lock if it was acquired */
3027  if (HeapLocked)
3029 
3030  return Ptr;
3031 }
3032 
3033 
3034 /***********************************************************************
3035  * RtlCompactHeap
3036  *
3037  * @unimplemented
3038  */
3039 ULONG NTAPI
3041  ULONG Flags)
3042 {
3043  UNIMPLEMENTED;
3044  return 0;
3045 }
3046 
3047 
3048 /***********************************************************************
3049  * RtlLockHeap
3050  * Attempts to acquire the critical section object for a specified heap.
3051  *
3052  * PARAMS
3053  * Heap [in] Handle of heap to lock for exclusive access
3054  *
3055  * RETURNS
3056  * TRUE: Success
3057  * FALSE: Failure
3058  *
3059  * @implemented
3060  */
3061 BOOLEAN NTAPI
3063 {
3064  PHEAP Heap = (PHEAP)HeapPtr;
3065 
3066  /* Check for page heap */
3067  if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
3068  {
3069  return RtlpPageHeapLock(Heap);
3070  }
3071 
3072  /* Check if it's really a heap */
3073  if (Heap->Signature != HEAP_SIGNATURE) return FALSE;
3074 
3075  /* Lock if it's lockable */
3076  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3077  {
3079  }
3080 
3081  return TRUE;
3082 }
3083 
3084 
3085 /***********************************************************************
3086  * RtlUnlockHeap
3087  * Releases ownership of the critical section object.
3088  *
3089  * PARAMS
3090  * Heap [in] Handle to the heap to unlock
3091  *
3092  * RETURNS
3093  * TRUE: Success
3094  * FALSE: Failure
3095  *
3096  * @implemented
3097  */
3098 BOOLEAN NTAPI
3100 {
3101  PHEAP Heap = (PHEAP)HeapPtr;
3102 
3103  /* Check for page heap */
3104  if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
3105  {
3106  return RtlpPageHeapUnlock(Heap);
3107  }
3108 
3109  /* Check if it's really a heap */
3110  if (Heap->Signature != HEAP_SIGNATURE) return FALSE;
3111 
3112  /* Unlock if it's lockable */
3113  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3114  {
3116  }
3117 
3118  return TRUE;
3119 }
3120 
3121 
3122 /***********************************************************************
3123  * RtlSizeHeap
3124  * PARAMS
3125  * Heap [in] Handle of heap
3126  * Flags [in] Heap size control flags
3127  * Ptr [in] Address of memory to return size for
3128  *
3129  * RETURNS
3130  * Size in bytes of allocated memory
3131  * 0xffffffff: Failure
3132  *
3133  * @implemented
3134  */
3135 SIZE_T NTAPI
3137  HANDLE HeapPtr,
3138  ULONG Flags,
3139  PVOID Ptr
3140 )
3141 {
3142  PHEAP Heap = (PHEAP)HeapPtr;
3143  PHEAP_ENTRY HeapEntry;
3144  SIZE_T EntrySize;
3145 
3146  // FIXME This is a hack around missing SEH support!
3147  if (!Heap)
3148  {
3150  return (SIZE_T)-1;
3151  }
3152 
3153  /* Force flags */
3154  Flags |= Heap->ForceFlags;
3155 
3156  /* Call special heap */
3157  if (RtlpHeapIsSpecial(Flags))
3158  return RtlDebugSizeHeap(Heap, Flags, Ptr);
3159 
3160  /* Get the heap entry pointer */
3161  HeapEntry = (PHEAP_ENTRY)Ptr - 1;
3162 
3163  /* Return -1 if that entry is free */
3164  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3165  {
3167  return (SIZE_T)-1;
3168  }
3169 
3170  /* Get size of this block depending if it's a usual or a big one */
3171  if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
3172  {
3173  EntrySize = RtlpGetSizeOfBigBlock(HeapEntry);
3174  }
3175  else
3176  {
3177  /* Calculate it */
3178  EntrySize = (HeapEntry->Size << HEAP_ENTRY_SHIFT) - HeapEntry->UnusedBytes;
3179  }
3180 
3181  /* Return calculated size */
3182  return EntrySize;
3183 }
3184 
3185 BOOLEAN NTAPI
3187 {
3188  SIZE_T Size, Result;
3189  PCHAR TailPart;
3190 
3191  /* Calculate size */
3192  if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
3193  Size = RtlpGetSizeOfBigBlock(HeapEntry);
3194  else
3195  Size = (HeapEntry->Size << HEAP_ENTRY_SHIFT) - HeapEntry->UnusedBytes;
3196 
3197  /* Calculate pointer to the tail part of the block */
3198  TailPart = (PCHAR)(HeapEntry + 1) + Size;
3199 
3200  /* Compare tail pattern */
3201  Result = RtlCompareMemory(TailPart,
3202  FillPattern,
3203  HEAP_ENTRY_SIZE);
3204 
3205  if (Result != HEAP_ENTRY_SIZE)
3206  {
3207  DPRINT1("HEAP: Heap entry (size %x) %p tail is modified at %p\n", Size, HeapEntry, TailPart + Result);
3208  return FALSE;
3209  }
3210 
3211  /* All is fine */
3212  return TRUE;
3213 }
3214 
3215 BOOLEAN NTAPI
3217  PHEAP Heap,
3218  BOOLEAN Recalculate)
3219 {
3220  // We skip header validation for now
3221  return TRUE;
3222 }
3223 
3224 BOOLEAN NTAPI
3226  PHEAP Heap,
3227  PHEAP_ENTRY HeapEntry)
3228 {
3229  BOOLEAN BigAllocation, EntryFound = FALSE;
3231  ULONG SegmentOffset;
3232 
3233  /* Perform various consistency checks of this entry */
3234  if (!HeapEntry) goto invalid_entry;
3235  if ((ULONG_PTR)HeapEntry & (HEAP_ENTRY_SIZE - 1)) goto invalid_entry;
3236  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY)) goto invalid_entry;
3237 
3238  BigAllocation = HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC;
3239  Segment = Heap->Segments[HeapEntry->SegmentOffset];
3240 
3241  if (BigAllocation &&
3242  (((ULONG_PTR)HeapEntry & (PAGE_SIZE - 1)) != FIELD_OFFSET(HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock)))
3243  goto invalid_entry;
3244 
3245  if (!BigAllocation && (HeapEntry->SegmentOffset >= HEAP_SEGMENTS ||
3246  !Segment ||
3247  HeapEntry < Segment->FirstEntry ||
3248  HeapEntry >= Segment->LastValidEntry))
3249  goto invalid_entry;
3250 
3251  if ((HeapEntry->Flags & HEAP_ENTRY_FILL_PATTERN) &&
3252  !RtlpCheckInUsePattern(HeapEntry))
3253  goto invalid_entry;
3254 
3255  /* Checks are done, if this is a virtual entry, that's all */
3256  if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) return TRUE;
3257 
3258  /* Go through segments and check if this entry fits into any of them */
3259  for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
3260  {
3261  Segment = Heap->Segments[SegmentOffset];
3262  if (!Segment) continue;
3263 
3264  if ((HeapEntry >= Segment->FirstEntry) &&
3265  (HeapEntry < Segment->LastValidEntry))
3266  {
3267  /* Got it */
3268  EntryFound = TRUE;
3269  break;
3270  }
3271  }
3272 
3273  /* Return our result of finding entry in the segments */
3274  return EntryFound;
3275 
3276 invalid_entry:
3277  DPRINT1("HEAP: Invalid heap entry %p in heap %p\n", HeapEntry, Heap);
3278  return FALSE;
3279 }
3280 
3281 BOOLEAN NTAPI
3283  PHEAP Heap,
3285  UCHAR SegmentOffset,
3286  PULONG FreeEntriesCount,
3287  PSIZE_T TotalFreeSize,
3288  PSIZE_T TagEntries,
3289  PSIZE_T PseudoTagEntries)
3290 {
3291  PHEAP_UCR_DESCRIPTOR UcrDescriptor;
3292  PLIST_ENTRY UcrEntry;
3294  PHEAP_ENTRY CurrentEntry;
3295  ULONG UnCommittedPages;
3296  ULONG UnCommittedRanges;
3297  ULONG PreviousSize;
3298 
3299  UnCommittedPages = 0;
3300  UnCommittedRanges = 0;
3301 
3302  if (IsListEmpty(&Segment->UCRSegmentList))
3303  {
3304  UcrEntry = NULL;
3305  UcrDescriptor = NULL;
3306  }
3307  else
3308  {
3309  UcrEntry = Segment->UCRSegmentList.Flink;
3310  UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
3311  }
3312 
3313  if (Segment->BaseAddress == Heap)
3314  CurrentEntry = &Heap->Entry;
3315  else
3316  CurrentEntry = &Segment->Entry;
3317 
3318  while (CurrentEntry < Segment->LastValidEntry)
3319  {
3320  if (UcrDescriptor &&
3321  ((PVOID)CurrentEntry >= UcrDescriptor->Address))
3322  {
3323  DPRINT1("HEAP: Entry %p is not inside uncommited range [%p .. %p)\n",
3324  CurrentEntry, UcrDescriptor->Address,
3325  (PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
3326 
3327  return FALSE;
3328  }
3329 
3330  PreviousSize = 0;
3331 
3332  while (CurrentEntry < Segment->LastValidEntry)
3333  {
3334  if (PreviousSize != CurrentEntry->PreviousSize)
3335  {
3336  DPRINT1("HEAP: Entry %p has incorrect PreviousSize %x instead of %x\n",
3337  CurrentEntry, CurrentEntry->PreviousSize, PreviousSize);
3338 
3339  return FALSE;
3340  }
3341 
3342  PreviousSize = CurrentEntry->Size;
3343  Size = CurrentEntry->Size << HEAP_ENTRY_SHIFT;
3344 
3345  if (CurrentEntry->Flags & HEAP_ENTRY_BUSY)
3346  {
3347  if (TagEntries)
3348  {
3349  UNIMPLEMENTED;
3350  }
3351 
3352  /* Check fill pattern */
3353  if (CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN)
3354  {
3355  if (!RtlpCheckInUsePattern(CurrentEntry))
3356  return FALSE;
3357  }
3358  }
3359  else
3360  {
3361  /* The entry is free, increase free entries count and total free size */
3362  *FreeEntriesCount = *FreeEntriesCount + 1;
3363  *TotalFreeSize += CurrentEntry->Size;
3364 
3365  if ((Heap->Flags & HEAP_FREE_CHECKING_ENABLED) &&
3366  (CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN))
3367  {
3368  ByteSize = Size - sizeof(HEAP_FREE_ENTRY);
3369 
3370  if ((CurrentEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT) &&
3371  (ByteSize > sizeof(HEAP_FREE_ENTRY_EXTRA)))
3372  {
3373  ByteSize -= sizeof(HEAP_FREE_ENTRY_EXTRA);
3374  }
3375 
3376  Result = RtlCompareMemoryUlong((PCHAR)((PHEAP_FREE_ENTRY)CurrentEntry + 1),
3377  ByteSize,
3379 
3380  if (Result != ByteSize)
3381  {
3382  DPRINT1("HEAP: Free heap block %p modified at %p after it was freed\n",
3383  CurrentEntry,
3384  (PCHAR)(CurrentEntry + 1) + Result);
3385 
3386  return FALSE;
3387  }
3388  }
3389  }
3390 
3391  if (CurrentEntry->SegmentOffset != SegmentOffset)
3392  {
3393  DPRINT1("HEAP: Heap entry %p SegmentOffset is incorrect %x (should be %x)\n",
3394  CurrentEntry, SegmentOffset, CurrentEntry->SegmentOffset);
3395  return FALSE;
3396  }
3397 
3398  /* Check if it's the last entry */
3399  if (CurrentEntry->Flags & HEAP_ENTRY_LAST_ENTRY)
3400  {
3401  CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
3402 
3403  if (!UcrDescriptor)
3404  {
3405  /* Check if it's not really the last one */
3406  if (CurrentEntry != Segment->LastValidEntry)
3407  {
3408  DPRINT1("HEAP: Heap entry %p is not last block in segment (%p)\n",
3409  CurrentEntry, Segment->LastValidEntry);
3410  return FALSE;
3411  }
3412  }
3413  else if (CurrentEntry != UcrDescriptor->Address)
3414  {
3415  DPRINT1("HEAP: Heap entry %p does not match next uncommitted address (%p)\n",
3416  CurrentEntry, UcrDescriptor->Address);
3417 
3418  return FALSE;
3419  }
3420  else
3421  {
3422  UnCommittedPages += (ULONG)(UcrDescriptor->Size / PAGE_SIZE);
3423  UnCommittedRanges++;
3424 
3425  CurrentEntry = (PHEAP_ENTRY)((PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
3426 
3427  /* Go to the next UCR descriptor */
3428  UcrEntry = UcrEntry->Flink;
3429  if (UcrEntry == &Segment->UCRSegmentList)
3430  {
3431  UcrEntry = NULL;
3432  UcrDescriptor = NULL;
3433  }
3434  else
3435  {
3436  UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
3437  }
3438  }
3439 
3440  break;
3441  }
3442 
3443  /* Advance to the next entry */
3444  CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
3445  }
3446  }
3447 
3448  /* Check total numbers of UCP and UCR */
3449  if (Segment->NumberOfUnCommittedPages != UnCommittedPages)
3450  {
3451  DPRINT1("HEAP: Segment %p NumberOfUnCommittedPages is invalid (%x != %x)\n",
3452  Segment, Segment->NumberOfUnCommittedPages, UnCommittedPages);
3453 
3454  return FALSE;
3455  }
3456 
3457  if (Segment->NumberOfUnCommittedRanges != UnCommittedRanges)
3458  {
3459  DPRINT1("HEAP: Segment %p NumberOfUnCommittedRanges is invalid (%x != %x)\n",
3460  Segment, Segment->NumberOfUnCommittedRanges, UnCommittedRanges);
3461 
3462  return FALSE;
3463  }
3464 
3465  return TRUE;
3466 }
3467 
3468 BOOLEAN NTAPI
3470  BOOLEAN ForceValidation)
3471 {
3473  BOOLEAN EmptyList;
3474  UCHAR SegmentOffset;
3475  SIZE_T Size, TotalFreeSize;
3476  ULONG PreviousSize;
3477  PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
3478  PLIST_ENTRY ListHead, NextEntry;
3479  PHEAP_FREE_ENTRY FreeEntry;
3480  ULONG FreeBlocksCount, FreeListEntriesCount;
3481 
3482  /* Check headers */
3483  if (!RtlpValidateHeapHeaders(Heap, FALSE))
3484  return FALSE;
3485 
3486  /* Skip validation if it's not needed */
3487  if (!ForceValidation && !(Heap->Flags & HEAP_VALIDATE_ALL_ENABLED))
3488  return TRUE;
3489 
3490  /* Check free lists bitmaps */
3491  FreeListEntriesCount = 0;
3492  ListHead = &Heap->FreeLists[0];
3493 
3494  for (Size = 0; Size < HEAP_FREELISTS; Size++)
3495  {
3496  if (Size)
3497  {
3498  /* This is a dedicated list. Check if it's empty */
3499  EmptyList = IsListEmpty(ListHead);
3500 
3501  if (Heap->u.FreeListsInUseBytes[Size >> 3] & (1 << (Size & 7)))
3502  {
3503  if (EmptyList)
3504  {
3505  DPRINT1("HEAP: Empty %x-free list marked as non-empty\n", Size);
3506  return FALSE;
3507  }
3508  }
3509  else
3510  {
3511  if (!EmptyList)
3512  {
3513  DPRINT1("HEAP: Non-empty %x-free list marked as empty\n", Size);
3514  return FALSE;
3515  }
3516  }
3517  }
3518 
3519  /* Now check this list entries */
3520  NextEntry = ListHead->Flink;
3521  PreviousSize = 0;
3522 
3523  while (ListHead != NextEntry)
3524  {
3525  FreeEntry = CONTAINING_RECORD(NextEntry, HEAP_FREE_ENTRY, FreeList);
3526  NextEntry = NextEntry->Flink;
3527 
3528  /* If there is an in-use entry in a free list - that's quite a big problem */
3529  if (FreeEntry->Flags & HEAP_ENTRY_BUSY)
3530  {
3531  DPRINT1("HEAP: %Ix-dedicated list free element %p is marked in-use\n", Size, FreeEntry);
3532  return FALSE;
3533  }
3534 
3535  /* Check sizes according to that specific list's size */
3536  if ((Size == 0) && (FreeEntry->Size < HEAP_FREELISTS))
3537  {
3538  DPRINT1("HEAP: Non dedicated list free element %p has size %x which would fit a dedicated list\n", FreeEntry, FreeEntry->Size);
3539  return FALSE;
3540  }
3541  else if (Size && (FreeEntry->Size != Size))
3542  {
3543  DPRINT1("HEAP: %Ix-dedicated list free element %p has incorrect size %x\n", Size, FreeEntry, FreeEntry->Size);
3544  return FALSE;
3545  }
3546  else if ((Size == 0) && (FreeEntry->Size < PreviousSize))
3547  {
3548  DPRINT1("HEAP: Non dedicated list free element %p is not put in order\n", FreeEntry);
3549  return FALSE;
3550  }
3551 
3552  /* Remember previous size*/
3553  PreviousSize = FreeEntry->Size;
3554 
3555  /* Add up to the total amount of free entries */
3556  FreeListEntriesCount++;
3557  }
3558 
3559  /* Go to the head of the next free list */
3560  ListHead++;
3561  }
3562 
3563  /* Check big allocations */
3564  ListHead = &Heap->VirtualAllocdBlocks;
3565  NextEntry = ListHead->Flink;
3566 
3567  while (ListHead != NextEntry)
3568  {
3569  VirtualAllocBlock = CONTAINING_RECORD(NextEntry, HEAP_VIRTUAL_ALLOC_ENTRY, Entry);
3570 
3571  /* We can only check the fill pattern */
3572  if (VirtualAllocBlock->BusyBlock.Flags & HEAP_ENTRY_FILL_PATTERN)
3573  {
3574  if (!RtlpCheckInUsePattern(&VirtualAllocBlock->BusyBlock))
3575  return FALSE;
3576  }
3577 
3578  NextEntry = NextEntry->Flink;
3579  }
3580 
3581  /* Check all segments */
3582  FreeBlocksCount = 0;
3583  TotalFreeSize = 0;
3584 
3585  for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
3586  {
3587  Segment = Heap->Segments[SegmentOffset];
3588 
3589  /* Go to the next one if there is no segment */
3590  if (!Segment) continue;
3591 
3592  if (!RtlpValidateHeapSegment(Heap,
3593  Segment,
3594  SegmentOffset,
3595  &FreeBlocksCount,
3596  &TotalFreeSize,
3597  NULL,
3598  NULL))
3599  {
3600  return FALSE;
3601  }
3602  }
3603 
3604  if (FreeListEntriesCount != FreeBlocksCount)
3605  {
3606  DPRINT1("HEAP: Free blocks count in arena (%lu) does not match free blocks number in the free lists (%lu)\n", FreeBlocksCount, FreeListEntriesCount);
3607  return FALSE;
3608  }
3609 
3610  if (Heap->TotalFreeSize != TotalFreeSize)
3611  {
3612  DPRINT1("HEAP: Total size of free blocks in arena (%Iu) does not equal to the one in heap header (%Iu)\n", TotalFreeSize, Heap->TotalFreeSize);
3613  return FALSE;
3614  }
3615 
3616  return TRUE;
3617 }
3618 
3619 /***********************************************************************
3620  * RtlValidateHeap
3621  * Validates a specified heap.
3622  *
3623  * PARAMS
3624  * Heap [in] Handle to the heap
3625  * Flags [in] Bit flags that control access during operation
3626  * Block [in] Optional pointer to memory block to validate
3627  *
3628  * NOTES
3629  * Flags is ignored.
3630  *
3631  * RETURNS
3632  * TRUE: Success
3633  * FALSE: Failure
3634  *
3635  * @implemented
3636  */
3638  HANDLE HeapPtr,
3639  ULONG Flags,
3640  PVOID Block
3641 )
3642 {
3643  PHEAP Heap = (PHEAP)HeapPtr;
3644  BOOLEAN HeapLocked = FALSE;
3645  BOOLEAN HeapValid;
3646 
3647  /* Check for page heap */
3648  if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
3649  return RtlpDebugPageHeapValidate(HeapPtr, Flags, Block);
3650 
3651  /* Check signature */
3652  if (Heap->Signature != HEAP_SIGNATURE)
3653  {
3654  DPRINT1("HEAP: Signature %lx is invalid for heap %p\n", Heap->Signature, Heap);
3655  return FALSE;
3656  }
3657 
3658  /* Force flags */
3659  Flags = Heap->ForceFlags;
3660 
3661  /* Acquire the lock if necessary */
3662  if (!(Flags & HEAP_NO_SERIALIZE))
3663  {
3665  HeapLocked = TRUE;
3666  }
3667 
3668  /* Either validate whole heap or just one entry */
3669  if (!Block)
3670  HeapValid = RtlpValidateHeap(Heap, TRUE);
3671  else
3672  HeapValid = RtlpValidateHeapEntry(Heap, (PHEAP_ENTRY)Block - 1);
3673 
3674  /* Unlock if it's lockable */
3675  if (HeapLocked)
3676  {
3678  }
3679 
3680  return HeapValid;
3681 }
3682 
3683 /*
3684  * @implemented
3685  */
3688  PVOID lParam)
3689 {
3690  UNIMPLEMENTED;
3691  return STATUS_NOT_IMPLEMENTED;
3692 }
3693 
3694 
3695 /*
3696  * @implemented
3697  */
3698 ULONG NTAPI
3700  HANDLE *heaps)
3701 {
3702  UNIMPLEMENTED;
3703  return 0;
3704 }
3705 
3706 
3707 /*
3708  * @implemented
3709  */
3710 BOOLEAN NTAPI
3712 {
3713  UNIMPLEMENTED;
3714  return TRUE;
3715 }
3716 
3717 
3718 /*
3719  * @unimplemented
3720  */
3721 BOOLEAN NTAPI
3723  IN PVOID HeapHandle,
3724  IN ULONG Flags
3725  )
3726 {
3727  UNIMPLEMENTED;
3728  return FALSE;
3729 }
3730 
3731 /*
3732  * @implemented
3733  */
3734 BOOLEAN
3735 NTAPI
3737  IN ULONG Flags,
3739  IN PVOID UserValue)
3740 {
3741  PHEAP Heap = (PHEAP)HeapHandle;
3742  PHEAP_ENTRY HeapEntry;
3743  PHEAP_ENTRY_EXTRA Extra;
3744  BOOLEAN HeapLocked = FALSE, ValueSet = FALSE;
3745 
3746  /* Force flags */
3747  Flags |= Heap->Flags;
3748 
3749  /* Call special heap */
3750  if (RtlpHeapIsSpecial(Flags))
3751  return RtlDebugSetUserValueHeap(Heap, Flags, BaseAddress, UserValue);
3752 
3753  /* Lock if it's lockable */
3754  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3755  {
3757  HeapLocked = TRUE;
3758  }
3759 
3760  /* Get a pointer to the entry */
3761  HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
3762 
3763  /* If it's a free entry - return error */
3764  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3765  {
3767 
3768  /* Release the heap lock if it was acquired */
3769  if (HeapLocked)
3771 
3772  return FALSE;
3773  }
3774 
3775  /* Check if this entry has an extra stuff associated with it */
3776  if (HeapEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
3777  {
3778  /* Use extra to store the value */
3779  Extra = RtlpGetExtraStuffPointer(HeapEntry);
3780  Extra->Settable = (ULONG_PTR)UserValue;
3781 
3782  /* Indicate that value was set */
3783  ValueSet = TRUE;
3784  }
3785 
3786  /* Release the heap lock if it was acquired */
3787  if (HeapLocked)
3789 
3790  return ValueSet;
3791 }
3792 
3793 /*
3794  * @implemented
3795  */
3796 BOOLEAN
3797 NTAPI
3799  IN ULONG Flags,
3801  IN ULONG UserFlagsReset,
3802  IN ULONG UserFlagsSet)
3803 {
3804  PHEAP Heap = (PHEAP)HeapHandle;
3805  PHEAP_ENTRY HeapEntry;
3806  BOOLEAN HeapLocked = FALSE;
3807 
3808  /* Force flags */
3809  Flags |= Heap->Flags;
3810 
3811  /* Call special heap */
3812  if (RtlpHeapIsSpecial(Flags))
3813  return RtlDebugSetUserFlagsHeap(Heap, Flags, BaseAddress, UserFlagsReset, UserFlagsSet);
3814 
3815  /* Lock if it's lockable */
3816  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3817  {
3819  HeapLocked = TRUE;
3820  }
3821 
3822  /* Get a pointer to the entry */
3823  HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
3824 
3825  /* If it's a free entry - return error */
3826  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3827  {
3829 
3830  /* Release the heap lock if it was acquired */
3831  if (HeapLocked)
3833 
3834  return FALSE;
3835  }
3836 
3837  /* Set / reset flags */
3838  HeapEntry->Flags &= ~(UserFlagsReset >> 4);
3839  HeapEntry->Flags |= (UserFlagsSet >> 4);
3840 
3841  /* Release the heap lock if it was acquired */
3842  if (HeapLocked)
3844 
3845  return TRUE;
3846 }
3847 
3848 /*
3849  * @implemented
3850  */
3851 BOOLEAN
3852 NTAPI
3854  IN ULONG Flags,
3856  OUT PVOID *UserValue,
3857  OUT PULONG UserFlags)
3858 {
3859  PHEAP Heap = (PHEAP)HeapHandle;
3860  PHEAP_ENTRY HeapEntry;
3861  PHEAP_ENTRY_EXTRA Extra;
3862  BOOLEAN HeapLocked = FALSE;
3863 
3864  /* Force flags */
3865  Flags |= Heap->Flags;
3866 
3867  /* Call special heap */
3868  if (RtlpHeapIsSpecial(Flags))
3869  return RtlDebugGetUserInfoHeap(Heap, Flags, BaseAddress, UserValue, UserFlags);
3870 
3871  /* Lock if it's lockable */
3872  if (!(Heap->Flags & HEAP_NO_SERIALIZE))
3873  {
3875  HeapLocked = TRUE;
3876  }
3877 
3878  /* Get a pointer to the entry */
3879  HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
3880 
3881  /* If it's a free entry - return error */
3882  if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
3883  {
3885 
3886  /* Release the heap lock if it was acquired */
3887  if (HeapLocked)
3889 
3890  return FALSE;
3891  }
3892 
3893  /* Check if this entry has an extra stuff associated with it */
3894  if (HeapEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
3895  {
3896  /* Get pointer to extra data */
3897  Extra = RtlpGetExtraStuffPointer(HeapEntry);
3898 
3899  /* Pass user value */
3900  if (UserValue)
3901  *UserValue = (PVOID)Extra->Settable;
3902  }
3903 
3904  /* Decode and return user flags */
3905  if (UserFlags)
3906  *UserFlags = (HeapEntry->Flags & HEAP_ENTRY_SETTABLE_FLAGS) << 4;
3907 
3908  /* Release the heap lock if it was acquired */
3909  if (HeapLocked)
3911 
3912  return TRUE;
3913 }
3914 
3915 /*
3916  * @unimplemented
3917  */
3918 NTSTATUS
3919 NTAPI
3921  IN ULONG Flags,
3923 {
3924  /* TODO */
3925  UNIMPLEMENTED;
3926  return STATUS_NOT_IMPLEMENTED;
3927 }
3928 
3929 PWSTR
3930 NTAPI
3932  IN ULONG Flags,
3933  IN USHORT TagIndex,
3934  IN BOOLEAN ResetCounters,
3935  OUT PRTL_HEAP_TAG_INFO HeapTagInfo)
3936 {
3937  /* TODO */
3938  UNIMPLEMENTED;
3939  return NULL;
3940 }
3941 
3942 ULONG
3943 NTAPI
3945  IN ULONG Flags,
3946  IN PVOID P,
3947  IN SIZE_T Size)
3948 {
3949  /* TODO */
3950  UNIMPLEMENTED;
3951  return 0;
3952 }
3953 
3954 ULONG
3955 NTAPI
3957  IN ULONG Flags,
3958  IN PWSTR TagName,
3959  IN PWSTR TagSubName)
3960 {
3961  /* TODO */
3962  UNIMPLEMENTED;
3963  return 0;
3964 }
3965 
3966 NTSTATUS
3967 NTAPI
3968 RtlWalkHeap(IN HANDLE HeapHandle,
3969  IN PVOID HeapEntry)
3970 {
3971  UNIMPLEMENTED;
3972  return STATUS_NOT_IMPLEMENTED;
3973 }
3974 
3975 PVOID
3976 NTAPI
3979 {
3980  UNIMPLEMENTED;
3981  return NULL;
3982 }
3983 
3984 NTSTATUS
3985 NTAPI
3987  IN HEAP_INFORMATION_CLASS HeapInformationClass,
3988  IN PVOID HeapInformation,
3989  IN SIZE_T HeapInformationLength)
3990 {
3991  /* Setting heap information is not really supported except for enabling LFH */
3992  if (HeapInformationClass == HeapCompatibilityInformation)
3993  {
3994  /* Check buffer length */
3995  if (HeapInformationLength < sizeof(ULONG))
3996  {
3997  /* The provided buffer is too small */
3998  return STATUS_BUFFER_TOO_SMALL;
3999  }
4000 
4001  /* Check for a special magic value for enabling LFH */
4002  if (*(PULONG)HeapInformation != 2)
4003  {
4004  return STATUS_UNSUCCESSFUL;
4005  }
4006 
4007  DPRINT1("RtlSetHeapInformation() needs to enable LFH\n");
4008  return STATUS_SUCCESS;
4009  }
4010 
4011  return STATUS_SUCCESS;
4012 }
4013 
4014 NTSTATUS
4015 NTAPI
4017  HEAP_INFORMATION_CLASS HeapInformationClass,
4018  PVOID HeapInformation,
4019  SIZE_T HeapInformationLength,
4021 {
4022  PHEAP Heap = (PHEAP)HeapHandle;
4023 
4024  /* Only HeapCompatibilityInformation is supported */
4025  if (HeapInformationClass == HeapCompatibilityInformation)
4026  {
4027  /* Set result length */
4028  if (ReturnLength)
4029  *ReturnLength = sizeof(ULONG);
4030 
4031  /* Check buffer length */
4032  if (HeapInformationLength < sizeof(ULONG))
4033  {
4034  /* It's too small, return needed length */
4035  return STATUS_BUFFER_TOO_SMALL;
4036  }
4037 
4038  /* Return front end heap type */
4039  *(PULONG)HeapInformation = Heap->FrontEndHeapType;
4040 
4041  return STATUS_SUCCESS;
4042  }
4043 
4044  return STATUS_UNSUCCESSFUL;
4045 }
4046 
4047 /* @implemented */
4048 ULONG
4049 NTAPI
4051  IN ULONG Flags,
4052  IN SIZE_T Size,
4053  IN ULONG Count,
4054  OUT PVOID *Array)
4055 {
4056  ULONG Index;
4057  EXCEPTION_RECORD ExceptionRecord;
4058 
4059  for (Index = 0; Index < Count; ++Index)
4060  {
4061  Array[Index] = RtlAllocateHeap(HeapHandle, Flags, Size);
4062  if (Array[Index] == NULL)
4063  {
4064  /* ERROR_NOT_ENOUGH_MEMORY */
4066 
4068  {
4069  ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
4070  ExceptionRecord.ExceptionRecord = NULL;
4071  ExceptionRecord.NumberParameters = 0;
4072  ExceptionRecord.ExceptionFlags = 0;
4073 
4074  RtlRaiseException(&ExceptionRecord);
4075  }
4076  break;
4077  }
4078  }
4079 
4080  return Index;
4081 }
4082 
4083 /* @implemented */
4084 ULONG
4085 NTAPI
4087  IN ULONG Flags,
4088  IN ULONG Count,
4089  OUT PVOID *Array)
4090 {
4091  ULONG Index;
4092 
4093  for (Index = 0; Index < Count; ++Index)
4094  {
4095  if (Array[Index] == NULL)
4096  continue;
4097 
4098  _SEH2_TRY
4099  {
4100  if (!RtlFreeHeap(HeapHandle, Flags, Array[Index]))
4101  {
4102  /* ERROR_INVALID_PARAMETER */
4104  break;
4105  }
4106  }
4108  {
4109  /* ERROR_INVALID_PARAMETER */
4111  break;
4112  }
4113  _SEH2_END;
4114  }
4115 
4116  return Index;
4117 }
4118 
4119 /*
4120  * Info:
4121  * - https://securityxploded.com/enumheaps.php
4122  * - https://evilcodecave.wordpress.com/2009/04/14/rtlqueryprocessheapinformation-as-anti-dbg-trick/
4123  */
4124 struct _DEBUG_BUFFER;
4125 
4126 NTSTATUS
4127 NTAPI
4129  IN struct _DEBUG_BUFFER *DebugBuffer)
4130 {
4131  UNIMPLEMENTED;
4132  return STATUS_NOT_IMPLEMENTED;
4133 }
4134 
4135 /* 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
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define HEAP_CREATE_ALIGN_16
Definition: nt_native.h:1701
PVOID NTAPI RtlReAllocateHeap(HANDLE HeapPtr, ULONG Flags, PVOID Ptr, SIZE_T Size)
Definition: heap.c: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_ 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 STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#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:3920
#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:4086
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:3225
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:3931
#define HEAP_EXTRA_FLAGS_MASK
Definition: heap.h:36
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1173
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:3136
BOOLEAN RtlpPageHeapEnabled
Definition: heappage.c:106
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:245
BOOLEAN NTAPI RtlpValidateHeap(PHEAP Heap, BOOLEAN ForceValidation)
Definition: heap.c:3469
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:3216
#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
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
BOOLEAN NTAPI RtlSetUserValueHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID BaseAddress, IN PVOID UserValue)
Definition: heap.c:3736
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
ULONG_PTR * PSIZE_T
Definition: typedefs.h: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:260
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:3956
Definition: heap.h:130
unsigned char BOOLEAN
struct _HEAP_ENTRY * PHEAP_ENTRY
VOID NTAPI RtlpAddHeapToProcessList(struct _HEAP *Heap)
Definition: libsupp.c:230
smooth NULL
Definition: ftsmooth.c:416
static WCHAR Address[46]
Definition: ping.c:68
BOOLEAN NTAPI RtlDebugFreeHeap(HANDLE HeapPtr, ULONG Flags, PVOID Ptr)
Definition: heapdbg.c:267
#define FORCEINLINE
Definition: ntbasedef.h:221
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
#define HEAP_ENTRY_BUSY
Definition: heap.h:41
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
void DPRINT(...)
Definition: polytest.cpp:61
_In_ BOOLEAN Remove
Definition: psfuncs.h:110
SIZE_T CommittedSize
Definition: heap.h: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:3853
#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:3944
#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:1051
BOOLEAN NTAPI RtlZeroHeap(IN PVOID HeapHandle, IN ULONG Flags)
Definition: heap.c:3722
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:4016
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:3040
NTSYSAPI NTSTATUS NTAPI ZwQueryVirtualMemory(_In_ HANDLE ProcessHandle, _In_ PVOID Address, _In_ MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass, _Out_ PVOID VirtualMemoryInformation, _In_ SIZE_T Length, _Out_opt_ PSIZE_T ResultLength)
#define MEM_FREE
Definition: nt_native.h:1317
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
PVOID NTAPI RtlpPageHeapDestroy(HANDLE HeapPtr)
Definition: heappage.c:1613
BOOLEAN NTAPI RtlDebugDestroyHeap(HANDLE HeapPtr)
Definition: heapdbg.c:95
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]
Definition: compat.h:213
SIZE_T CommitSize
Definition: heap.h:316
UCHAR FrontEndHeapType
Definition: heap.h:271
#define _SEH2_YIELD(STMT_)
Definition: pseh2_64.h:8
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:3977
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
#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:3968
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
static const UCHAR Index[8]
Definition: usbohci.c:18
#define HEAP_ENTRY_SIZE
Definition: heap.h:18
union _HEAP::@4120 u
#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
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
VOID NTAPI RtlpRemoveFreeBlock(PHEAP Heap, PHEAP_FREE_ENTRY FreeEntry, BOOLEAN Dedicated, BOOLEAN NoFill)
Definition: heap.c: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:3986
MmuFreePage * FreeList
Definition: mmuobject.c:60
LIST_ENTRY SegmentEntry
Definition: heap.h:284
Status
Definition: gdiplustypes.h:24
_In_ PPCI_DEVICE_PRESENCE_PARAMETERS Parameters
Definition: iotypes.h:876
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:3186
#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
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG IN OUT PLONG IN LONG Increment IN PNDIS_RW_LOCK Lock
Definition: CrNtStubs.h:75
struct _HEAP_ENTRY HEAP_ENTRY
#define HEAP_FLAG_PAGE_ALLOCS
Definition: rtltypes.h:160
SIZE_T NTAPI RtlDebugSizeHeap(HANDLE HeapPtr, ULONG Flags, PVOID Ptr)
Definition: heapdbg.c:494
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:361
NTSTATUS NTAPI RtlQueryProcessHeapInformation(IN struct _DEBUG_BUFFER *DebugBuffer)
Definition: heap.c:4128
BOOLEAN NTAPI RtlSetUserFlagsHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID BaseAddress, IN ULONG UserFlagsReset, IN ULONG UserFlagsSet)
Definition: heap.c:3798
#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:4050
ULONG_PTR AlignRound
Definition: heap.h:250
_SEH2_END
Definition: create.c:4400
#define HEAP_TAG_SHIFT
Definition: nt_native.h:1724
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
struct _HEAP_ENTRY_EXTRA HEAP_ENTRY_EXTRA
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
BOOLEAN NTAPI RtlUnlockHeap(HANDLE HeapPtr)
Definition: heap.c:3099
SIZE_T SegmentCommit
Definition: heap.h:237
unsigned int * PULONG
Definition: retypes.h:1
NTSTATUS NTAPI RtlpInitializeHeapSegment(IN OUT PHEAP Heap, OUT PHEAP_SEGMENT Segment, IN UCHAR SegmentIndex, IN ULONG SegmentFlags, IN SIZE_T SegmentReserve, IN SIZE_T SegmentCommit)
Definition: heap.c: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:3699
#define DPRINT1
Definition: precomp.h:8
BOOLEAN NTAPI RtlValidateProcessHeaps(VOID)
Definition: heap.c:3711
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
#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)
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 HEAP_CAPTURE_STACK_BACKTRACES
Definition: rtltypes.h:164
NTSTATUS NTAPI RtlEnumProcessHeaps(PHEAP_ENUMERATION_ROUTINE HeapEnumerationRoutine, PVOID lParam)
Definition: heap.c:3687
DWORD NumberParameters
Definition: compat.h:212
BOOLEAN NTAPI RtlLockHeap(IN HANDLE HeapPtr)
Definition: heap.c:3062
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
return STATUS_SUCCESS
Definition: btrfs.c:3014
_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:3282
#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:3637
ULONG NTAPI RtlGetNtGlobalFlags(VOID)
Definition: libsupp.c:93
BOOLEAN NTAPI RtlpDebugPageHeapValidate(PVOID HeapPtr, ULONG Flags, PVOID Block)
Definition: heappage.c:2290
HANDLE NTAPI RtlpPageHeapCreate(ULONG Flags, PVOID Addr, SIZE_T TotalSize, SIZE_T CommitSize, PVOID Lock, PRTL_HEAP_PARAMETERS Parameters)
Definition: heappage.c:1472
LIST_ENTRY FreeLists[HEAP_FREELISTS]
Definition: heap.h: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