00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <rtl.h>
00021 #include <heap.h>
00022
00023 #define NDEBUG
00024 #include <debug.h>
00025
00026
00027
00028
00029 UCHAR RtlpBitsClearLow[] =
00030 {
00031 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00032 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00033 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00034 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00035 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00036 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00037 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00038 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00039 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00040 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00041 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00042 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00043 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00044 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00045 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
00046 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
00047 };
00048
00049 UCHAR FORCEINLINE
00050 RtlpFindLeastSetBit(ULONG Bits)
00051 {
00052 if (Bits & 0xFFFF)
00053 {
00054 if (Bits & 0xFF)
00055 return RtlpBitsClearLow[Bits & 0xFF];
00056 else
00057 return RtlpBitsClearLow[(Bits >> 8) & 0xFF] + 8;
00058 }
00059 else
00060 {
00061 if ((Bits >> 16) & 0xFF)
00062 return RtlpBitsClearLow[(Bits >> 16) & 0xFF] + 16;
00063 else
00064 return RtlpBitsClearLow[(Bits >> 24) & 0xFF] + 24;
00065 }
00066 }
00067
00068
00069 UCHAR FillPattern[HEAP_ENTRY_SIZE] =
00070 {
00071 HEAP_TAIL_FILL,
00072 HEAP_TAIL_FILL,
00073 HEAP_TAIL_FILL,
00074 HEAP_TAIL_FILL,
00075 HEAP_TAIL_FILL,
00076 HEAP_TAIL_FILL,
00077 HEAP_TAIL_FILL,
00078 HEAP_TAIL_FILL
00079 };
00080
00081
00082
00083 NTSTATUS NTAPI
00084 RtlpInitializeHeap(OUT PHEAP Heap,
00085 IN ULONG Flags,
00086 IN PHEAP_LOCK Lock OPTIONAL,
00087 IN PRTL_HEAP_PARAMETERS Parameters)
00088 {
00089 ULONG NumUCRs = 8;
00090 ULONG Index;
00091 SIZE_T HeaderSize;
00092 NTSTATUS Status;
00093 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
00094
00095
00096 ASSERT(Heap != NULL);
00097 ASSERT(Parameters != NULL);
00098 ASSERT(!(Flags & HEAP_LOCK_USER_ALLOCATED));
00099 ASSERT(!(Flags & HEAP_NO_SERIALIZE) || (Lock == NULL));
00100
00101
00102 HeaderSize = ROUND_UP(sizeof(HEAP), sizeof(HEAP_ENTRY));
00103
00104
00105 if (!(Flags & HEAP_NO_SERIALIZE))
00106 {
00107 if (Lock != NULL)
00108
00109 Flags |= HEAP_LOCK_USER_ALLOCATED;
00110 else
00111 if (RtlpGetMode() == UserMode)
00112 {
00113
00114 Lock = (PHEAP_LOCK) ((ULONG_PTR) (Heap) + HeaderSize);
00115 HeaderSize += ROUND_UP(sizeof(HEAP_LOCK), sizeof(HEAP_ENTRY));
00116 }
00117 }
00118
00119
00120 UcrDescriptor = (PHEAP_UCR_DESCRIPTOR) ((ULONG_PTR) (Heap) + HeaderSize);
00121 HeaderSize += ROUND_UP(NumUCRs * sizeof(HEAP_UCR_DESCRIPTOR), sizeof(HEAP_ENTRY));
00122
00123
00124 ASSERT(HeaderSize <= PAGE_SIZE);
00125
00126
00127 Heap->Entry.Size = (USHORT)(HeaderSize >> HEAP_ENTRY_SHIFT);
00128 Heap->Entry.Flags = HEAP_ENTRY_BUSY;
00129 Heap->Entry.SmallTagIndex = LOBYTE(Heap->Entry.Size) ^ HIBYTE(Heap->Entry.Size) ^ Heap->Entry.Flags;
00130 Heap->Entry.PreviousSize = 0;
00131 Heap->Entry.SegmentOffset = 0;
00132 Heap->Entry.UnusedBytes = 0;
00133
00134
00135 Heap->Signature = HEAP_SIGNATURE;
00136 Heap->Flags = Flags;
00137 Heap->ForceFlags = (Flags & (HEAP_NO_SERIALIZE |
00138 HEAP_GENERATE_EXCEPTIONS |
00139 HEAP_ZERO_MEMORY |
00140 HEAP_REALLOC_IN_PLACE_ONLY |
00141 HEAP_VALIDATE_PARAMETERS_ENABLED |
00142 HEAP_VALIDATE_ALL_ENABLED |
00143 HEAP_TAIL_CHECKING_ENABLED |
00144 HEAP_CREATE_ALIGN_16 |
00145 HEAP_FREE_CHECKING_ENABLED));
00146
00147
00148 Heap->VirtualMemoryThreshold = ROUND_UP(Parameters->VirtualMemoryThreshold, sizeof(HEAP_ENTRY)) >> HEAP_ENTRY_SHIFT;
00149 Heap->SegmentReserve = Parameters->SegmentReserve;
00150 Heap->SegmentCommit = Parameters->SegmentCommit;
00151 Heap->DeCommitFreeBlockThreshold = Parameters->DeCommitFreeBlockThreshold >> HEAP_ENTRY_SHIFT;
00152 Heap->DeCommitTotalFreeThreshold = Parameters->DeCommitTotalFreeThreshold >> HEAP_ENTRY_SHIFT;
00153 Heap->MaximumAllocationSize = Parameters->MaximumAllocationSize;
00154 Heap->CommitRoutine = Parameters->CommitRoutine;
00155
00156
00157 Heap->HeaderValidateCopy = NULL;
00158 Heap->HeaderValidateLength = (USHORT)HeaderSize;
00159
00160
00161 if (!(Flags & HEAP_NO_SERIALIZE) && !(Flags & HEAP_LOCK_USER_ALLOCATED))
00162 {
00163 Status = RtlInitializeHeapLock(&Lock);
00164 if (!NT_SUCCESS(Status))
00165 return Status;
00166 }
00167 Heap->LockVariable = Lock;
00168
00169
00170 if (Flags & HEAP_CREATE_ALIGN_16)
00171 {
00172 Heap->AlignMask = (ULONG) ~15;
00173 Heap->AlignRound = 15 + sizeof(HEAP_ENTRY);
00174 }
00175 else
00176 {
00177 Heap->AlignMask = (ULONG) ~(sizeof(HEAP_ENTRY) - 1);
00178 Heap->AlignRound = 2 * sizeof(HEAP_ENTRY) - 1;
00179 }
00180
00181 if (Flags & HEAP_TAIL_CHECKING_ENABLED)
00182 Heap->AlignRound += sizeof(HEAP_ENTRY);
00183
00184
00185 for (Index = 0; Index < HEAP_SEGMENTS; ++Index)
00186 Heap->Segments[Index] = NULL;
00187
00188
00189 for (Index = 0; Index < HEAP_FREELISTS; ++Index)
00190 InitializeListHead(&Heap->FreeLists[Index]);
00191
00192
00193 InitializeListHead(&Heap->VirtualAllocdBlocks);
00194
00195
00196 InitializeListHead(&Heap->UCRSegments);
00197 InitializeListHead(&Heap->UCRList);
00198
00199
00200 for (Index = 0; Index < NumUCRs; ++Index)
00201 InsertTailList(&Heap->UCRList, &UcrDescriptor[Index].ListEntry);
00202
00203 return STATUS_SUCCESS;
00204 }
00205
00206 VOID FORCEINLINE
00207 RtlpSetFreeListsBit(PHEAP Heap,
00208 PHEAP_FREE_ENTRY FreeEntry)
00209 {
00210 ULONG Index, Bit;
00211
00212 ASSERT(FreeEntry->Size < HEAP_FREELISTS);
00213
00214
00215 Index = FreeEntry->Size >> 3;
00216 Bit = 1 << (FreeEntry->Size & 7);
00217
00218
00219 ASSERT((Heap->u.FreeListsInUseBytes[Index] & Bit) == 0);
00220
00221
00222 Heap->u.FreeListsInUseBytes[Index] |= Bit;
00223 }
00224
00225 VOID FORCEINLINE
00226 RtlpClearFreeListsBit(PHEAP Heap,
00227 PHEAP_FREE_ENTRY FreeEntry)
00228 {
00229 ULONG Index, Bit;
00230
00231 ASSERT(FreeEntry->Size < HEAP_FREELISTS);
00232
00233
00234 Index = FreeEntry->Size >> 3;
00235 Bit = 1 << (FreeEntry->Size & 7);
00236
00237
00238 ASSERT(Heap->u.FreeListsInUseBytes[Index] & Bit);
00239 ASSERT(IsListEmpty(&Heap->FreeLists[FreeEntry->Size]));
00240
00241
00242 Heap->u.FreeListsInUseBytes[Index] ^= Bit;
00243 }
00244
00245 VOID NTAPI
00246 RtlpInsertFreeBlockHelper(PHEAP Heap,
00247 PHEAP_FREE_ENTRY FreeEntry,
00248 SIZE_T BlockSize,
00249 BOOLEAN NoFill)
00250 {
00251 PLIST_ENTRY FreeListHead, Current;
00252 PHEAP_FREE_ENTRY CurrentEntry;
00253
00254 ASSERT(FreeEntry->Size == BlockSize);
00255
00256
00257 if (!NoFill)
00258 {
00259 FreeEntry->Flags &= ~(HEAP_ENTRY_FILL_PATTERN |
00260 HEAP_ENTRY_EXTRA_PRESENT |
00261 HEAP_ENTRY_BUSY);
00262
00263 if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
00264 {
00265 RtlFillMemoryUlong((PCHAR)(FreeEntry + 1),
00266 (BlockSize << HEAP_ENTRY_SHIFT) - sizeof(*FreeEntry),
00267 ARENA_FREE_FILLER);
00268
00269 FreeEntry->Flags |= HEAP_ENTRY_FILL_PATTERN;
00270 }
00271 }
00272 else
00273 {
00274
00275 FreeEntry->Flags &= HEAP_ENTRY_LAST_ENTRY;
00276 }
00277
00278
00279 if (BlockSize < HEAP_FREELISTS)
00280 {
00281
00282 FreeListHead = &Heap->FreeLists[BlockSize];
00283
00284 if (IsListEmpty(FreeListHead))
00285 {
00286 RtlpSetFreeListsBit(Heap, FreeEntry);
00287 }
00288 }
00289 else
00290 {
00291
00292 FreeListHead = &Heap->FreeLists[0];
00293 Current = FreeListHead->Flink;
00294
00295
00296 while (FreeListHead != Current)
00297 {
00298 CurrentEntry = CONTAINING_RECORD(Current, HEAP_FREE_ENTRY, FreeList);
00299
00300 if (BlockSize <= CurrentEntry->Size)
00301 break;
00302
00303 Current = Current->Flink;
00304 }
00305
00306 FreeListHead = Current;
00307 }
00308
00309
00310 InsertTailList(FreeListHead, &FreeEntry->FreeList);
00311 }
00312
00313 VOID NTAPI
00314 RtlpInsertFreeBlock(PHEAP Heap,
00315 PHEAP_FREE_ENTRY FreeEntry,
00316 SIZE_T BlockSize)
00317 {
00318 USHORT Size, PreviousSize;
00319 UCHAR SegmentOffset, Flags;
00320 PHEAP_SEGMENT Segment;
00321
00322 DPRINT("RtlpInsertFreeBlock(%p %p %x)\n", Heap, FreeEntry, BlockSize);
00323
00324
00325 Heap->TotalFreeSize += BlockSize;
00326
00327
00328 Flags = FreeEntry->Flags;
00329 PreviousSize = FreeEntry->PreviousSize;
00330 SegmentOffset = FreeEntry->SegmentOffset;
00331 Segment = Heap->Segments[SegmentOffset];
00332
00333
00334 while (BlockSize)
00335 {
00336
00337 if (BlockSize > HEAP_MAX_BLOCK_SIZE)
00338 {
00339 Size = HEAP_MAX_BLOCK_SIZE;
00340
00341
00342 if (BlockSize == (HEAP_MAX_BLOCK_SIZE + 1))
00343 Size -= 16;
00344
00345 FreeEntry->Flags = 0;
00346 }
00347 else
00348 {
00349 Size = (USHORT)BlockSize;
00350 FreeEntry->Flags = Flags;
00351 }
00352
00353
00354 FreeEntry->Size = Size;
00355 FreeEntry->PreviousSize = PreviousSize;
00356 FreeEntry->SegmentOffset = SegmentOffset;
00357
00358
00359 RtlpInsertFreeBlockHelper(Heap, FreeEntry, Size, FALSE);
00360
00361
00362 PreviousSize = Size;
00363 BlockSize -= Size;
00364
00365
00366 FreeEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeEntry + Size);
00367
00368
00369 if ((PHEAP_ENTRY)FreeEntry >= Segment->LastValidEntry) return;
00370 }
00371
00372
00373 if (!(Flags & HEAP_ENTRY_LAST_ENTRY))
00374 FreeEntry->PreviousSize = PreviousSize;
00375 }
00376
00377 VOID NTAPI
00378 RtlpRemoveFreeBlock(PHEAP Heap,
00379 PHEAP_FREE_ENTRY FreeEntry,
00380 BOOLEAN Dedicated,
00381 BOOLEAN NoFill)
00382 {
00383 SIZE_T Result, RealSize;
00384
00385
00386 if (RemoveEntryList(&FreeEntry->FreeList) &&
00387 (Dedicated || (!Dedicated && FreeEntry->Size < HEAP_FREELISTS)))
00388 {
00389 RtlpClearFreeListsBit(Heap, FreeEntry);
00390 }
00391
00392
00393 if (!NoFill &&
00394 (FreeEntry->Flags & HEAP_ENTRY_FILL_PATTERN))
00395 {
00396 RealSize = (FreeEntry->Size << HEAP_ENTRY_SHIFT) - sizeof(*FreeEntry);
00397
00398
00399 if (FreeEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT &&
00400 RealSize > sizeof(HEAP_FREE_ENTRY_EXTRA))
00401 {
00402 RealSize -= sizeof(HEAP_FREE_ENTRY_EXTRA);
00403 }
00404
00405
00406 Result = RtlCompareMemoryUlong((PCHAR)(FreeEntry + 1),
00407 RealSize,
00408 ARENA_FREE_FILLER);
00409
00410 if (Result != RealSize)
00411 {
00412 DPRINT1("Free heap block %p modified at %p after it was freed\n",
00413 FreeEntry,
00414 (PCHAR)(FreeEntry + 1) + Result);
00415 }
00416 }
00417 }
00418
00419 SIZE_T NTAPI
00420 RtlpGetSizeOfBigBlock(PHEAP_ENTRY HeapEntry)
00421 {
00422 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry;
00423
00424
00425 VirtualEntry = CONTAINING_RECORD(HeapEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
00426
00427
00428 return VirtualEntry->CommitSize - HeapEntry->Size;
00429 }
00430
00431 PHEAP_UCR_DESCRIPTOR NTAPI
00432 RtlpCreateUnCommittedRange(PHEAP_SEGMENT Segment)
00433 {
00434 PLIST_ENTRY Entry;
00435 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
00436 PHEAP_UCR_SEGMENT UcrSegment;
00437 PHEAP Heap = Segment->Heap;
00438 SIZE_T ReserveSize = 16 * PAGE_SIZE;
00439 SIZE_T CommitSize = 1 * PAGE_SIZE;
00440 NTSTATUS Status;
00441
00442 DPRINT("RtlpCreateUnCommittedRange(%p)\n", Segment);
00443
00444
00445 if (IsListEmpty(&Heap->UCRList))
00446 {
00447
00448 UcrSegment = CONTAINING_RECORD(Heap->UCRSegments.Flink, HEAP_UCR_SEGMENT, ListEntry);
00449
00450
00451 if (IsListEmpty(&Heap->UCRSegments) ||
00452 UcrSegment->ReservedSize == UcrSegment->CommittedSize)
00453 {
00454
00455 UcrSegment = NULL;
00456 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
00457 (PVOID *)&UcrSegment,
00458 0,
00459 &ReserveSize,
00460 MEM_RESERVE,
00461 PAGE_READWRITE);
00462
00463 if (!NT_SUCCESS(Status)) return NULL;
00464
00465
00466 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
00467 (PVOID *)&UcrSegment,
00468 0,
00469 &CommitSize,
00470 MEM_COMMIT,
00471 PAGE_READWRITE);
00472
00473 if (!NT_SUCCESS(Status))
00474 {
00475
00476 ZwFreeVirtualMemory(NtCurrentProcess(),
00477 (PVOID *)&UcrSegment,
00478 &ReserveSize,
00479 MEM_RELEASE);
00480 return NULL;
00481 }
00482
00483
00484 UcrSegment->ReservedSize = ReserveSize;
00485 UcrSegment->CommittedSize = CommitSize;
00486
00487
00488 InsertHeadList(&Heap->UCRSegments, &UcrSegment->ListEntry);
00489
00490
00491 UcrDescriptor = (PHEAP_UCR_DESCRIPTOR)(UcrSegment + 1);
00492 }
00493 else
00494 {
00495
00496 UcrDescriptor = (PHEAP_UCR_DESCRIPTOR)((PCHAR)UcrSegment + UcrSegment->CommittedSize);
00497 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
00498 (PVOID *)&UcrDescriptor,
00499 0,
00500 &CommitSize,
00501 MEM_COMMIT,
00502 PAGE_READWRITE);
00503
00504 if (!NT_SUCCESS(Status)) return NULL;
00505
00506
00507 UcrSegment->CommittedSize += CommitSize;
00508 }
00509
00510
00511 while ((PCHAR)(UcrDescriptor + 1) <= (PCHAR)UcrSegment + UcrSegment->CommittedSize)
00512 {
00513 InsertTailList(&Heap->UCRList, &UcrDescriptor->ListEntry);
00514 UcrDescriptor++;
00515 }
00516 }
00517
00518
00519 Entry = RemoveHeadList(&Heap->UCRList);
00520 UcrDescriptor = CONTAINING_RECORD(Entry, HEAP_UCR_DESCRIPTOR, ListEntry);
00521 return UcrDescriptor;
00522 }
00523
00524 VOID NTAPI
00525 RtlpDestroyUnCommittedRange(PHEAP_SEGMENT Segment,
00526 PHEAP_UCR_DESCRIPTOR UcrDescriptor)
00527 {
00528
00529 UcrDescriptor->Address = NULL;
00530 UcrDescriptor->Size = 0;
00531
00532
00533 InsertHeadList(&Segment->Heap->UCRList, &UcrDescriptor->ListEntry);
00534 }
00535
00536 VOID NTAPI
00537 RtlpInsertUnCommittedPages(PHEAP_SEGMENT Segment,
00538 ULONG_PTR Address,
00539 SIZE_T Size)
00540 {
00541 PLIST_ENTRY Current;
00542 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
00543
00544 DPRINT("RtlpInsertUnCommittedPages(%p %08Ix %Ix)\n", Segment, Address, Size);
00545
00546
00547
00548 Current = Segment->UCRSegmentList.Flink;
00549 while (Current != &Segment->UCRSegmentList)
00550 {
00551 UcrDescriptor = CONTAINING_RECORD(Current, HEAP_UCR_DESCRIPTOR, SegmentEntry);
00552
00553 if ((ULONG_PTR)UcrDescriptor->Address > Address)
00554 {
00555
00556 if ((Address + Size) == (ULONG_PTR)UcrDescriptor->Address)
00557 {
00558
00559 UcrDescriptor->Address = (PVOID)Address;
00560 UcrDescriptor->Size += Size;
00561 return;
00562 }
00563
00564
00565 break;
00566 }
00567 else if (((ULONG_PTR)UcrDescriptor->Address + UcrDescriptor->Size) == Address)
00568 {
00569
00570 Address = (ULONG_PTR)UcrDescriptor->Address;
00571 Size += UcrDescriptor->Size;
00572
00573
00574 Current = Current->Flink;
00575
00576
00577 RemoveEntryList(&UcrDescriptor->SegmentEntry);
00578 RtlpDestroyUnCommittedRange(Segment, UcrDescriptor);
00579
00580 Segment->NumberOfUnCommittedRanges--;
00581 }
00582 else
00583 {
00584
00585 Current = Current->Flink;
00586 }
00587 }
00588
00589
00590 UcrDescriptor = RtlpCreateUnCommittedRange(Segment);
00591 if (!UcrDescriptor) return;
00592
00593 UcrDescriptor->Address = (PVOID)Address;
00594 UcrDescriptor->Size = Size;
00595
00596
00597 InsertTailList(Current, &UcrDescriptor->SegmentEntry);
00598
00599 DPRINT("Added segment UCR with base %08Ix, size 0x%x\n", Address, Size);
00600
00601
00602 Segment->NumberOfUnCommittedRanges++;
00603 }
00604
00605 PHEAP_FREE_ENTRY NTAPI
00606 RtlpFindAndCommitPages(PHEAP Heap,
00607 PHEAP_SEGMENT Segment,
00608 PSIZE_T Size,
00609 PVOID AddressRequested)
00610 {
00611 PLIST_ENTRY Current;
00612 ULONG_PTR Address = 0;
00613 PHEAP_UCR_DESCRIPTOR UcrDescriptor, PreviousUcr = NULL;
00614 PHEAP_ENTRY FirstEntry, LastEntry;
00615 NTSTATUS Status;
00616
00617 DPRINT("RtlpFindAndCommitPages(%p %p %Ix %08Ix)\n", Heap, Segment, *Size, Address);
00618
00619
00620 Current = Segment->UCRSegmentList.Flink;
00621 while (Current != &Segment->UCRSegmentList)
00622 {
00623 UcrDescriptor = CONTAINING_RECORD(Current, HEAP_UCR_DESCRIPTOR, SegmentEntry);
00624
00625
00626 if (UcrDescriptor->Size >= *Size &&
00627 (UcrDescriptor->Address == AddressRequested || !AddressRequested))
00628 {
00629
00630 Address = (ULONG_PTR)UcrDescriptor->Address;
00631
00632
00633 if (Heap->CommitRoutine)
00634 {
00635 Status = Heap->CommitRoutine(Heap, (PVOID *)&Address, Size);
00636 }
00637 else
00638 {
00639 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
00640 (PVOID *)&Address,
00641 0,
00642 Size,
00643 MEM_COMMIT,
00644 PAGE_READWRITE);
00645 }
00646
00647 DPRINT("Committed %Iu bytes at base %08Ix, UCR size is %lu\n", *Size, Address, UcrDescriptor->Size);
00648
00649
00650 if (!NT_SUCCESS(Status))
00651 {
00652 DPRINT1("Committing page failed with status 0x%08X\n", Status);
00653 return NULL;
00654 }
00655
00656
00657 Segment->NumberOfUnCommittedPages -= (ULONG)(*Size / PAGE_SIZE);
00658
00659
00660 FirstEntry = (PHEAP_ENTRY)Address;
00661
00662
00663 if (PreviousUcr)
00664 LastEntry = (PHEAP_ENTRY)((ULONG_PTR)PreviousUcr->Address + PreviousUcr->Size);
00665 else
00666 LastEntry = &Segment->Entry;
00667
00668 while (!(LastEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
00669 {
00670 ASSERT(LastEntry->Size != 0);
00671 LastEntry += LastEntry->Size;
00672 }
00673 ASSERT((LastEntry + LastEntry->Size) == FirstEntry);
00674
00675
00676 LastEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
00677
00678
00679 UcrDescriptor->Address = (PVOID)((ULONG_PTR)UcrDescriptor->Address + *Size);
00680 UcrDescriptor->Size -= *Size;
00681
00682 DPRINT("Updating UcrDescriptor %p, new Address %p, size %lu\n",
00683 UcrDescriptor, UcrDescriptor->Address, UcrDescriptor->Size);
00684
00685
00686 FirstEntry->SegmentOffset = LastEntry->SegmentOffset;
00687 FirstEntry->Size = (USHORT)(*Size >> HEAP_ENTRY_SHIFT);
00688 FirstEntry->PreviousSize = LastEntry->Size;
00689
00690
00691 if (UcrDescriptor->Size == 0)
00692 {
00693
00694
00695
00696 if(UcrDescriptor->Address == Segment->LastValidEntry)
00697 {
00698 FirstEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
00699 }
00700 else
00701 {
00702 FirstEntry->Flags = 0;
00703
00704 ASSERT((FirstEntry + FirstEntry->Size)->PreviousSize == 0);
00705 (FirstEntry + FirstEntry->Size)->PreviousSize = FirstEntry->Size;
00706 }
00707
00708
00709 RemoveEntryList(&UcrDescriptor->SegmentEntry);
00710
00711 RtlpDestroyUnCommittedRange(Segment, UcrDescriptor);
00712 Segment->NumberOfUnCommittedRanges--;
00713 }
00714 else
00715 {
00716 FirstEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
00717 }
00718
00719
00720 return (PHEAP_FREE_ENTRY)FirstEntry;
00721 }
00722
00723
00724 PreviousUcr = UcrDescriptor;
00725 Current = Current->Flink;
00726 }
00727
00728 return NULL;
00729 }
00730
00731 VOID NTAPI
00732 RtlpDeCommitFreeBlock(PHEAP Heap,
00733 PHEAP_FREE_ENTRY FreeEntry,
00734 SIZE_T Size)
00735 {
00736 PHEAP_SEGMENT Segment;
00737 PHEAP_ENTRY PrecedingInUseEntry = NULL, NextInUseEntry = NULL;
00738 PHEAP_FREE_ENTRY NextFreeEntry;
00739 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
00740 SIZE_T PrecedingSize, NextSize, DecommitSize;
00741 ULONG_PTR DecommitBase;
00742 NTSTATUS Status;
00743
00744 DPRINT("Decommitting %p %p %x\n", Heap, FreeEntry, Size);
00745
00746
00747 if (Heap->CommitRoutine)
00748 {
00749
00750 RtlpInsertFreeBlock(Heap, FreeEntry, Size);
00751 return;
00752 }
00753
00754
00755 Segment = Heap->Segments[FreeEntry->SegmentOffset];
00756
00757
00758 DecommitBase = ROUND_UP(FreeEntry, PAGE_SIZE);
00759 PrecedingSize = (PHEAP_ENTRY)DecommitBase - (PHEAP_ENTRY)FreeEntry;
00760
00761 if (PrecedingSize == 1)
00762 {
00763
00764 DecommitBase += PAGE_SIZE;
00765 PrecedingSize += PAGE_SIZE >> HEAP_ENTRY_SHIFT;
00766 }
00767 else if (FreeEntry->PreviousSize &&
00768 (DecommitBase == (ULONG_PTR)FreeEntry))
00769 {
00770 PrecedingInUseEntry = (PHEAP_ENTRY)FreeEntry - FreeEntry->PreviousSize;
00771 }
00772
00773
00774 NextFreeEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeEntry + Size);
00775 DecommitSize = ROUND_DOWN(NextFreeEntry, PAGE_SIZE);
00776 NextSize = (PHEAP_ENTRY)NextFreeEntry - (PHEAP_ENTRY)DecommitSize;
00777
00778 if (NextSize == 1)
00779 {
00780
00781 DecommitSize -= PAGE_SIZE;
00782 NextSize += PAGE_SIZE >> HEAP_ENTRY_SHIFT;
00783 }
00784 else if (NextSize == 0 &&
00785 !(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
00786 {
00787 NextInUseEntry = (PHEAP_ENTRY)NextFreeEntry;
00788 }
00789
00790 NextFreeEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)NextFreeEntry - NextSize);
00791
00792
00793 if (DecommitSize > DecommitBase)
00794 {
00795 DecommitSize -= DecommitBase;
00796 }
00797 else
00798 {
00799
00800 RtlpInsertFreeBlock(Heap, FreeEntry, Size);
00801 return;
00802 }
00803
00804
00805 UcrDescriptor = RtlpCreateUnCommittedRange(Segment);
00806 if (!UcrDescriptor)
00807 {
00808 DPRINT1("HEAP: Failed to create UCR descriptor\n");
00809 RtlpInsertFreeBlock(Heap, FreeEntry, PrecedingSize);
00810 return;
00811 }
00812
00813
00814 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
00815 (PVOID *)&DecommitBase,
00816 &DecommitSize,
00817 MEM_DECOMMIT);
00818
00819
00820 RtlpDestroyUnCommittedRange(Segment, UcrDescriptor);
00821
00822 if (!NT_SUCCESS(Status))
00823 {
00824 RtlpInsertFreeBlock(Heap, FreeEntry, Size);
00825 return;
00826 }
00827
00828
00829 RtlpInsertUnCommittedPages(Segment, DecommitBase, DecommitSize);
00830 Segment->NumberOfUnCommittedPages += (ULONG)(DecommitSize / PAGE_SIZE);
00831
00832 if (PrecedingSize)
00833 {
00834
00835 FreeEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
00836 FreeEntry->Size = (USHORT)PrecedingSize;
00837 Heap->TotalFreeSize += PrecedingSize;
00838
00839
00840 RtlpInsertFreeBlockHelper(Heap, FreeEntry, PrecedingSize, FALSE);
00841 }
00842 else if (PrecedingInUseEntry)
00843 {
00844
00845 PrecedingInUseEntry->Flags |= HEAP_ENTRY_LAST_ENTRY;
00846 }
00847
00848
00849 if (NextSize)
00850 {
00851
00852 NextFreeEntry->Flags = 0;
00853 NextFreeEntry->PreviousSize = 0;
00854 NextFreeEntry->SegmentOffset = Segment->Entry.SegmentOffset;
00855 NextFreeEntry->Size = (USHORT)NextSize;
00856
00857 ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)NextFreeEntry + NextSize))->PreviousSize = (USHORT)NextSize;
00858
00859 Heap->TotalFreeSize += NextSize;
00860 RtlpInsertFreeBlockHelper(Heap, NextFreeEntry, NextSize, FALSE);
00861 }
00862 else if (NextInUseEntry)
00863 {
00864 NextInUseEntry->PreviousSize = 0;
00865 }
00866 }
00867
00868 NTSTATUS
00869 NTAPI
00870 RtlpInitializeHeapSegment(IN OUT PHEAP Heap,
00871 OUT PHEAP_SEGMENT Segment,
00872 IN UCHAR SegmentIndex,
00873 IN ULONG SegmentFlags,
00874 IN SIZE_T SegmentReserve,
00875 IN SIZE_T SegmentCommit)
00876 {
00877 PHEAP_ENTRY HeapEntry;
00878
00879
00880 ASSERT(Heap != NULL);
00881 ASSERT(Segment != NULL);
00882 ASSERT(SegmentCommit >= PAGE_SIZE);
00883 ASSERT(ROUND_DOWN(SegmentCommit, PAGE_SIZE) == SegmentCommit);
00884 ASSERT(SegmentReserve >= SegmentCommit);
00885 ASSERT(ROUND_DOWN(SegmentReserve, PAGE_SIZE) == SegmentReserve);
00886
00887 DPRINT("RtlpInitializeHeapSegment(%p %p %x %x %lx %lx)\n", Heap, Segment, SegmentIndex, SegmentFlags, SegmentReserve, SegmentCommit);
00888
00889
00890 if ((PHEAP_SEGMENT) (Heap) != Segment)
00891 {
00892 Segment->Entry.Size = ROUND_UP(sizeof(HEAP_SEGMENT), sizeof(HEAP_ENTRY)) >> HEAP_ENTRY_SHIFT;
00893 Segment->Entry.Flags = HEAP_ENTRY_BUSY;
00894 Segment->Entry.SmallTagIndex = LOBYTE(Segment->Entry.Size) ^ HIBYTE(Segment->Entry.Size) ^ Segment->Entry.Flags;
00895 Segment->Entry.PreviousSize = 0;
00896 Segment->Entry.SegmentOffset = SegmentIndex;
00897 Segment->Entry.UnusedBytes = 0;
00898 }
00899
00900
00901 ASSERT((Segment->Entry.Size << HEAP_ENTRY_SHIFT) <= PAGE_SIZE);
00902
00903
00904 Segment->SegmentSignature = HEAP_SEGMENT_SIGNATURE;
00905 Segment->SegmentFlags = SegmentFlags;
00906 Segment->Heap = Heap;
00907 Heap->Segments[SegmentIndex] = Segment;
00908
00909
00910 Segment->BaseAddress = Segment;
00911 Segment->NumberOfPages = (ULONG)(SegmentReserve >> PAGE_SHIFT);
00912
00913
00914 Segment->FirstEntry = &Segment->Entry + Segment->Entry.Size;
00915 Segment->LastValidEntry = (PHEAP_ENTRY)((ULONG_PTR)Segment + SegmentReserve);
00916
00917 if (((SIZE_T)Segment->Entry.Size << HEAP_ENTRY_SHIFT) < SegmentCommit)
00918 {
00919 HeapEntry = Segment->FirstEntry;
00920
00921
00922 HeapEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
00923 HeapEntry->PreviousSize = Segment->Entry.Size;
00924 HeapEntry->SegmentOffset = SegmentIndex;
00925
00926
00927 RtlpInsertFreeBlock(Heap, (PHEAP_FREE_ENTRY) HeapEntry, (SegmentCommit >> HEAP_ENTRY_SHIFT) - Segment->Entry.Size);
00928 }
00929
00930
00931 Segment->NumberOfUnCommittedPages = (ULONG)((SegmentReserve - SegmentCommit) >> PAGE_SHIFT);
00932 Segment->NumberOfUnCommittedRanges = 0;
00933 InitializeListHead(&Segment->UCRSegmentList);
00934
00935
00936 if (Segment->NumberOfUnCommittedPages != 0)
00937 RtlpInsertUnCommittedPages(Segment, (ULONG_PTR) (Segment) + SegmentCommit, SegmentReserve - SegmentCommit);
00938
00939 return STATUS_SUCCESS;
00940 }
00941
00942 VOID NTAPI
00943 RtlpDestroyHeapSegment(PHEAP_SEGMENT Segment)
00944 {
00945 NTSTATUS Status;
00946 PVOID BaseAddress;
00947 SIZE_T Size = 0;
00948
00949
00950 if (Segment->SegmentFlags & HEAP_USER_ALLOCATED) return;
00951
00952 BaseAddress = Segment->BaseAddress;
00953 DPRINT("Destroying segment %p, BA %p\n", Segment, BaseAddress);
00954
00955
00956 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
00957 &BaseAddress,
00958 &Size,
00959 MEM_RELEASE);
00960
00961 if (!NT_SUCCESS(Status))
00962 {
00963 DPRINT1("HEAP: Failed to release segment's memory with status 0x%08X\n", Status);
00964 }
00965 }
00966
00967 PHEAP_FREE_ENTRY NTAPI
00968 RtlpCoalesceHeap(PHEAP Heap)
00969 {
00970 UNIMPLEMENTED;
00971 return NULL;
00972 }
00973
00974 PHEAP_FREE_ENTRY NTAPI
00975 RtlpCoalesceFreeBlocks (PHEAP Heap,
00976 PHEAP_FREE_ENTRY FreeEntry,
00977 PSIZE_T FreeSize,
00978 BOOLEAN Remove)
00979 {
00980 PHEAP_FREE_ENTRY CurrentEntry, NextEntry;
00981
00982
00983 CurrentEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeEntry - FreeEntry->PreviousSize);
00984
00985
00986 if (CurrentEntry != FreeEntry &&
00987 !(CurrentEntry->Flags & HEAP_ENTRY_BUSY) &&
00988 (*FreeSize + CurrentEntry->Size) <= HEAP_MAX_BLOCK_SIZE)
00989 {
00990 ASSERT(FreeEntry->PreviousSize == CurrentEntry->Size);
00991
00992
00993 if (Remove)
00994 {
00995 RtlpRemoveFreeBlock(Heap, FreeEntry, FALSE, FALSE);
00996 Heap->TotalFreeSize -= FreeEntry->Size;
00997
00998
00999 Remove = FALSE;
01000 }
01001
01002
01003 RtlpRemoveFreeBlock(Heap, CurrentEntry, FALSE, FALSE);
01004
01005
01006 CurrentEntry->Flags = FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY;
01007
01008
01009 FreeEntry = CurrentEntry;
01010 *FreeSize = *FreeSize + CurrentEntry->Size;
01011 Heap->TotalFreeSize -= CurrentEntry->Size;
01012 FreeEntry->Size = (USHORT)(*FreeSize);
01013
01014
01015 if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
01016 {
01017 ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = (USHORT)(*FreeSize);
01018 }
01019 }
01020
01021
01022 if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
01023 {
01024 NextEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeEntry + *FreeSize);
01025
01026 if (!(NextEntry->Flags & HEAP_ENTRY_BUSY) &&
01027 NextEntry->Size + *FreeSize <= HEAP_MAX_BLOCK_SIZE)
01028 {
01029 ASSERT(*FreeSize == NextEntry->PreviousSize);
01030
01031
01032 if (Remove)
01033 {
01034 RtlpRemoveFreeBlock(Heap, FreeEntry, FALSE, FALSE);
01035 Heap->TotalFreeSize -= FreeEntry->Size;
01036 }
01037
01038
01039 FreeEntry->Flags = NextEntry->Flags & HEAP_ENTRY_LAST_ENTRY;
01040
01041
01042 RtlpRemoveFreeBlock(Heap, NextEntry, FALSE, FALSE);
01043
01044
01045 *FreeSize = *FreeSize + NextEntry->Size;
01046 Heap->TotalFreeSize -= NextEntry->Size;
01047 FreeEntry->Size = (USHORT)(*FreeSize);
01048
01049
01050 if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
01051 {
01052 ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = (USHORT)(*FreeSize);
01053 }
01054 }
01055 }
01056 return FreeEntry;
01057 }
01058
01059 PHEAP_FREE_ENTRY NTAPI
01060 RtlpExtendHeap(PHEAP Heap,
01061 SIZE_T Size)
01062 {
01063 ULONG Pages;
01064 UCHAR Index, EmptyIndex;
01065 SIZE_T FreeSize, CommitSize, ReserveSize;
01066 PHEAP_SEGMENT Segment;
01067 PHEAP_FREE_ENTRY FreeEntry;
01068 NTSTATUS Status;
01069
01070 DPRINT("RtlpExtendHeap(%p %x)\n", Heap, Size);
01071
01072
01073 Pages = (ULONG)((Size + PAGE_SIZE - 1) / PAGE_SIZE);
01074 FreeSize = Pages * PAGE_SIZE;
01075 DPRINT("Pages %x, FreeSize %x. Going through segments...\n", Pages, FreeSize);
01076
01077
01078 EmptyIndex = HEAP_SEGMENTS;
01079 for (Index = 0; Index < HEAP_SEGMENTS; Index++)
01080 {
01081 Segment = Heap->Segments[Index];
01082
01083 if (Segment) DPRINT("Segment[%u] %p with NOUCP %x\n", Index, Segment, Segment->NumberOfUnCommittedPages);
01084
01085
01086 if (Segment &&
01087 Pages <= Segment->NumberOfUnCommittedPages)
01088 {
01089 DPRINT("This segment is suitable\n");
01090
01091
01092 FreeEntry = RtlpFindAndCommitPages(Heap, Segment, &FreeSize, NULL);
01093
01094
01095 if (FreeEntry)
01096 {
01097 FreeSize = FreeSize >> HEAP_ENTRY_SHIFT;
01098 FreeEntry = RtlpCoalesceFreeBlocks(Heap, FreeEntry, &FreeSize, FALSE);
01099 RtlpInsertFreeBlock(Heap, FreeEntry, FreeSize);
01100 return FreeEntry;
01101 }
01102 }
01103 else if (!Segment &&
01104 EmptyIndex == HEAP_SEGMENTS)
01105 {
01106
01107 EmptyIndex = Index;
01108 }
01109 }
01110
01111
01112 if ((Heap->Flags & HEAP_GROWABLE) &&
01113 (EmptyIndex != HEAP_SEGMENTS))
01114 {
01115 Segment = NULL;
01116
01117
01118 if ((Size + PAGE_SIZE) <= Heap->SegmentReserve)
01119 ReserveSize = Heap->SegmentReserve;
01120 else
01121 ReserveSize = Size + PAGE_SIZE;
01122
01123 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
01124 (PVOID)&Segment,
01125 0,
01126 &ReserveSize,
01127 MEM_RESERVE,
01128 PAGE_READWRITE);
01129
01130
01131 while (!NT_SUCCESS(Status) &&
01132 ReserveSize != Size + PAGE_SIZE)
01133 {
01134 ReserveSize /= 2;
01135
01136 if (ReserveSize < (Size + PAGE_SIZE))
01137 ReserveSize = Size + PAGE_SIZE;
01138
01139 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
01140 (PVOID)&Segment,
01141 0,
01142 &ReserveSize,
01143 MEM_RESERVE,
01144 PAGE_READWRITE);
01145 }
01146
01147
01148 if (NT_SUCCESS(Status))
01149 {
01150 Heap->SegmentReserve += ReserveSize;
01151
01152
01153 if ((Size + PAGE_SIZE) <= Heap->SegmentCommit)
01154 CommitSize = Heap->SegmentCommit;
01155 else
01156 CommitSize = Size + PAGE_SIZE;
01157
01158 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
01159 (PVOID)&Segment,
01160 0,
01161 &CommitSize,
01162 MEM_COMMIT,
01163 PAGE_READWRITE);
01164
01165 DPRINT("Committed %lu bytes at base %p\n", CommitSize, Segment);
01166
01167
01168 if (NT_SUCCESS(Status))
01169 Status = RtlpInitializeHeapSegment(Heap, Segment, EmptyIndex, 0, ReserveSize, CommitSize);
01170
01171
01172 if (NT_SUCCESS(Status)) return (PHEAP_FREE_ENTRY)Segment->FirstEntry;
01173
01174 DPRINT1("Committing failed with status 0x%08X\n", Status);
01175
01176
01177 ZwFreeVirtualMemory(NtCurrentProcess(),
01178 (PVOID)&Segment,
01179 &ReserveSize,
01180 MEM_RELEASE);
01181 }
01182 else
01183 {
01184 DPRINT1("Reserving failed with status 0x%08X\n", Status);
01185 }
01186 }
01187
01188 if (RtlpGetMode() == UserMode)
01189 {
01190
01191 if (Heap->Flags & HEAP_DISABLE_COALESCE_ON_FREE)
01192 {
01193 FreeEntry = RtlpCoalesceHeap(Heap);
01194
01195
01196 if (FreeEntry &&
01197 FreeEntry->Size >= Size)
01198 {
01199 return FreeEntry;
01200 }
01201 }
01202 }
01203
01204 return NULL;
01205 }
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215 HANDLE NTAPI
01216 RtlCreateHeap(ULONG Flags,
01217 PVOID Addr,
01218 SIZE_T TotalSize,
01219 SIZE_T CommitSize,
01220 PVOID Lock,
01221 PRTL_HEAP_PARAMETERS Parameters)
01222 {
01223 PVOID CommittedAddress = NULL, UncommittedAddress = NULL;
01224 PHEAP Heap = NULL;
01225 RTL_HEAP_PARAMETERS SafeParams = {0};
01226 PPEB Peb;
01227 ULONG_PTR MaximumUserModeAddress;
01228 SYSTEM_BASIC_INFORMATION SystemInformation;
01229 MEMORY_BASIC_INFORMATION MemoryInfo;
01230 ULONG NtGlobalFlags = RtlGetNtGlobalFlags();
01231 ULONG HeapSegmentFlags = 0;
01232 NTSTATUS Status;
01233 ULONG MaxBlockSize;
01234
01235
01236 if (RtlpPageHeapEnabled && !Addr && !Lock)
01237 {
01238 Heap = RtlpPageHeapCreate(Flags, Addr, TotalSize, CommitSize, Lock, Parameters);
01239 if (Heap) return Heap;
01240
01241
01242 if ((ULONG_PTR)Parameters == (ULONG_PTR)-1)
01243 Parameters = NULL;
01244 else
01245 DPRINT1("Enabling page heap failed\n");
01246 }
01247
01248
01249 if (!(Flags & HEAP_SKIP_VALIDATION_CHECKS) && (Flags & ~HEAP_CREATE_VALID_MASK))
01250 {
01251 DPRINT1("Invalid flags 0x%08x, fixing...\n", Flags);
01252 Flags &= HEAP_CREATE_VALID_MASK;
01253 }
01254
01255
01256 if (!Parameters) Parameters = &SafeParams;
01257
01258
01259 if (NtGlobalFlags & FLG_HEAP_DISABLE_COALESCING)
01260 Flags |= HEAP_DISABLE_COALESCE_ON_FREE;
01261
01262 if (NtGlobalFlags & FLG_HEAP_ENABLE_FREE_CHECK)
01263 Flags |= HEAP_FREE_CHECKING_ENABLED;
01264
01265 if (NtGlobalFlags & FLG_HEAP_ENABLE_TAIL_CHECK)
01266 Flags |= HEAP_TAIL_CHECKING_ENABLED;
01267
01268 if (RtlpGetMode() == UserMode)
01269 {
01270
01271 if (NtGlobalFlags & FLG_HEAP_VALIDATE_ALL)
01272 Flags |= HEAP_VALIDATE_ALL_ENABLED;
01273
01274 if (NtGlobalFlags & FLG_HEAP_VALIDATE_PARAMETERS)
01275 Flags |= HEAP_VALIDATE_PARAMETERS_ENABLED;
01276
01277 if (NtGlobalFlags & FLG_USER_STACK_TRACE_DB)
01278 Flags |= HEAP_CAPTURE_STACK_BACKTRACES;
01279
01280
01281 Peb = RtlGetCurrentPeb();
01282
01283
01284 if (!Parameters->SegmentCommit) Parameters->SegmentCommit = Peb->HeapSegmentCommit;
01285 if (!Parameters->SegmentReserve) Parameters->SegmentReserve = Peb->HeapSegmentReserve;
01286 if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = Peb->HeapDeCommitFreeBlockThreshold;
01287 if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = Peb->HeapDeCommitTotalFreeThreshold;
01288 }
01289 else
01290 {
01291
01292 #if 0
01293 if (!Parameters->SegmentCommit) Parameters->SegmentCommit = MmHeapSegmentCommit;
01294 if (!Parameters->SegmentReserve) Parameters->SegmentReserve = MmHeapSegmentReserve;
01295 if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
01296 if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
01297 #endif
01298 }
01299
01300
01301 if (!Parameters->SegmentCommit) Parameters->SegmentCommit = PAGE_SIZE * 2;
01302 if (!Parameters->SegmentReserve) Parameters->SegmentReserve = 1048576;
01303 if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = PAGE_SIZE;
01304 if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = 65536;
01305
01306
01307 Status = ZwQuerySystemInformation(SystemBasicInformation,
01308 &SystemInformation,
01309 sizeof(SystemInformation),
01310 NULL);
01311
01312 if (!NT_SUCCESS(Status))
01313 {
01314 DPRINT1("Getting max usermode address failed with status 0x%08x\n", Status);
01315 return NULL;
01316 }
01317
01318 MaximumUserModeAddress = SystemInformation.MaximumUserModeAddress;
01319
01320
01321 if (!Parameters->MaximumAllocationSize)
01322 Parameters->MaximumAllocationSize = MaximumUserModeAddress - (ULONG_PTR)0x10000 - PAGE_SIZE;
01323
01324 MaxBlockSize = 0x80000 - PAGE_SIZE;
01325
01326 if (!Parameters->VirtualMemoryThreshold ||
01327 Parameters->VirtualMemoryThreshold > MaxBlockSize)
01328 {
01329 Parameters->VirtualMemoryThreshold = MaxBlockSize;
01330 }
01331
01332
01333 if (!CommitSize)
01334 {
01335 CommitSize = PAGE_SIZE;
01336 if (TotalSize)
01337 TotalSize = ROUND_UP(TotalSize, PAGE_SIZE);
01338 else
01339 TotalSize = 64 * PAGE_SIZE;
01340 }
01341 else
01342 {
01343
01344 CommitSize = ROUND_UP(CommitSize, PAGE_SIZE);
01345
01346 if (TotalSize)
01347 TotalSize = ROUND_UP(TotalSize, PAGE_SIZE);
01348 else
01349 TotalSize = ROUND_UP(CommitSize, 16 * PAGE_SIZE);
01350 }
01351
01352
01353 if (RtlpHeapIsSpecial(Flags))
01354 return RtlDebugCreateHeap(Flags, Addr, TotalSize, CommitSize, Lock, Parameters);
01355
01356
01357 if ((Flags & HEAP_NO_SERIALIZE) && (Lock != NULL))
01358 return NULL;
01359
01360
01361 if (Addr)
01362 {
01363 if (Parameters->CommitRoutine)
01364 {
01365
01366 if ((Flags & HEAP_GROWABLE) ||
01367 !Parameters->InitialCommit ||
01368 !Parameters->InitialReserve ||
01369 (Parameters->InitialCommit > Parameters->InitialReserve))
01370 {
01371
01372 return NULL;
01373 }
01374
01375
01376 CommittedAddress = Addr;
01377 UncommittedAddress = (PCHAR)Addr + Parameters->InitialCommit;
01378 TotalSize = Parameters->InitialReserve;
01379
01380
01381 RtlZeroMemory(CommittedAddress, PAGE_SIZE);
01382 }
01383 else
01384 {
01385
01386 Status = ZwQueryVirtualMemory(NtCurrentProcess(),
01387 Addr,
01388 MemoryBasicInformation,
01389 &MemoryInfo,
01390 sizeof(MemoryInfo),
01391 NULL);
01392
01393 if (!NT_SUCCESS(Status))
01394 {
01395 DPRINT1("Querying amount of user supplied memory failed with status 0x%08X\n", Status);
01396 return NULL;
01397 }
01398
01399
01400 if (MemoryInfo.BaseAddress != Addr ||
01401 MemoryInfo.State == MEM_FREE)
01402 {
01403 return NULL;
01404 }
01405
01406
01407 CommittedAddress = Addr;
01408
01409
01410 if (MemoryInfo.State == MEM_COMMIT)
01411 {
01412
01413 RtlZeroMemory(CommittedAddress, PAGE_SIZE);
01414
01415
01416 CommitSize = MemoryInfo.RegionSize;
01417 TotalSize = CommitSize;
01418 UncommittedAddress = (PCHAR)Addr + CommitSize;
01419
01420
01421 Status = ZwQueryVirtualMemory(NtCurrentProcess(),
01422 UncommittedAddress,
01423 MemoryBasicInformation,
01424 &MemoryInfo,
01425 sizeof(MemoryInfo),
01426 NULL);
01427
01428 if (NT_SUCCESS(Status) &&
01429 MemoryInfo.State == MEM_RESERVE)
01430 {
01431
01432 TotalSize += MemoryInfo.RegionSize;
01433 }
01434 }
01435 else
01436 {
01437
01438 CommitSize = PAGE_SIZE;
01439 UncommittedAddress = Addr;
01440 }
01441 }
01442
01443
01444 HeapSegmentFlags = HEAP_USER_ALLOCATED;
01445 Heap = (PHEAP)Addr;
01446 }
01447 else
01448 {
01449
01450 if (Parameters->CommitRoutine) return NULL;
01451
01452
01453 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
01454 (PVOID *)&Heap,
01455 0,
01456 &TotalSize,
01457 MEM_RESERVE,
01458 PAGE_READWRITE);
01459
01460 if (!NT_SUCCESS(Status))
01461 {
01462 DPRINT1("Failed to reserve memory with status 0x%08x\n", Status);
01463 return NULL;
01464 }
01465
01466
01467 CommittedAddress = Heap;
01468 UncommittedAddress = Heap;
01469 }
01470
01471
01472 if (CommittedAddress == UncommittedAddress)
01473 {
01474
01475 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
01476 &CommittedAddress,
01477 0,
01478 &CommitSize,
01479 MEM_COMMIT,
01480 PAGE_READWRITE);
01481
01482 DPRINT("Committed %Iu bytes at base %p\n", CommitSize, CommittedAddress);
01483
01484 if (!NT_SUCCESS(Status))
01485 {
01486 DPRINT1("Failure, Status 0x%08X\n", Status);
01487
01488
01489 if (!Addr) ZwFreeVirtualMemory(NtCurrentProcess(),
01490 (PVOID *)&Heap,
01491 &TotalSize,
01492 MEM_RELEASE);
01493
01494 return NULL;
01495 }
01496
01497
01498 UncommittedAddress = (PCHAR)UncommittedAddress + CommitSize;
01499 }
01500
01501
01502 Status = RtlpInitializeHeap(Heap, Flags, Lock, Parameters);
01503 if (!NT_SUCCESS(Status))
01504 {
01505 DPRINT1("Failed to initialize heap (%x)\n", Status);
01506 return NULL;
01507 }
01508
01509
01510 Status = RtlpInitializeHeapSegment(Heap, (PHEAP_SEGMENT) (Heap), 0, HeapSegmentFlags, TotalSize, CommitSize);
01511 if (!NT_SUCCESS(Status))
01512 {
01513 DPRINT1("Failed to initialize heap segment (%x)\n", Status);
01514 return NULL;
01515 }
01516
01517 DPRINT("Created heap %p, CommitSize %x, ReserveSize %x\n", Heap, CommitSize, TotalSize);
01518
01519
01520 if (RtlpGetMode() == UserMode)
01521 {
01522 RtlpAddHeapToProcessList(Heap);
01523
01524
01525 }
01526
01527 return Heap;
01528 }
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542 HANDLE NTAPI
01543 RtlDestroyHeap(HANDLE HeapPtr)
01544 {
01545 PHEAP Heap = (PHEAP)HeapPtr;
01546 PLIST_ENTRY Current;
01547 PHEAP_UCR_SEGMENT UcrSegment;
01548 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry;
01549 PVOID BaseAddress;
01550 SIZE_T Size;
01551 LONG i;
01552 PHEAP_SEGMENT Segment;
01553
01554 if (!HeapPtr) return NULL;
01555
01556
01557 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) return RtlpPageHeapDestroy(HeapPtr);
01558
01559
01560 if (RtlpHeapIsSpecial(Heap->Flags))
01561 {
01562 if (!RtlDebugDestroyHeap(Heap)) return HeapPtr;
01563 }
01564
01565
01566 if (RtlpGetMode() == UserMode &&
01567 HeapPtr == NtCurrentPeb()->ProcessHeap) return HeapPtr;
01568
01569
01570 Current = Heap->VirtualAllocdBlocks.Flink;
01571 while (Current != &Heap->VirtualAllocdBlocks)
01572 {
01573 VirtualEntry = CONTAINING_RECORD(Current, HEAP_VIRTUAL_ALLOC_ENTRY, Entry);
01574 BaseAddress = (PVOID)VirtualEntry;
01575 Current = Current->Flink;
01576 Size = 0;
01577 ZwFreeVirtualMemory(NtCurrentProcess(),
01578 &BaseAddress,
01579 &Size,
01580 MEM_RELEASE);
01581 }
01582
01583
01584 if (RtlpGetMode() == UserMode)
01585 {
01586
01587 RtlpRemoveHeapFromProcessList(Heap);
01588 }
01589
01590
01591 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
01592 {
01593
01594 if (!(Heap->Flags & HEAP_LOCK_USER_ALLOCATED))
01595 RtlDeleteHeapLock(Heap->LockVariable);
01596
01597
01598 Heap->LockVariable = NULL;
01599 }
01600
01601
01602 Current = Heap->UCRSegments.Flink;
01603 while (Current != &Heap->UCRSegments)
01604 {
01605 UcrSegment = CONTAINING_RECORD(Current, HEAP_UCR_SEGMENT, ListEntry);
01606
01607
01608 Current = Current->Flink;
01609
01610 BaseAddress = (PVOID)UcrSegment;
01611 Size = 0;
01612
01613
01614 ZwFreeVirtualMemory(NtCurrentProcess(),
01615 &BaseAddress,
01616 &Size,
01617 MEM_RELEASE);
01618 }
01619
01620
01621 for (i = HEAP_SEGMENTS - 1; i >= 0; i--)
01622 {
01623 Segment = Heap->Segments[i];
01624 if (Segment) RtlpDestroyHeapSegment(Segment);
01625 }
01626
01627 return NULL;
01628 }
01629
01630 PHEAP_ENTRY NTAPI
01631 RtlpSplitEntry(PHEAP Heap,
01632 ULONG Flags,
01633 PHEAP_FREE_ENTRY FreeBlock,
01634 SIZE_T AllocationSize,
01635 SIZE_T Index,
01636 SIZE_T Size)
01637 {
01638 PHEAP_FREE_ENTRY SplitBlock, SplitBlock2;
01639 UCHAR FreeFlags, EntryFlags = HEAP_ENTRY_BUSY;
01640 PHEAP_ENTRY InUseEntry;
01641 SIZE_T FreeSize;
01642
01643
01644
01645
01646 if ((Flags & HEAP_EXTRA_FLAGS_MASK) ||
01647 Heap->PseudoTagEntries)
01648 {
01649
01650 EntryFlags |= HEAP_ENTRY_EXTRA_PRESENT;
01651
01652
01653 }
01654
01655
01656 EntryFlags |= (Flags & HEAP_SETTABLE_USER_FLAGS) >> 4;
01657
01658
01659 FreeFlags = FreeBlock->Flags;
01660 Heap->TotalFreeSize -= FreeBlock->Size;
01661
01662
01663 InUseEntry = (PHEAP_ENTRY)FreeBlock;
01664 InUseEntry->Flags = EntryFlags;
01665 InUseEntry->SmallTagIndex = 0;
01666
01667
01668 FreeSize = InUseEntry->Size - Index;
01669
01670
01671 InUseEntry->Size = (USHORT)Index;
01672 InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
01673
01674
01675 if (FreeSize != 0)
01676 {
01677
01678
01679 if (FreeSize == 1)
01680 {
01681
01682 InUseEntry->Size++;
01683 InUseEntry->UnusedBytes += sizeof(HEAP_ENTRY);
01684 }
01685 else
01686 {
01687
01688 SplitBlock = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
01689
01690
01691 SplitBlock->Flags = FreeFlags;
01692 SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
01693 SplitBlock->Size = (USHORT)FreeSize;
01694 SplitBlock->PreviousSize = (USHORT)Index;
01695
01696
01697 if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
01698 {
01699
01700 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
01701 Heap->TotalFreeSize += FreeSize;
01702 }
01703 else
01704 {
01705
01706 SplitBlock2 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize);
01707
01708 if (SplitBlock2->Flags & HEAP_ENTRY_BUSY)
01709 {
01710 SplitBlock2->PreviousSize = (USHORT)FreeSize;
01711 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
01712 Heap->TotalFreeSize += FreeSize;
01713 }
01714 else
01715 {
01716
01717 SplitBlock->Flags = SplitBlock2->Flags;
01718
01719
01720 RtlpRemoveFreeBlock(Heap, SplitBlock2, FALSE, FALSE);
01721
01722
01723 FreeSize += SplitBlock2->Size;
01724 Heap->TotalFreeSize -= SplitBlock2->Size;
01725
01726 if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
01727 {
01728
01729 SplitBlock->Size = (USHORT)FreeSize;
01730
01731
01732 if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
01733 {
01734 ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
01735 }
01736
01737
01738 RtlpInsertFreeBlockHelper(Heap, SplitBlock, (USHORT)FreeSize, FALSE);
01739
01740
01741 Heap->TotalFreeSize += FreeSize;
01742 }
01743 else
01744 {
01745
01746 RtlpInsertFreeBlock(Heap, SplitBlock, FreeSize);
01747 }
01748 }
01749 }
01750
01751
01752 FreeFlags = 0;
01753 }
01754 }
01755
01756
01757 if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
01758 InUseEntry->Flags |= HEAP_ENTRY_LAST_ENTRY;
01759
01760 return InUseEntry;
01761 }
01762
01763 PVOID NTAPI
01764 RtlpAllocateNonDedicated(PHEAP Heap,
01765 ULONG Flags,
01766 SIZE_T Size,
01767 SIZE_T AllocationSize,
01768 SIZE_T Index,
01769 BOOLEAN HeapLocked)
01770 {
01771 PLIST_ENTRY FreeListHead, Next;
01772 PHEAP_FREE_ENTRY FreeBlock;
01773 PHEAP_ENTRY InUseEntry;
01774 PHEAP_ENTRY_EXTRA Extra;
01775 EXCEPTION_RECORD ExceptionRecord;
01776
01777
01778 FreeListHead = &Heap->FreeLists[0];
01779
01780
01781 Next = FreeListHead->Blink;
01782 if (FreeListHead != Next)
01783 {
01784 FreeBlock = CONTAINING_RECORD(Next, HEAP_FREE_ENTRY, FreeList);
01785
01786 if (FreeBlock->Size >= Index)
01787 {
01788
01789
01790
01791 Next = FreeListHead->Flink;
01792 while (FreeListHead != Next)
01793 {
01794 FreeBlock = CONTAINING_RECORD(Next, HEAP_FREE_ENTRY, FreeList);
01795
01796 if (FreeBlock->Size >= Index)
01797 {
01798
01799
01800 RemoveEntryList(&FreeBlock->FreeList);
01801
01802
01803 InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
01804
01805
01806 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
01807
01808
01809 if (Flags & HEAP_ZERO_MEMORY)
01810 RtlZeroMemory(InUseEntry + 1, Size);
01811 else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
01812 {
01813
01814 RtlFillMemoryUlong(InUseEntry + 1, Size & ~0x3, ARENA_INUSE_FILLER);
01815 }
01816
01817
01818 if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
01819 {
01820 RtlFillMemory((PCHAR)(InUseEntry + 1) + Size, sizeof(HEAP_ENTRY), HEAP_TAIL_FILL);
01821 InUseEntry->Flags |= HEAP_ENTRY_FILL_PATTERN;
01822 }
01823
01824
01825 if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
01826 {
01827 Extra = RtlpGetExtraStuffPointer(InUseEntry);
01828 RtlZeroMemory(Extra, sizeof(HEAP_ENTRY_EXTRA));
01829
01830
01831 }
01832
01833
01834 return InUseEntry + 1;
01835 }
01836
01837
01838 Next = Next->Flink;
01839 }
01840 }
01841 }
01842
01843
01844 FreeBlock = RtlpExtendHeap(Heap, AllocationSize);
01845
01846
01847 if (FreeBlock)
01848 {
01849 RemoveEntryList(&FreeBlock->FreeList);
01850
01851
01852 InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
01853
01854
01855 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
01856
01857
01858 if (Flags & HEAP_ZERO_MEMORY)
01859 RtlZeroMemory(InUseEntry + 1, Size);
01860 else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
01861 {
01862
01863 RtlFillMemoryUlong(InUseEntry + 1, Size & ~0x3, ARENA_INUSE_FILLER);
01864 }
01865
01866
01867 if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
01868 {
01869 RtlFillMemory((PCHAR)(InUseEntry + 1) + Size, sizeof(HEAP_ENTRY), HEAP_TAIL_FILL);
01870 InUseEntry->Flags |= HEAP_ENTRY_FILL_PATTERN;
01871 }
01872
01873
01874 if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
01875 {
01876 Extra = RtlpGetExtraStuffPointer(InUseEntry);
01877 RtlZeroMemory(Extra, sizeof(HEAP_ENTRY_EXTRA));
01878
01879
01880 }
01881
01882
01883 return InUseEntry + 1;
01884 }
01885
01886
01887 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_NO_MEMORY);
01888
01889
01890 if (Flags & HEAP_GENERATE_EXCEPTIONS)
01891 {
01892 ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
01893 ExceptionRecord.ExceptionRecord = NULL;
01894 ExceptionRecord.NumberParameters = 1;
01895 ExceptionRecord.ExceptionFlags = 0;
01896 ExceptionRecord.ExceptionInformation[0] = AllocationSize;
01897
01898 RtlRaiseException(&ExceptionRecord);
01899 }
01900
01901
01902 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
01903 DPRINT1("HEAP: Allocation failed!\n");
01904 DPRINT1("Flags %x\n", Heap->Flags);
01905 return NULL;
01906 }
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916 PVOID NTAPI
01917 RtlAllocateHeap(IN PVOID HeapPtr,
01918 IN ULONG Flags,
01919 IN SIZE_T Size)
01920 {
01921 PHEAP Heap = (PHEAP)HeapPtr;
01922 PULONG FreeListsInUse;
01923 ULONG FreeListsInUseUlong;
01924 SIZE_T AllocationSize;
01925 SIZE_T Index, InUseIndex, i;
01926 PLIST_ENTRY FreeListHead;
01927 PHEAP_ENTRY InUseEntry;
01928 PHEAP_FREE_ENTRY FreeBlock;
01929 UCHAR FreeFlags, EntryFlags = HEAP_ENTRY_BUSY;
01930 EXCEPTION_RECORD ExceptionRecord;
01931 BOOLEAN HeapLocked = FALSE;
01932 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualBlock = NULL;
01933 PHEAP_ENTRY_EXTRA Extra;
01934 NTSTATUS Status;
01935
01936
01937 Flags |= Heap->ForceFlags;
01938
01939
01940 if (RtlpHeapIsSpecial(Flags))
01941 return RtlDebugAllocateHeap(Heap, Flags, Size);
01942
01943
01944 if (Size >= 0x80000000)
01945 {
01946 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_NO_MEMORY);
01947 DPRINT1("HEAP: Allocation failed!\n");
01948 return NULL;
01949 }
01950
01951 if (Flags & (HEAP_CREATE_ENABLE_TRACING |
01952 HEAP_CREATE_ALIGN_16))
01953 {
01954 DPRINT1("HEAP: RtlAllocateHeap is called with unsupported flags %x, ignoring\n", Flags);
01955 }
01956
01957
01958
01959
01960 if (Size)
01961 AllocationSize = Size;
01962 else
01963 AllocationSize = 1;
01964 AllocationSize = (AllocationSize + Heap->AlignRound) & Heap->AlignMask;
01965
01966
01967
01968
01969 if ((Flags & HEAP_EXTRA_FLAGS_MASK) ||
01970 Heap->PseudoTagEntries)
01971 {
01972
01973 EntryFlags |= HEAP_ENTRY_EXTRA_PRESENT;
01974
01975
01976 AllocationSize += sizeof(HEAP_ENTRY_EXTRA);
01977 }
01978
01979
01980 EntryFlags |= (Flags & HEAP_SETTABLE_USER_FLAGS) >> 4;
01981
01982 Index = AllocationSize >> HEAP_ENTRY_SHIFT;
01983
01984
01985 if (!(Flags & HEAP_NO_SERIALIZE))
01986 {
01987 RtlEnterHeapLock(Heap->LockVariable, TRUE);
01988 HeapLocked = TRUE;
01989 }
01990
01991
01992
01993 if (Index < HEAP_FREELISTS)
01994 {
01995 FreeListHead = &Heap->FreeLists[Index];
01996
01997 if (!IsListEmpty(FreeListHead))
01998 {
01999
02000 FreeBlock = CONTAINING_RECORD(FreeListHead->Blink,
02001 HEAP_FREE_ENTRY,
02002 FreeList);
02003
02004
02005 FreeFlags = FreeBlock->Flags;
02006 RtlpRemoveFreeBlock(Heap, FreeBlock, TRUE, FALSE);
02007
02008
02009 Heap->TotalFreeSize -= Index;
02010
02011
02012 InUseEntry = (PHEAP_ENTRY)FreeBlock;
02013 InUseEntry->Flags = EntryFlags | (FreeFlags & HEAP_ENTRY_LAST_ENTRY);
02014 InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
02015 InUseEntry->SmallTagIndex = 0;
02016 }
02017 else
02018 {
02019
02020 InUseIndex = Index >> 5;
02021 FreeListsInUse = &Heap->u.FreeListsInUseUlong[InUseIndex];
02022
02023
02024 FreeListsInUseUlong = *FreeListsInUse++ & ~((1 << ((ULONG)Index & 0x1f)) - 1);
02025
02026
02027 if (InUseIndex > 3)
02028 return RtlpAllocateNonDedicated(Heap, Flags, Size, AllocationSize, Index, HeapLocked);
02029
02030
02031 for (i = InUseIndex; i < 4; i++)
02032 {
02033 if (FreeListsInUseUlong)
02034 {
02035 FreeListHead = &Heap->FreeLists[i * 32];
02036 break;
02037 }
02038
02039 if (i < 3) FreeListsInUseUlong = *FreeListsInUse++;
02040 }
02041
02042
02043 if (i == 4)
02044 return RtlpAllocateNonDedicated(Heap, Flags, Size, AllocationSize, Index, HeapLocked);
02045
02046
02047 FreeListHead += RtlpFindLeastSetBit(FreeListsInUseUlong);
02048
02049
02050 FreeBlock = CONTAINING_RECORD(FreeListHead->Blink,
02051 HEAP_FREE_ENTRY,
02052 FreeList);
02053 RtlpRemoveFreeBlock(Heap, FreeBlock, TRUE, FALSE);
02054
02055
02056 InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
02057 }
02058
02059
02060 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
02061
02062
02063 if (Flags & HEAP_ZERO_MEMORY)
02064 RtlZeroMemory(InUseEntry + 1, Size);
02065 else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
02066 {
02067
02068 RtlFillMemoryUlong(InUseEntry + 1, Size & ~0x3, ARENA_INUSE_FILLER);
02069 }
02070
02071
02072 if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
02073 {
02074 RtlFillMemory((PCHAR)(InUseEntry + 1) + Size, sizeof(HEAP_ENTRY), HEAP_TAIL_FILL);
02075 InUseEntry->Flags |= HEAP_ENTRY_FILL_PATTERN;
02076 }
02077
02078
02079 if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
02080 {
02081 Extra = RtlpGetExtraStuffPointer(InUseEntry);
02082 RtlZeroMemory(Extra, sizeof(HEAP_ENTRY_EXTRA));
02083
02084
02085 }
02086
02087
02088 return InUseEntry + 1;
02089 }
02090 else if (Index <= Heap->VirtualMemoryThreshold)
02091 {
02092
02093 return RtlpAllocateNonDedicated(Heap, Flags, Size, AllocationSize, Index, HeapLocked);
02094 }
02095 else if (Heap->Flags & HEAP_GROWABLE)
02096 {
02097
02098 AllocationSize += sizeof(HEAP_VIRTUAL_ALLOC_ENTRY) - sizeof(HEAP_ENTRY);
02099
02100 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
02101 (PVOID *)&VirtualBlock,
02102 0,
02103 &AllocationSize,
02104 MEM_COMMIT,
02105 PAGE_READWRITE);
02106
02107 if (!NT_SUCCESS(Status))
02108 {
02109
02110
02111 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
02112 DPRINT1("HEAP: Allocation failed!\n");
02113 return NULL;
02114 }
02115
02116
02117 VirtualBlock->BusyBlock.Size = (USHORT)(AllocationSize - Size);
02118 VirtualBlock->BusyBlock.Flags = EntryFlags | HEAP_ENTRY_VIRTUAL_ALLOC | HEAP_ENTRY_EXTRA_PRESENT;
02119 VirtualBlock->CommitSize = AllocationSize;
02120 VirtualBlock->ReserveSize = AllocationSize;
02121
02122
02123 InsertTailList(&Heap->VirtualAllocdBlocks, &VirtualBlock->Entry);
02124
02125
02126 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
02127
02128
02129 return VirtualBlock + 1;
02130 }
02131
02132
02133 if (Flags & HEAP_GENERATE_EXCEPTIONS)
02134 {
02135 ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
02136 ExceptionRecord.ExceptionRecord = NULL;
02137 ExceptionRecord.NumberParameters = 1;
02138 ExceptionRecord.ExceptionFlags = 0;
02139 ExceptionRecord.ExceptionInformation[0] = AllocationSize;
02140
02141 RtlRaiseException(&ExceptionRecord);
02142 }
02143
02144 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_BUFFER_TOO_SMALL);
02145
02146
02147 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
02148 DPRINT1("HEAP: Allocation failed!\n");
02149 return NULL;
02150 }
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161 BOOLEAN NTAPI RtlFreeHeap(
02162 HANDLE HeapPtr,
02163 ULONG Flags,
02164 PVOID Ptr
02165 )
02166 {
02167 PHEAP Heap;
02168 PHEAP_ENTRY HeapEntry;
02169 USHORT TagIndex = 0;
02170 SIZE_T BlockSize;
02171 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry;
02172 BOOLEAN Locked = FALSE;
02173 NTSTATUS Status;
02174
02175
02176 if (!Ptr) return TRUE;
02177
02178
02179 Heap = (PHEAP)HeapPtr;
02180 Flags |= Heap->ForceFlags;
02181
02182
02183 if (RtlpHeapIsSpecial(Flags))
02184 return RtlDebugFreeHeap(Heap, Flags, Ptr);
02185
02186
02187 if (!(Flags & HEAP_NO_SERIALIZE))
02188 {
02189 RtlEnterHeapLock(Heap->LockVariable, TRUE);
02190 Locked = TRUE;
02191 }
02192
02193
02194 HeapEntry = (PHEAP_ENTRY)Ptr - 1;
02195
02196
02197 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY) ||
02198 (((ULONG_PTR)Ptr & 0x7) != 0) ||
02199 (HeapEntry->SegmentOffset >= HEAP_SEGMENTS))
02200 {
02201
02202 DPRINT1("HEAP: Trying to free an invalid address %p!\n", Ptr);
02203 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER);
02204
02205
02206 if (Locked) RtlLeaveHeapLock(Heap->LockVariable);
02207 return FALSE;
02208 }
02209
02210 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
02211 {
02212
02213 VirtualEntry = CONTAINING_RECORD(HeapEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
02214
02215
02216 RemoveEntryList(&VirtualEntry->Entry);
02217
02218
02219
02220 BlockSize = 0;
02221 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
02222 (PVOID *)&VirtualEntry,
02223 &BlockSize,
02224 MEM_RELEASE);
02225
02226 if (!NT_SUCCESS(Status))
02227 {
02228 DPRINT1("HEAP: Failed releasing memory with Status 0x%08X. Heap %p, ptr %p, base address %p\n",
02229 Status, Heap, Ptr, VirtualEntry);
02230 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(Status);
02231 }
02232 }
02233 else
02234 {
02235
02236 BlockSize = HeapEntry->Size;
02237
02238
02239
02240
02241 if (RtlpGetMode() == KernelMode ||
02242 (RtlpGetMode() == UserMode && !(Heap->Flags & HEAP_DISABLE_COALESCE_ON_FREE)))
02243 {
02244 HeapEntry = (PHEAP_ENTRY)RtlpCoalesceFreeBlocks(Heap,
02245 (PHEAP_FREE_ENTRY)HeapEntry,
02246 &BlockSize,
02247 FALSE);
02248 }
02249
02250
02251 if (BlockSize < Heap->DeCommitFreeBlockThreshold ||
02252 (Heap->TotalFreeSize + BlockSize < Heap->DeCommitTotalFreeThreshold))
02253 {
02254
02255 if (BlockSize > HEAP_MAX_BLOCK_SIZE)
02256 {
02257
02258 RtlpInsertFreeBlock(Heap, (PHEAP_FREE_ENTRY)HeapEntry, BlockSize);
02259 }
02260 else
02261 {
02262
02263 RtlpInsertFreeBlockHelper(Heap, (PHEAP_FREE_ENTRY)HeapEntry, BlockSize, FALSE);
02264
02265
02266 if (!(HeapEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
02267 {
02268 ASSERT((HeapEntry + BlockSize)->PreviousSize == BlockSize);
02269 }
02270
02271
02272 Heap->TotalFreeSize += BlockSize;
02273 }
02274
02275
02276 if (RtlpGetMode() == UserMode &&
02277 TagIndex != 0)
02278 {
02279
02280 UNIMPLEMENTED;
02281 }
02282 }
02283 else
02284 {
02285
02286 RtlpDeCommitFreeBlock(Heap, (PHEAP_FREE_ENTRY)HeapEntry, BlockSize);
02287 }
02288 }
02289
02290
02291 if (Locked) RtlLeaveHeapLock(Heap->LockVariable);
02292
02293 return TRUE;
02294 }
02295
02296 BOOLEAN NTAPI
02297 RtlpGrowBlockInPlace (IN PHEAP Heap,
02298 IN ULONG Flags,
02299 IN PHEAP_ENTRY InUseEntry,
02300 IN SIZE_T Size,
02301 IN SIZE_T Index)
02302 {
02303 UCHAR EntryFlags, RememberFlags;
02304 PHEAP_FREE_ENTRY FreeEntry, UnusedEntry, FollowingEntry;
02305 SIZE_T FreeSize, PrevSize, TailPart, AddedSize = 0;
02306 PHEAP_ENTRY_EXTRA OldExtra, NewExtra;
02307
02308
02309 if (Index > Heap->VirtualMemoryThreshold)
02310 return FALSE;
02311
02312
02313 EntryFlags = InUseEntry->Flags;
02314
02315
02316 FreeEntry = (PHEAP_FREE_ENTRY)(InUseEntry + InUseEntry->Size);
02317
02318 if (EntryFlags & HEAP_ENTRY_LAST_ENTRY)
02319 {
02320
02321 FreeSize = (Index - InUseEntry->Size) << HEAP_ENTRY_SHIFT;
02322 FreeSize = ROUND_UP(FreeSize, PAGE_SIZE);
02323
02324
02325 FreeEntry = RtlpFindAndCommitPages(Heap,
02326 Heap->Segments[InUseEntry->SegmentOffset],
02327 &FreeSize,
02328 FreeEntry);
02329
02330
02331 if (!FreeEntry) return FALSE;
02332
02333
02334 FreeSize = FreeSize >> HEAP_ENTRY_SHIFT;
02335 FreeEntry = RtlpCoalesceFreeBlocks(Heap, FreeEntry, &FreeSize, FALSE);
02336
02337
02338 if (FreeSize + InUseEntry->Size < Index)
02339 {
02340
02341 RtlpInsertFreeBlock(Heap, FreeEntry, FreeSize);
02342 Heap->TotalFreeSize += FreeSize;
02343 return FALSE;
02344 }
02345
02346
02347 RememberFlags = FreeEntry->Flags;
02348
02349
02350 FreeSize += InUseEntry->Size;
02351 }
02352 else
02353 {
02354
02355 if (FreeEntry->Flags & HEAP_ENTRY_BUSY) return FALSE;
02356
02357
02358 FreeSize = InUseEntry->Size + FreeEntry->Size;
02359 if (FreeSize < Index) return FALSE;
02360
02361
02362 RememberFlags = FreeEntry->Flags;
02363
02364
02365 RtlpRemoveFreeBlock(Heap, FreeEntry, FALSE, FALSE);
02366 Heap->TotalFreeSize -= FreeEntry->Size;
02367 }
02368
02369 PrevSize = (InUseEntry->Size << HEAP_ENTRY_SHIFT) - InUseEntry->UnusedBytes;
02370 FreeSize -= Index;
02371
02372
02373 if (FreeSize <= 2)
02374 {
02375 Index += FreeSize;
02376 FreeSize = 0;
02377 }
02378
02379
02380 if (RememberFlags & HEAP_ENTRY_EXTRA_PRESENT)
02381 {
02382
02383 OldExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + InUseEntry->Size - 1);
02384 NewExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + Index - 1);
02385
02386
02387 *NewExtra = *OldExtra;
02388
02389
02390 }
02391
02392
02393 InUseEntry->Size = (USHORT)Index;
02394 InUseEntry->UnusedBytes = (UCHAR)((Index << HEAP_ENTRY_SHIFT) - Size);
02395
02396
02397 if (!FreeSize)
02398 {
02399
02400 InUseEntry->Flags |= RememberFlags & HEAP_ENTRY_LAST_ENTRY;
02401
02402
02403
02404 if (!(RememberFlags & HEAP_ENTRY_LAST_ENTRY))
02405 (InUseEntry + InUseEntry->Size)->PreviousSize = InUseEntry->Size;
02406 }
02407 else
02408 {
02409
02410
02411 UnusedEntry = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
02412 UnusedEntry->PreviousSize = (USHORT)Index;
02413 UnusedEntry->SegmentOffset = InUseEntry->SegmentOffset;
02414
02415
02416 if (RememberFlags & HEAP_ENTRY_LAST_ENTRY)
02417 {
02418
02419 UnusedEntry->Flags = RememberFlags;
02420 UnusedEntry->Size = (USHORT)FreeSize;
02421
02422
02423 RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
02424 Heap->TotalFreeSize += FreeSize;
02425 }
02426 else
02427 {
02428
02429 FollowingEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)UnusedEntry + FreeSize);
02430
02431 if (FollowingEntry->Flags & HEAP_ENTRY_BUSY)
02432 {
02433
02434 UnusedEntry->Flags = RememberFlags & (~HEAP_ENTRY_LAST_ENTRY);
02435 UnusedEntry->Size = (USHORT)FreeSize;
02436
02437
02438 FollowingEntry->PreviousSize = (USHORT)FreeSize;
02439
02440
02441 RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
02442 Heap->TotalFreeSize += FreeSize;
02443 }
02444 else
02445 {
02446
02447 RememberFlags = FollowingEntry->Flags;
02448
02449
02450 RtlpRemoveFreeBlock(Heap, FollowingEntry, FALSE, FALSE);
02451 Heap->TotalFreeSize -= FollowingEntry->Size;
02452
02453
02454 FreeSize += FollowingEntry->Size;
02455 UnusedEntry->Flags = RememberFlags;
02456
02457
02458 if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
02459 {
02460
02461 UnusedEntry->Size = (USHORT)FreeSize;
02462
02463 if (!(RememberFlags & HEAP_ENTRY_LAST_ENTRY))
02464 ((PHEAP_ENTRY)UnusedEntry + FreeSize)->PreviousSize = (USHORT)FreeSize;
02465
02466
02467 RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
02468 Heap->TotalFreeSize += FreeSize;
02469 }
02470 else
02471 {
02472
02473 RtlpInsertFreeBlock(Heap, UnusedEntry, FreeSize);
02474 }
02475 }
02476 }
02477 }
02478
02479
02480 if (Flags & HEAP_ZERO_MEMORY)
02481 {
02482 RtlZeroMemory((PCHAR)(InUseEntry + 1) + PrevSize, Size - PrevSize);
02483 }
02484 else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
02485 {
02486
02487 TailPart = PrevSize & (sizeof(ULONG) - 1);
02488
02489
02490 if (TailPart) TailPart = 4 - TailPart;
02491
02492 if (Size > (PrevSize + TailPart))
02493 AddedSize = (Size - (PrevSize + TailPart)) & ~(sizeof(ULONG) - 1);
02494
02495 if (AddedSize)
02496 {
02497 RtlFillMemoryUlong((PCHAR)(InUseEntry + 1) + PrevSize + TailPart,
02498 AddedSize,
02499 ARENA_INUSE_FILLER);
02500 }
02501 }
02502
02503
02504 if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
02505 {
02506 RtlFillMemory((PCHAR)(InUseEntry + 1) + Size,
02507 HEAP_ENTRY_SIZE,
02508 HEAP_TAIL_FILL);
02509 }
02510
02511
02512 InUseEntry->Flags &= ~HEAP_ENTRY_SETTABLE_FLAGS;
02513 InUseEntry->Flags |= ((Flags & HEAP_SETTABLE_USER_FLAGS) >> 4);
02514
02515
02516 return TRUE;
02517 }
02518
02519 PHEAP_ENTRY_EXTRA NTAPI
02520 RtlpGetExtraStuffPointer(PHEAP_ENTRY HeapEntry)
02521 {
02522 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry;
02523
02524
02525 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
02526 {
02527 VirtualEntry = CONTAINING_RECORD(HeapEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
02528
02529
02530 return &VirtualEntry->ExtraStuff;
02531 }
02532 else
02533 {
02534
02535 return (PHEAP_ENTRY_EXTRA)(HeapEntry + HeapEntry->Size - 1);
02536 }
02537 }
02538
02539
02540
02541
02542
02543
02544
02545
02546
02547
02548
02549
02550
02551
02552
02553
02554 PVOID NTAPI
02555 RtlReAllocateHeap(HANDLE HeapPtr,
02556 ULONG Flags,
02557 PVOID Ptr,
02558 SIZE_T Size)
02559 {
02560 PHEAP Heap = (PHEAP)HeapPtr;
02561 PHEAP_ENTRY InUseEntry, NewInUseEntry;
02562 PHEAP_ENTRY_EXTRA OldExtra, NewExtra;
02563 SIZE_T AllocationSize, FreeSize, DecommitSize;
02564 BOOLEAN HeapLocked = FALSE;
02565 PVOID NewBaseAddress;
02566 PHEAP_FREE_ENTRY SplitBlock, SplitBlock2;
02567 SIZE_T OldSize, Index, OldIndex;
02568 UCHAR FreeFlags;
02569 NTSTATUS Status;
02570 PVOID DecommitBase;
02571 SIZE_T RemainderBytes, ExtraSize;
02572 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
02573 EXCEPTION_RECORD ExceptionRecord;
02574
02575
02576 if (!Ptr)
02577 {
02578 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_SUCCESS);
02579 return NULL;
02580 }
02581
02582
02583 Flags |= Heap->ForceFlags;
02584
02585
02586 if (RtlpHeapIsSpecial(Flags))
02587 return RtlDebugReAllocateHeap(Heap, Flags, Ptr, Size);
02588
02589
02590 if (Size >= 0x80000000)
02591 {
02592 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_NO_MEMORY);
02593 return NULL;
02594 }
02595
02596
02597 if (Size)
02598 AllocationSize = Size;
02599 else
02600 AllocationSize = 1;
02601 AllocationSize = (AllocationSize + Heap->AlignRound) & Heap->AlignMask;
02602
02603
02604 if (((((PHEAP_ENTRY)Ptr)-1)->Flags & HEAP_ENTRY_EXTRA_PRESENT) ||
02605 (Flags & HEAP_EXTRA_FLAGS_MASK) ||
02606 Heap->PseudoTagEntries)
02607 {
02608 AllocationSize += sizeof(HEAP_ENTRY_EXTRA);
02609 }
02610
02611
02612 if (!(Flags & HEAP_NO_SERIALIZE))
02613 {
02614 RtlEnterHeapLock(Heap->LockVariable, TRUE);
02615 HeapLocked = TRUE;
02616 Flags &= ~HEAP_NO_SERIALIZE;
02617 }
02618
02619
02620 InUseEntry = (PHEAP_ENTRY)Ptr - 1;
02621
02622
02623 if (!(InUseEntry->Flags & HEAP_ENTRY_BUSY))
02624 {
02625 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER);
02626
02627
02628 if (HeapLocked)
02629 RtlLeaveHeapLock(Heap->LockVariable);
02630 return Ptr;
02631 }
02632
02633 if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
02634 {
02635
02636 OldSize = RtlpGetSizeOfBigBlock(InUseEntry);
02637
02638
02639 OldIndex = (OldSize + InUseEntry->Size) >> HEAP_ENTRY_SHIFT;
02640
02641
02642 AllocationSize += FIELD_OFFSET(HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
02643 AllocationSize = ROUND_UP(AllocationSize, PAGE_SIZE);
02644 }
02645 else
02646 {
02647
02648 OldIndex = InUseEntry->Size;
02649
02650 OldSize = (OldIndex << HEAP_ENTRY_SHIFT) - InUseEntry->UnusedBytes;
02651 }
02652
02653
02654 Index = AllocationSize >> HEAP_ENTRY_SHIFT;
02655
02656
02657 if (Index <= OldIndex)
02658 {
02659
02660 if (Index + 1 == OldIndex)
02661 {
02662 Index++;
02663 AllocationSize += sizeof(HEAP_ENTRY);
02664 }
02665
02666
02667 if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
02668 {
02669
02670 InUseEntry->Size = (USHORT)((AllocationSize - Size) >> HEAP_ENTRY_SHIFT);
02671 }
02672 else if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
02673 {
02674
02675 OldExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + InUseEntry->Size - 1);
02676 NewExtra = (PHEAP_ENTRY_EXTRA)(InUseEntry + Index - 1);
02677 *NewExtra = *OldExtra;
02678
02679
02680
02681
02682 InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
02683 }
02684 else
02685 {
02686
02687 InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
02688 }
02689
02690
02691 if (Size > OldSize)
02692 {
02693
02694 if (Flags & HEAP_ZERO_MEMORY)
02695 {
02696 RtlZeroMemory((PCHAR)Ptr + OldSize, Size - OldSize);
02697 }
02698 else if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED)
02699 {
02700
02701 RemainderBytes = OldSize & (sizeof(ULONG) - 1);
02702
02703 if (RemainderBytes)
02704 RemainderBytes = 4 - RemainderBytes;
02705
02706 if (Size > (OldSize + RemainderBytes))
02707 {
02708
02709 ExtraSize = (Size - (OldSize + RemainderBytes)) & ~(sizeof(ULONG) - 1);
02710
02711
02712 if (ExtraSize != 0)
02713 {
02714 RtlFillMemoryUlong((PCHAR)(InUseEntry + 1) + OldSize + RemainderBytes,
02715 ExtraSize,
02716 ARENA_INUSE_FILLER);
02717 }
02718 }
02719 }
02720 }
02721
02722
02723 if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
02724 {
02725 RtlFillMemory((PCHAR)(InUseEntry + 1) + Size,
02726 HEAP_ENTRY_SIZE,
02727 HEAP_TAIL_FILL);
02728 }
02729
02730
02731 if (Index != OldIndex)
02732 {
02733
02734 FreeFlags = InUseEntry->Flags & ~HEAP_ENTRY_BUSY;
02735
02736 if (FreeFlags & HEAP_ENTRY_VIRTUAL_ALLOC)
02737 {
02738
02739 VirtualAllocBlock = CONTAINING_RECORD(InUseEntry, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock);
02740
02741
02742
02743 DecommitBase = (PCHAR)VirtualAllocBlock + AllocationSize;
02744 DecommitSize = (OldIndex << HEAP_ENTRY_SHIFT) - AllocationSize;
02745
02746
02747 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
02748 (PVOID *)&DecommitBase,
02749 &DecommitSize,
02750 MEM_RELEASE);
02751
02752 if (!NT_SUCCESS(Status))
02753 {
02754 DPRINT1("HEAP: Unable to release memory (pointer %p, size 0x%x), Status %08x\n", DecommitBase, DecommitSize, Status);
02755 }
02756 else
02757 {
02758
02759 VirtualAllocBlock->CommitSize -= DecommitSize;
02760 }
02761 }
02762 else
02763 {
02764
02765 SplitBlock = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
02766
02767
02768 SplitBlock->Flags = FreeFlags;
02769 SplitBlock->PreviousSize = (USHORT)Index;
02770 SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
02771
02772
02773 FreeSize = InUseEntry->Size - Index;
02774
02775
02776 InUseEntry->Size = (USHORT)Index;
02777 InUseEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
02778
02779
02780 if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
02781 {
02782
02783 SplitBlock->Size = (USHORT)FreeSize;
02784 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
02785
02786
02787 Heap->TotalFreeSize += FreeSize;
02788 }
02789 else
02790 {
02791
02792 SplitBlock2 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize);
02793
02794 if (SplitBlock2->Flags & HEAP_ENTRY_BUSY)
02795 {
02796
02797 SplitBlock->Size = (USHORT)FreeSize;
02798
02799
02800 ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
02801
02802
02803 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
02804
02805
02806 Heap->TotalFreeSize += FreeSize;
02807 }
02808 else
02809 {
02810
02811 SplitBlock->Flags = SplitBlock2->Flags;
02812
02813
02814 RtlpRemoveFreeBlock(Heap, SplitBlock2, FALSE, FALSE);
02815 Heap->TotalFreeSize -= SplitBlock2->Size;
02816
02817
02818 FreeSize += SplitBlock2->Size;
02819
02820 if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
02821 {
02822 SplitBlock->Size = (USHORT)FreeSize;
02823
02824 if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
02825 {
02826
02827 ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
02828 }
02829
02830
02831 RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
02832 Heap->TotalFreeSize += FreeSize;
02833 }
02834 else
02835 {
02836
02837 RtlpInsertFreeBlock(Heap, SplitBlock, FreeSize);
02838 }
02839 }
02840 }
02841 }
02842 }
02843 }
02844 else
02845 {
02846
02847 if ((InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) ||
02848 !RtlpGrowBlockInPlace(Heap, Flags, InUseEntry, Size, Index))
02849 {
02850
02851 if (Flags & HEAP_REALLOC_IN_PLACE_ONLY)
02852 {
02853 DPRINT1("Realloc in place failed, but it was the only option\n");
02854 Ptr = NULL;
02855 }
02856 else
02857 {
02858
02859 Flags &= ~HEAP_TAG_MASK;
02860
02861
02862 if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
02863 {
02864
02865 Flags &= ~HEAP_SETTABLE_USER_FLAGS;
02866
02867 Flags |= HEAP_SETTABLE_USER_VALUE | ((InUseEntry->Flags & HEAP_ENTRY_SETTABLE_FLAGS) << 4);
02868
02869
02870 OldExtra = RtlpGetExtraStuffPointer(InUseEntry);
02871
02872
02873 if (OldExtra->TagIndex &&
02874 !(OldExtra->TagIndex & HEAP_PSEUDO_TAG_FLAG))
02875 {
02876 Flags |= OldExtra->TagIndex << HEAP_TAG_SHIFT;
02877 }
02878 }
02879 else if (InUseEntry->SmallTagIndex)
02880 {
02881
02882 Flags |= InUseEntry->SmallTagIndex << HEAP_TAG_SHIFT;
02883 }
02884
02885
02886 NewBaseAddress = RtlAllocateHeap(HeapPtr,
02887 Flags & ~HEAP_ZERO_MEMORY,
02888 Size);
02889
02890
02891 if (NewBaseAddress)
02892 {
02893
02894 NewInUseEntry = (PHEAP_ENTRY)NewBaseAddress - 1;
02895
02896
02897 if (NewInUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
02898 {
02899 NewExtra = RtlpGetExtraStuffPointer(NewInUseEntry);
02900
02901 if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
02902 {
02903 OldExtra = RtlpGetExtraStuffPointer(InUseEntry);
02904 NewExtra->Settable = OldExtra->Settable;
02905 }
02906 else
02907 {
02908 RtlZeroMemory(NewExtra, sizeof(*NewExtra));
02909 }
02910 }
02911
02912
02913 if (Size < OldSize)
02914 RtlMoveMemory(NewBaseAddress, Ptr, Size);
02915 else
02916 RtlMoveMemory(NewBaseAddress, Ptr, OldSize);
02917
02918
02919 if (Size > OldSize &&
02920 (Flags & HEAP_ZERO_MEMORY))
02921 {
02922 RtlZeroMemory((PCHAR)NewBaseAddress + OldSize, Size - OldSize);
02923 }
02924
02925
02926 RtlFreeHeap(HeapPtr, Flags, Ptr);
02927 }
02928
02929 Ptr = NewBaseAddress;
02930 }
02931 }
02932 }
02933
02934
02935 if (!Ptr && (Flags & HEAP_GENERATE_EXCEPTIONS))
02936 {
02937
02938 ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
02939 ExceptionRecord.ExceptionRecord = NULL;
02940 ExceptionRecord.NumberParameters = 1;
02941 ExceptionRecord.ExceptionFlags = 0;
02942 ExceptionRecord.ExceptionInformation[0] = AllocationSize;
02943
02944 RtlRaiseException(&ExceptionRecord);
02945 }
02946
02947
02948 if (HeapLocked)
02949 RtlLeaveHeapLock(Heap->LockVariable);
02950
02951 return Ptr;
02952 }
02953
02954
02955
02956
02957
02958
02959
02960 ULONG NTAPI
02961 RtlCompactHeap(HANDLE Heap,
02962 ULONG Flags)
02963 {
02964 UNIMPLEMENTED;
02965 return 0;
02966 }
02967
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977
02978
02979
02980
02981
02982 BOOLEAN NTAPI
02983 RtlLockHeap(IN HANDLE HeapPtr)
02984 {
02985 PHEAP Heap = (PHEAP)HeapPtr;
02986
02987
02988
02989
02990 if (Heap->Signature != HEAP_SIGNATURE) return FALSE;
02991
02992
02993 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
02994 {
02995 RtlEnterHeapLock(Heap->LockVariable, TRUE);
02996 }
02997
02998 return TRUE;
02999 }
03000
03001
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012
03013
03014
03015 BOOLEAN NTAPI
03016 RtlUnlockHeap(HANDLE HeapPtr)
03017 {
03018 PHEAP Heap = (PHEAP)HeapPtr;
03019
03020
03021
03022
03023 if (Heap->Signature != HEAP_SIGNATURE) return FALSE;
03024
03025
03026 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
03027 {
03028 RtlLeaveHeapLock(Heap->LockVariable);
03029 }
03030
03031 return TRUE;
03032 }
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042
03043
03044
03045
03046
03047
03048 SIZE_T NTAPI
03049 RtlSizeHeap(
03050 HANDLE HeapPtr,
03051 ULONG Flags,
03052 PVOID Ptr
03053 )
03054 {
03055 PHEAP Heap = (PHEAP)HeapPtr;
03056 PHEAP_ENTRY HeapEntry;
03057 SIZE_T EntrySize;
03058
03059
03060 if (!Heap)
03061 {
03062 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_HANDLE);
03063 return (SIZE_T)-1;
03064 }
03065
03066
03067 Flags |= Heap->ForceFlags;
03068
03069
03070 if (RtlpHeapIsSpecial(Flags))
03071 return RtlDebugSizeHeap(Heap, Flags, Ptr);
03072
03073
03074 HeapEntry = (PHEAP_ENTRY)Ptr - 1;
03075
03076
03077 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
03078 {
03079 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER);
03080 return (SIZE_T)-1;
03081 }
03082
03083
03084 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
03085 {
03086 EntrySize = RtlpGetSizeOfBigBlock(HeapEntry);
03087 }
03088 else
03089 {
03090
03091 EntrySize = (HeapEntry->Size << HEAP_ENTRY_SHIFT) - HeapEntry->UnusedBytes;
03092 }
03093
03094
03095 return EntrySize;
03096 }
03097
03098 BOOLEAN NTAPI
03099 RtlpCheckInUsePattern(PHEAP_ENTRY HeapEntry)
03100 {
03101 SIZE_T Size, Result;
03102 PCHAR TailPart;
03103
03104
03105 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
03106 Size = RtlpGetSizeOfBigBlock(HeapEntry);
03107 else
03108 Size = (HeapEntry->Size << HEAP_ENTRY_SHIFT) - HeapEntry->UnusedBytes;
03109
03110
03111 TailPart = (PCHAR)(HeapEntry + 1) + Size;
03112
03113
03114 Result = RtlCompareMemory(TailPart,
03115 FillPattern,
03116 HEAP_ENTRY_SIZE);
03117
03118 if (Result != HEAP_ENTRY_SIZE)
03119 {
03120 DPRINT1("HEAP: Heap entry (size %x) %p tail is modified at %p\n", Size, HeapEntry, TailPart + Result);
03121 return FALSE;
03122 }
03123
03124
03125 return TRUE;
03126 }
03127
03128 BOOLEAN NTAPI
03129 RtlpValidateHeapHeaders(
03130 PHEAP Heap,
03131 BOOLEAN Recalculate)
03132 {
03133
03134 return TRUE;
03135 }
03136
03137 BOOLEAN NTAPI
03138 RtlpValidateHeapEntry(
03139 PHEAP Heap,
03140 PHEAP_ENTRY HeapEntry)
03141 {
03142 BOOLEAN BigAllocation, EntryFound = FALSE;
03143 PHEAP_SEGMENT Segment;
03144 ULONG SegmentOffset;
03145
03146
03147 if (!HeapEntry) goto invalid_entry;
03148 if ((ULONG_PTR)HeapEntry & (HEAP_ENTRY_SIZE - 1)) goto invalid_entry;
03149 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY)) goto invalid_entry;
03150
03151 BigAllocation = HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC;
03152 Segment = Heap->Segments[HeapEntry->SegmentOffset];
03153
03154 if (BigAllocation &&
03155 (((ULONG_PTR)HeapEntry & (PAGE_SIZE - 1)) != FIELD_OFFSET(HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock)))
03156 goto invalid_entry;
03157
03158 if (!BigAllocation && (HeapEntry->SegmentOffset >= HEAP_SEGMENTS ||
03159 !Segment ||
03160 HeapEntry < Segment->FirstEntry ||
03161 HeapEntry >= Segment->LastValidEntry))
03162 goto invalid_entry;
03163
03164 if ((HeapEntry->Flags & HEAP_ENTRY_FILL_PATTERN) &&
03165 !RtlpCheckInUsePattern(HeapEntry))
03166 goto invalid_entry;
03167
03168
03169 if (HeapEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) return TRUE;
03170
03171
03172 for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
03173 {
03174 Segment = Heap->Segments[SegmentOffset];
03175 if (!Segment) continue;
03176
03177 if ((HeapEntry >= Segment->FirstEntry) &&
03178 (HeapEntry < Segment->LastValidEntry))
03179 {
03180
03181 EntryFound = TRUE;
03182 break;
03183 }
03184 }
03185
03186
03187 return EntryFound;
03188
03189 invalid_entry:
03190 DPRINT1("HEAP: Invalid heap entry %p in heap %p\n", HeapEntry, Heap);
03191 return FALSE;
03192 }
03193
03194 BOOLEAN NTAPI
03195 RtlpValidateHeapSegment(
03196 PHEAP Heap,
03197 PHEAP_SEGMENT Segment,
03198 UCHAR SegmentOffset,
03199 PULONG FreeEntriesCount,
03200 PSIZE_T TotalFreeSize,
03201 PSIZE_T TagEntries,
03202 PSIZE_T PseudoTagEntries)
03203 {
03204 PHEAP_UCR_DESCRIPTOR UcrDescriptor;
03205 PLIST_ENTRY UcrEntry;
03206 SIZE_T ByteSize, Size, Result;
03207 PHEAP_ENTRY CurrentEntry;
03208 ULONG UnCommittedPages;
03209 ULONG UnCommittedRanges;
03210 ULONG PreviousSize;
03211
03212 UnCommittedPages = 0;
03213 UnCommittedRanges = 0;
03214
03215 if (IsListEmpty(&Segment->UCRSegmentList))
03216 {
03217 UcrEntry = NULL;
03218 UcrDescriptor = NULL;
03219 }
03220 else
03221 {
03222 UcrEntry = Segment->UCRSegmentList.Flink;
03223 UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
03224 }
03225
03226 if (Segment->BaseAddress == Heap)
03227 CurrentEntry = &Heap->Entry;
03228 else
03229 CurrentEntry = &Segment->Entry;
03230
03231 while (CurrentEntry < Segment->LastValidEntry)
03232 {
03233 if (UcrDescriptor &&
03234 ((PVOID)CurrentEntry >= UcrDescriptor->Address))
03235 {
03236 DPRINT1("HEAP: Entry %p is not inside uncommited range [%p .. %p)\n",
03237 CurrentEntry, UcrDescriptor->Address,
03238 (PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
03239
03240 return FALSE;
03241 }
03242
03243 PreviousSize = 0;
03244
03245 while (CurrentEntry < Segment->LastValidEntry)
03246 {
03247 if (PreviousSize != CurrentEntry->PreviousSize)
03248 {
03249 DPRINT1("HEAP: Entry %p has incorrect PreviousSize %x instead of %x\n",
03250 CurrentEntry, CurrentEntry->PreviousSize, PreviousSize);
03251
03252 return FALSE;
03253 }
03254
03255 PreviousSize = CurrentEntry->Size;
03256 Size = CurrentEntry->Size << HEAP_ENTRY_SHIFT;
03257
03258 if (CurrentEntry->Flags & HEAP_ENTRY_BUSY)
03259 {
03260 if (TagEntries)
03261 {
03262 UNIMPLEMENTED;
03263 }
03264
03265
03266 if (CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN)
03267 {
03268 if (!RtlpCheckInUsePattern(CurrentEntry))
03269 return FALSE;
03270 }
03271 }
03272 else
03273 {
03274
03275 *FreeEntriesCount = *FreeEntriesCount + 1;
03276 *TotalFreeSize += CurrentEntry->Size;
03277
03278 if ((Heap->Flags & HEAP_FREE_CHECKING_ENABLED) &&
03279 (CurrentEntry->Flags & HEAP_ENTRY_FILL_PATTERN))
03280 {
03281 ByteSize = Size - sizeof(HEAP_FREE_ENTRY);
03282
03283 if ((CurrentEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT) &&
03284 (ByteSize > sizeof(HEAP_FREE_ENTRY_EXTRA)))
03285 {
03286 ByteSize -= sizeof(HEAP_FREE_ENTRY_EXTRA);
03287 }
03288
03289 Result = RtlCompareMemoryUlong((PCHAR)((PHEAP_FREE_ENTRY)CurrentEntry + 1),
03290 ByteSize,
03291 ARENA_FREE_FILLER);
03292
03293 if (Result != ByteSize)
03294 {
03295 DPRINT1("HEAP: Free heap block %p modified at %p after it was freed\n",
03296 CurrentEntry,
03297 (PCHAR)(CurrentEntry + 1) + Result);
03298
03299 return FALSE;
03300 }
03301 }
03302 }
03303
03304 if (CurrentEntry->SegmentOffset != SegmentOffset)
03305 {
03306 DPRINT1("HEAP: Heap entry %p SegmentOffset is incorrect %x (should be %x)\n",
03307 CurrentEntry, SegmentOffset, CurrentEntry->SegmentOffset);
03308 return FALSE;
03309 }
03310
03311
03312 if (CurrentEntry->Flags & HEAP_ENTRY_LAST_ENTRY)
03313 {
03314 CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
03315
03316 if (!UcrDescriptor)
03317 {
03318
03319 if (CurrentEntry != Segment->LastValidEntry)
03320 {
03321 DPRINT1("HEAP: Heap entry %p is not last block in segment (%p)\n",
03322 CurrentEntry, Segment->LastValidEntry);
03323 return FALSE;
03324 }
03325 }
03326 else if (CurrentEntry != UcrDescriptor->Address)
03327 {
03328 DPRINT1("HEAP: Heap entry %p does not match next uncommitted address (%p)\n",
03329 CurrentEntry, UcrDescriptor->Address);
03330
03331 return FALSE;
03332 }
03333 else
03334 {
03335 UnCommittedPages += (ULONG)(UcrDescriptor->Size / PAGE_SIZE);
03336 UnCommittedRanges++;
03337
03338 CurrentEntry = (PHEAP_ENTRY)((PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
03339
03340
03341 UcrEntry = UcrEntry->Flink;
03342 if (UcrEntry == &Segment->UCRSegmentList)
03343 {
03344 UcrEntry = NULL;
03345 UcrDescriptor = NULL;
03346 }
03347 else
03348 {
03349 UcrDescriptor = CONTAINING_RECORD(UcrEntry, HEAP_UCR_DESCRIPTOR, SegmentEntry);
03350 }
03351 }
03352
03353 break;
03354 }
03355
03356
03357 CurrentEntry = (PHEAP_ENTRY)((PCHAR)CurrentEntry + Size);
03358 }
03359 }
03360
03361
03362 if (Segment->NumberOfUnCommittedPages != UnCommittedPages)
03363 {
03364 DPRINT1("HEAP: Segment %p NumberOfUnCommittedPages is invalid (%x != %x)\n",
03365 Segment, Segment->NumberOfUnCommittedPages, UnCommittedPages);
03366
03367 return FALSE;
03368 }
03369
03370 if (Segment->NumberOfUnCommittedRanges != UnCommittedRanges)
03371 {
03372 DPRINT1("HEAP: Segment %p NumberOfUnCommittedRanges is invalid (%x != %x)\n",
03373 Segment, Segment->NumberOfUnCommittedRanges, UnCommittedRanges);
03374
03375 return FALSE;
03376 }
03377
03378 return TRUE;
03379 }
03380
03381 BOOLEAN NTAPI
03382 RtlpValidateHeap(PHEAP Heap,
03383 BOOLEAN ForceValidation)
03384 {
03385 PHEAP_SEGMENT Segment;
03386 BOOLEAN EmptyList;
03387 UCHAR SegmentOffset;
03388 SIZE_T Size, TotalFreeSize;
03389 ULONG PreviousSize;
03390 PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
03391 PLIST_ENTRY ListHead, NextEntry;
03392 PHEAP_FREE_ENTRY FreeEntry;
03393 ULONG FreeBlocksCount, FreeListEntriesCount;
03394
03395
03396 if (!RtlpValidateHeapHeaders(Heap, FALSE))
03397 return FALSE;
03398
03399
03400 if (!ForceValidation && !(Heap->Flags & HEAP_VALIDATE_ALL_ENABLED))
03401 return TRUE;
03402
03403
03404 FreeListEntriesCount = 0;
03405 ListHead = &Heap->FreeLists[0];
03406
03407 for (Size = 0; Size < HEAP_FREELISTS; Size++)
03408 {
03409 if (Size)
03410 {
03411
03412 EmptyList = IsListEmpty(ListHead);
03413
03414 if (Heap->u.FreeListsInUseBytes[Size >> 3] & (1 << (Size & 7)))
03415 {
03416 if (EmptyList)
03417 {
03418 DPRINT1("HEAP: Empty %x-free list marked as non-empty\n", Size);
03419 return FALSE;
03420 }
03421 }
03422 else
03423 {
03424 if (!EmptyList)
03425 {
03426 DPRINT1("HEAP: Non-empty %x-free list marked as empty\n", Size);
03427 return FALSE;
03428 }
03429 }
03430 }
03431
03432
03433 NextEntry = ListHead->Flink;
03434 PreviousSize = 0;
03435
03436 while (ListHead != NextEntry)
03437 {
03438 FreeEntry = CONTAINING_RECORD(NextEntry, HEAP_FREE_ENTRY, FreeList);
03439 NextEntry = NextEntry->Flink;
03440
03441
03442 if (FreeEntry->Flags & HEAP_ENTRY_BUSY)
03443 {
03444 DPRINT1("HEAP: %Ix-dedicated list free element %p is marked in-use\n", Size, FreeEntry);
03445 return FALSE;
03446 }
03447
03448
03449 if ((Size == 0) && (FreeEntry->Size < HEAP_FREELISTS))
03450 {
03451 DPRINT1("HEAP: Non dedicated list free element %p has size %x which would fit a dedicated list\n", FreeEntry, FreeEntry->Size);
03452 return FALSE;
03453 }
03454 else if (Size && (FreeEntry->Size != Size))
03455 {
03456 DPRINT1("HEAP: %Ix-dedicated list free element %p has incorrect size %x\n", Size, FreeEntry, FreeEntry->Size);
03457 return FALSE;
03458 }
03459 else if ((Size == 0) && (FreeEntry->Size < PreviousSize))
03460 {
03461 DPRINT1("HEAP: Non dedicated list free element %p is not put in order\n", FreeEntry);
03462 return FALSE;
03463 }
03464
03465
03466 PreviousSize = FreeEntry->Size;
03467
03468
03469 FreeListEntriesCount++;
03470 }
03471
03472
03473 ListHead++;
03474 }
03475
03476
03477 ListHead = &Heap->VirtualAllocdBlocks;
03478 NextEntry = ListHead->Flink;
03479
03480 while (ListHead != NextEntry)
03481 {
03482 VirtualAllocBlock = CONTAINING_RECORD(NextEntry, HEAP_VIRTUAL_ALLOC_ENTRY, Entry);
03483
03484
03485 if (VirtualAllocBlock->BusyBlock.Flags & HEAP_ENTRY_FILL_PATTERN)
03486 {
03487 if (!RtlpCheckInUsePattern(&VirtualAllocBlock->BusyBlock))
03488 return FALSE;
03489 }
03490
03491 NextEntry = NextEntry->Flink;
03492 }
03493
03494
03495 FreeBlocksCount = 0;
03496 TotalFreeSize = 0;
03497
03498 for (SegmentOffset = 0; SegmentOffset < HEAP_SEGMENTS; SegmentOffset++)
03499 {
03500 Segment = Heap->Segments[SegmentOffset];
03501
03502
03503 if (!Segment) continue;
03504
03505 if (!RtlpValidateHeapSegment(Heap,
03506 Segment,
03507 SegmentOffset,
03508 &FreeBlocksCount,
03509 &TotalFreeSize,
03510 NULL,
03511 NULL))
03512 {
03513 return FALSE;
03514 }
03515 }
03516
03517 if (FreeListEntriesCount != FreeBlocksCount)
03518 {
03519 DPRINT1("HEAP: Free blocks count in arena (%lu) does not match free blocks number in the free lists (%lu)\n", FreeBlocksCount, FreeListEntriesCount);
03520 return FALSE;
03521 }
03522
03523 if (Heap->TotalFreeSize != TotalFreeSize)
03524 {
03525 DPRINT1("HEAP: Total size of free blocks in arena (%Iu) does not equal to the one in heap header (%Iu)\n", TotalFreeSize, Heap->TotalFreeSize);
03526 return FALSE;
03527 }
03528
03529 return TRUE;
03530 }
03531
03532
03533
03534
03535
03536
03537
03538
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549
03550 BOOLEAN NTAPI RtlValidateHeap(
03551 HANDLE HeapPtr,
03552 ULONG Flags,
03553 PVOID Block
03554 )
03555 {
03556 PHEAP Heap = (PHEAP)HeapPtr;
03557 BOOLEAN HeapLocked = FALSE;
03558 BOOLEAN HeapValid;
03559
03560
03561 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
03562 return RtlpDebugPageHeapValidate(HeapPtr, Flags, Block);
03563
03564
03565 if (Heap->Signature != HEAP_SIGNATURE)
03566 {
03567 DPRINT1("HEAP: Signature %lx is invalid for heap %p\n", Heap->Signature, Heap);
03568 return FALSE;
03569 }
03570
03571
03572 Flags = Heap->ForceFlags;
03573
03574
03575 if (!(Flags & HEAP_NO_SERIALIZE))
03576 {
03577 RtlEnterHeapLock(Heap->LockVariable, TRUE);
03578 HeapLocked = TRUE;
03579 }
03580
03581
03582 if (!Block)
03583 HeapValid = RtlpValidateHeap(Heap, TRUE);
03584 else
03585 HeapValid = RtlpValidateHeapEntry(Heap, (PHEAP_ENTRY)Block - 1);
03586
03587
03588 if (HeapLocked)
03589 {
03590 RtlLeaveHeapLock(Heap->LockVariable);
03591 }
03592
03593 return HeapValid;
03594 }
03595
03596
03597
03598
03599 NTSTATUS NTAPI
03600 RtlEnumProcessHeaps(PHEAP_ENUMERATION_ROUTINE HeapEnumerationRoutine,
03601 PVOID lParam)
03602 {
03603 UNIMPLEMENTED;
03604 return STATUS_NOT_IMPLEMENTED;
03605 }
03606
03607
03608
03609
03610
03611 ULONG NTAPI
03612 RtlGetProcessHeaps(ULONG count,
03613 HANDLE *heaps)
03614 {
03615 UNIMPLEMENTED;
03616 return 0;
03617 }
03618
03619
03620
03621
03622
03623 BOOLEAN NTAPI
03624 RtlValidateProcessHeaps(VOID)
03625 {
03626 UNIMPLEMENTED;
03627 return TRUE;
03628 }
03629
03630
03631
03632
03633
03634 BOOLEAN NTAPI
03635 RtlZeroHeap(
03636 IN PVOID HeapHandle,
03637 IN ULONG Flags
03638 )
03639 {
03640 UNIMPLEMENTED;
03641 return FALSE;
03642 }
03643
03644
03645
03646
03647 BOOLEAN
03648 NTAPI
03649 RtlSetUserValueHeap(IN PVOID HeapHandle,
03650 IN ULONG Flags,
03651 IN PVOID BaseAddress,
03652 IN PVOID UserValue)
03653 {
03654 PHEAP Heap = (PHEAP)HeapHandle;
03655 PHEAP_ENTRY HeapEntry;
03656 PHEAP_ENTRY_EXTRA Extra;
03657 BOOLEAN HeapLocked = FALSE, ValueSet = FALSE;
03658
03659
03660 Flags |= Heap->Flags;
03661
03662
03663 if (RtlpHeapIsSpecial(Flags))
03664 return RtlDebugSetUserValueHeap(Heap, Flags, BaseAddress, UserValue);
03665
03666
03667 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
03668 {
03669 RtlEnterHeapLock(Heap->LockVariable, TRUE);
03670 HeapLocked = TRUE;
03671 }
03672
03673
03674 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
03675
03676
03677 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
03678 {
03679 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER);
03680
03681
03682 if (HeapLocked)
03683 RtlLeaveHeapLock(Heap->LockVariable);
03684
03685 return FALSE;
03686 }
03687
03688
03689 if (HeapEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
03690 {
03691
03692 Extra = RtlpGetExtraStuffPointer(HeapEntry);
03693 Extra->Settable = (ULONG_PTR)UserValue;
03694
03695
03696 ValueSet = TRUE;
03697 }
03698
03699
03700 if (HeapLocked)
03701 RtlLeaveHeapLock(Heap->LockVariable);
03702
03703 return ValueSet;
03704 }
03705
03706
03707
03708
03709 BOOLEAN
03710 NTAPI
03711 RtlSetUserFlagsHeap(IN PVOID HeapHandle,
03712 IN ULONG Flags,
03713 IN PVOID BaseAddress,
03714 IN ULONG UserFlagsReset,
03715 IN ULONG UserFlagsSet)
03716 {
03717 PHEAP Heap = (PHEAP)HeapHandle;
03718 PHEAP_ENTRY HeapEntry;
03719 BOOLEAN HeapLocked = FALSE;
03720
03721
03722 Flags |= Heap->Flags;
03723
03724
03725 if (RtlpHeapIsSpecial(Flags))
03726 return RtlDebugSetUserFlagsHeap(Heap, Flags, BaseAddress, UserFlagsReset, UserFlagsSet);
03727
03728
03729 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
03730 {
03731 RtlEnterHeapLock(Heap->LockVariable, TRUE);
03732 HeapLocked = TRUE;
03733 }
03734
03735
03736 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
03737
03738
03739 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
03740 {
03741 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER);
03742
03743
03744 if (HeapLocked)
03745 RtlLeaveHeapLock(Heap->LockVariable);
03746
03747 return FALSE;
03748 }
03749
03750
03751 HeapEntry->Flags &= ~(UserFlagsReset >> 4);
03752 HeapEntry->Flags |= (UserFlagsSet >> 4);
03753
03754
03755 if (HeapLocked)
03756 RtlLeaveHeapLock(Heap->LockVariable);
03757
03758 return TRUE;
03759 }
03760
03761
03762
03763
03764 BOOLEAN
03765 NTAPI
03766 RtlGetUserInfoHeap(IN PVOID HeapHandle,
03767 IN ULONG Flags,
03768 IN PVOID BaseAddress,
03769 OUT PVOID *UserValue,
03770 OUT PULONG UserFlags)
03771 {
03772 PHEAP Heap = (PHEAP)HeapHandle;
03773 PHEAP_ENTRY HeapEntry;
03774 PHEAP_ENTRY_EXTRA Extra;
03775 BOOLEAN HeapLocked = FALSE;
03776
03777
03778 Flags |= Heap->Flags;
03779
03780
03781 if (RtlpHeapIsSpecial(Flags))
03782 return RtlDebugGetUserInfoHeap(Heap, Flags, BaseAddress, UserValue, UserFlags);
03783
03784
03785 if (!(Heap->Flags & HEAP_NO_SERIALIZE))
03786 {
03787 RtlEnterHeapLock(Heap->LockVariable, TRUE);
03788 HeapLocked = TRUE;
03789 }
03790
03791
03792 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
03793
03794
03795 if (!(HeapEntry->Flags & HEAP_ENTRY_BUSY))
03796 {
03797 RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER);
03798
03799
03800 if (HeapLocked)
03801 RtlLeaveHeapLock(Heap->LockVariable);
03802
03803 return FALSE;
03804 }
03805
03806
03807 if (HeapEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
03808 {
03809
03810 Extra = RtlpGetExtraStuffPointer(HeapEntry);
03811
03812
03813 if (UserValue)
03814 *UserValue = (PVOID)Extra->Settable;
03815 }
03816
03817
03818 if (UserFlags)
03819 *UserFlags = (HeapEntry->Flags & HEAP_ENTRY_SETTABLE_FLAGS) << 4;
03820
03821
03822 if (HeapLocked)
03823 RtlLeaveHeapLock(Heap->LockVariable);
03824
03825 return TRUE;
03826 }
03827
03828
03829
03830
03831 NTSTATUS
03832 NTAPI
03833 RtlUsageHeap(IN HANDLE Heap,
03834 IN ULONG Flags,
03835 OUT PRTL_HEAP_USAGE Usage)
03836 {
03837
03838 UNIMPLEMENTED;
03839 return STATUS_NOT_IMPLEMENTED;
03840 }
03841
03842 PWSTR
03843 NTAPI
03844 RtlQueryTagHeap(IN PVOID HeapHandle,
03845 IN ULONG Flags,
03846 IN USHORT TagIndex,
03847 IN BOOLEAN ResetCounters,
03848 OUT PRTL_HEAP_TAG_INFO HeapTagInfo)
03849 {
03850
03851 UNIMPLEMENTED;
03852 return NULL;
03853 }
03854
03855 ULONG
03856 NTAPI
03857 RtlExtendHeap(IN HANDLE Heap,
03858 IN ULONG Flags,
03859 IN PVOID P,
03860 IN SIZE_T Size)
03861 {
03862
03863 UNIMPLEMENTED;
03864 return 0;
03865 }
03866
03867 ULONG
03868 NTAPI
03869 RtlCreateTagHeap(IN HANDLE HeapHandle,
03870 IN ULONG Flags,
03871 IN PWSTR TagName,
03872 IN PWSTR TagSubName)
03873 {
03874
03875 UNIMPLEMENTED;
03876 return 0;
03877 }
03878
03879 NTSTATUS
03880 NTAPI
03881 RtlWalkHeap(IN HANDLE HeapHandle,
03882 IN PVOID HeapEntry)
03883 {
03884 UNIMPLEMENTED;
03885 return STATUS_NOT_IMPLEMENTED;
03886 }
03887
03888 PVOID
03889 NTAPI
03890 RtlProtectHeap(IN PVOID HeapHandle,
03891 IN BOOLEAN ReadOnly)
03892 {
03893 UNIMPLEMENTED;
03894 return NULL;
03895 }
03896
03897 NTSTATUS
03898 NTAPI
03899 RtlSetHeapInformation(IN HANDLE HeapHandle OPTIONAL,
03900 IN HEAP_INFORMATION_CLASS HeapInformationClass,
03901 IN PVOID HeapInformation,
03902 IN SIZE_T HeapInformationLength)
03903 {
03904
03905 if (HeapInformationClass == HeapCompatibilityInformation)
03906 {
03907
03908 if (HeapInformationLength < sizeof(ULONG))
03909 {
03910
03911 return STATUS_BUFFER_TOO_SMALL;
03912 }
03913
03914
03915 if (*(PULONG)HeapInformation != 2)
03916 {
03917 return STATUS_UNSUCCESSFUL;
03918 }
03919
03920 DPRINT1("RtlSetHeapInformation() needs to enable LFH\n");
03921 return STATUS_SUCCESS;
03922 }
03923
03924 return STATUS_SUCCESS;
03925 }
03926
03927 NTSTATUS
03928 NTAPI
03929 RtlQueryHeapInformation(HANDLE HeapHandle,
03930 HEAP_INFORMATION_CLASS HeapInformationClass,
03931 PVOID HeapInformation,
03932 SIZE_T HeapInformationLength,
03933 PSIZE_T ReturnLength OPTIONAL)
03934 {
03935 PHEAP Heap = (PHEAP)HeapHandle;
03936
03937
03938 if (HeapInformationClass == HeapCompatibilityInformation)
03939 {
03940
03941 if (ReturnLength)
03942 *ReturnLength = sizeof(ULONG);
03943
03944
03945 if (HeapInformationLength < sizeof(ULONG))
03946 {
03947
03948 return STATUS_BUFFER_TOO_SMALL;
03949 }
03950
03951
03952 *(PULONG)HeapInformation = Heap->FrontEndHeapType;
03953
03954 return STATUS_SUCCESS;
03955 }
03956
03957 return STATUS_UNSUCCESSFUL;
03958 }
03959
03960 NTSTATUS
03961 NTAPI
03962 RtlMultipleAllocateHeap(IN PVOID HeapHandle,
03963 IN ULONG Flags,
03964 IN SIZE_T Size,
03965 IN ULONG Count,
03966 OUT PVOID *Array)
03967 {
03968 UNIMPLEMENTED;
03969 return 0;
03970 }
03971
03972 NTSTATUS
03973 NTAPI
03974 RtlMultipleFreeHeap(IN PVOID HeapHandle,
03975 IN ULONG Flags,
03976 IN ULONG Count,
03977 OUT PVOID *Array)
03978 {
03979 UNIMPLEMENTED;
03980 return 0;
03981 }
03982
03983