00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include "ntrtlp.h"
00022
#include "heap.h"
00023
#include "heappriv.h"
00024
00025
#ifdef NTHEAP_ENABLED
00026
#include "heapp.h"
00027
#endif // NTHEAP_ENABLED
00028
00029 ULONG
RtlpDisableHeapLookaside = 0;
00030
00031
00032
00033
00034
00035
00036 #define HEAP_SLOW_FLAGS (HEAP_DEBUG_FLAGS | \
00037
HEAP_SETTABLE_USER_FLAGS | \
00038
HEAP_NEED_EXTRA_FLAGS | \
00039
HEAP_CREATE_ALIGN_16 | \
00040
HEAP_FREE_CHECKING_ENABLED | \
00041
HEAP_TAIL_CHECKING_ENABLED)
00042
00043 UCHAR
CheckHeapFillPattern[
CHECK_HEAP_TAIL_SIZE ] = {
00044
CHECK_HEAP_TAIL_FILL,
00045
CHECK_HEAP_TAIL_FILL,
00046
CHECK_HEAP_TAIL_FILL,
00047
CHECK_HEAP_TAIL_FILL,
00048
CHECK_HEAP_TAIL_FILL,
00049
CHECK_HEAP_TAIL_FILL,
00050
CHECK_HEAP_TAIL_FILL,
00051
#ifdef _WIN64
00052
CHECK_HEAP_TAIL_FILL,
00053
CHECK_HEAP_TAIL_FILL,
00054
CHECK_HEAP_TAIL_FILL,
00055
CHECK_HEAP_TAIL_FILL,
00056
CHECK_HEAP_TAIL_FILL,
00057
CHECK_HEAP_TAIL_FILL,
00058
CHECK_HEAP_TAIL_FILL,
00059
CHECK_HEAP_TAIL_FILL,
00060
#endif
00061
CHECK_HEAP_TAIL_FILL
00062 };
00063
00064
00065
00066
00067
00068 #define RtlFindFirstSetRightMember(Set) \
00069
(((Set) & 0xFFFF) ? \
00070
(((Set) & 0xFF) ? \
00071
RtlpBitsClearLow[(Set) & 0xFF] : \
00072
RtlpBitsClearLow[((Set) >> 8) & 0xFF] + 8) : \
00073
((((Set) >> 16) & 0xFF) ? \
00074
RtlpBitsClearLow[ ((Set) >> 16) & 0xFF] + 16 : \
00075
RtlpBitsClearLow[ (Set) >> 24] + 24) \
00076
)
00077
00078
00079
00080
00081
00082
00083
#ifndef NTOS_KERNEL_RUNTIME
00084
00085 PVOID
00086
RtlDebugCreateHeap (
00087 IN ULONG Flags,
00088 IN PVOID HeapBase OPTIONAL,
00089 IN SIZE_T ReserveSize OPTIONAL,
00090 IN SIZE_T CommitSize OPTIONAL,
00091 IN PVOID Lock OPTIONAL,
00092 IN PRTL_HEAP_PARAMETERS Parameters OPTIONAL
00093 );
00094
00095 BOOLEAN
00096
RtlDebugDestroyHeap (
00097 IN PVOID HeapHandle
00098 );
00099
00100 PVOID
00101
RtlDebugAllocateHeap (
00102 IN PVOID HeapHandle,
00103 IN ULONG Flags,
00104 IN SIZE_T Size
00105 );
00106
00107 BOOLEAN
00108
RtlDebugFreeHeap (
00109 IN PVOID HeapHandle,
00110 IN ULONG Flags,
00111 IN PVOID BaseAddress
00112 );
00113
00114 ULONG
00115
RtlDebugSizeHeap (
00116 IN PVOID HeapHandle,
00117 IN ULONG Flags,
00118 IN PVOID BaseAddress
00119 );
00120
00121
NTSTATUS
00122
RtlDebugZeroHeap (
00123 IN PVOID HeapHandle,
00124 IN ULONG Flags
00125 );
00126
00127
#endif // NTOS_KERNEL_RUNTIME
00128
00129
00130
00131
00132
00133
00134
PHEAP_UNCOMMMTTED_RANGE
00135
RtlpCreateUnCommittedRange (
00136 IN
PHEAP_SEGMENT Segment
00137 );
00138
00139
VOID
00140
RtlpDestroyUnCommittedRange (
00141 IN
PHEAP_SEGMENT Segment,
00142 IN
PHEAP_UNCOMMMTTED_RANGE UnCommittedRange
00143 );
00144
00145
VOID
00146
RtlpInsertUnCommittedPages (
00147 IN
PHEAP_SEGMENT Segment,
00148 IN ULONG_PTR Address,
00149 IN SIZE_T Size
00150 );
00151
00152
NTSTATUS
00153
RtlpDestroyHeapSegment (
00154 IN
PHEAP_SEGMENT Segment
00155 );
00156
00157
PHEAP_FREE_ENTRY
00158
RtlpExtendHeap (
00159 IN
PHEAP Heap,
00160 IN SIZE_T AllocationSize
00161 );
00162
00163
#ifdef ALLOC_PRAGMA
00164
00165
#pragma alloc_text(PAGE, RtlCreateHeap)
00166
#pragma alloc_text(PAGE, RtlDestroyHeap)
00167
#pragma alloc_text(PAGE, RtlAllocateHeap)
00168
#pragma alloc_text(PAGE, RtlFreeHeap)
00169
#pragma alloc_text(PAGE, RtlSizeHeap)
00170
#pragma alloc_text(PAGE, RtlZeroHeap)
00171
00172
#pragma alloc_text(PAGE, RtlpCreateUnCommittedRange)
00173
#pragma alloc_text(PAGE, RtlpDestroyUnCommittedRange)
00174
#pragma alloc_text(PAGE, RtlpInsertUnCommittedPages)
00175
#pragma alloc_text(PAGE, RtlpDestroyHeapSegment)
00176
#pragma alloc_text(PAGE, RtlpExtendHeap)
00177
00178
#pragma alloc_text(PAGE, RtlpFindAndCommitPages)
00179
#pragma alloc_text(PAGE, RtlpInitializeHeapSegment)
00180
#pragma alloc_text(PAGE, RtlpCoalesceFreeBlocks)
00181
#pragma alloc_text(PAGE, RtlpDeCommitFreeBlock)
00182
#pragma alloc_text(PAGE, RtlpInsertFreeBlock)
00183
#pragma alloc_text(PAGE, RtlpGetSizeOfBigBlock)
00184
#pragma alloc_text(PAGE, RtlpCheckBusyBlockTail)
00185
00186
#endif // ALLOC_PRAGMA
00187
00188
00189 PVOID
00190
00191 RtlCreateHeap (
00192 IN ULONG Flags,
00193 IN PVOID HeapBase OPTIONAL,
00194 IN SIZE_T ReserveSize OPTIONAL,
00195 IN SIZE_T CommitSize OPTIONAL,
00196 IN PVOID Lock OPTIONAL,
00197 IN PRTL_HEAP_PARAMETERS Parameters OPTIONAL
00198 )
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240 {
00241 ULONG_PTR HighestUserAddress;
00242
NTSTATUS Status;
00243
PHEAP Heap =
NULL;
00244
PHEAP_SEGMENT Segment =
NULL;
00245 PLIST_ENTRY FreeListHead;
00246 ULONG SizeOfHeapHeader;
00247 ULONG SegmentFlags;
00248 PVOID CommittedBase;
00249 PVOID UnCommittedBase;
00250 MEMORY_BASIC_INFORMATION MemoryInformation;
00251 SYSTEM_BASIC_INFORMATION SystemInformation;
00252 ULONG
n;
00253 ULONG InitialCountOfUnusedUnCommittedRanges;
00254 SIZE_T MaximumHeapBlockSize;
00255 PVOID NextHeapHeaderAddress;
00256
PHEAP_UNCOMMMTTED_RANGE UnCommittedRange, *pp;
00257 RTL_HEAP_PARAMETERS TempParameters;
00258 ULONG
NtGlobalFlag =
RtlGetNtGlobalFlags();
00259
00260
#ifndef NTOS_KERNEL_RUNTIME
00261
00262 PPEB Peb;
00263
00264
#else // NTOS_KERNEL_RUNTIME
00265
00266
extern SIZE_T
MmHeapSegmentReserve;
00267
extern SIZE_T
MmHeapSegmentCommit;
00268
extern SIZE_T
MmHeapDeCommitTotalFreeThreshold;
00269
extern SIZE_T
MmHeapDeCommitFreeBlockThreshold;
00270
00271
#endif // NTOS_KERNEL_RUNTIME
00272
00273
RTL_PAGED_CODE();
00274
00275
#ifndef NTOS_KERNEL_RUNTIME
00276
#ifdef NTHEAP_ENABLED
00277
{
00278
if (Flags & NTHEAP_ENABLED_FLAG) {
00279
00280 Heap = RtlCreateNtHeap( Flags,
NULL );
00281
00282
if (Heap !=
NULL) {
00283
00284
return Heap;
00285 }
00286
00287 Flags &= ~NTHEAP_ENABLED_FLAG;
00288 }
00289 }
00290
#endif // NTHEAP_ENABLED
00291
#endif // NTOS_KERNEL_RUNTIME
00292
00293
00294
00295
00296
00297
00298
#ifdef DEBUG_PAGE_HEAP
00299
00300
if (
RtlpDebugPageHeap && ( HeapBase ==
NULL ) && (
Lock ==
NULL )) {
00301
00302 PVOID PageHeap;
00303
00304 PageHeap =
RtlpDebugPageHeapCreate(
00305
00306 Flags,
00307 HeapBase,
00308 ReserveSize,
00309 CommitSize,
00310
Lock,
00311 Parameters );
00312
00313
if (PageHeap !=
NULL) {
00314
return PageHeap;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
if ((SIZE_T)Parameters == (SIZE_T)-1) {
00326
00327 Parameters =
NULL;
00328 }
00329 }
00330
00331 Flags &= ~(
HEAP_PROTECTION_ENABLED |
00332
HEAP_BREAK_WHEN_OUT_OF_VM |
00333
HEAP_NO_ALIGNMENT );
00334
00335
#endif // DEBUG_PAGE_HEAP
00336
00337
00338
00339
00340
00341
00342
00343
if (!(Flags &
HEAP_SKIP_VALIDATION_CHECKS)) {
00344
00345
if (Flags & ~HEAP_CREATE_VALID_MASK) {
00346
00347
HeapDebugPrint((
"Invalid flags (%08x) specified to RtlCreateHeap\n", Flags ));
00348
HeapDebugBreak(
NULL );
00349
00350 Flags &= HEAP_CREATE_VALID_MASK;
00351 }
00352 }
00353
00354
00355
00356
00357
00358
00359 MaximumHeapBlockSize =
HEAP_MAXIMUM_BLOCK_SIZE <<
HEAP_GRANULARITY_SHIFT;
00360
00361
00362
00363
00364
00365
Status = STATUS_SUCCESS;
00366
00367
00368
00369
00370
00371
00372
00373 RtlZeroMemory( &TempParameters,
sizeof( TempParameters ) );
00374
00375
00376
00377
00378
00379
00380
00381
if (ARGUMENT_PRESENT( Parameters )) {
00382
00383
try {
00384
00385
if (Parameters->Length ==
sizeof( *Parameters )) {
00386
00387 RtlMoveMemory( &TempParameters, Parameters,
sizeof( *Parameters ) );
00388 }
00389
00390 } except(
EXCEPTION_EXECUTE_HANDLER ) {
00391
00392
Status = GetExceptionCode();
00393 }
00394
00395
if (!
NT_SUCCESS(
Status )) {
00396
00397
return NULL;
00398 }
00399 }
00400
00401
00402
00403
00404
00405 Parameters = &TempParameters;
00406
00407
00408
00409
00410
00411
00412
00413
if (
NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK) {
00414
00415 Flags |= HEAP_TAIL_CHECKING_ENABLED;
00416 }
00417
00418
if (
NtGlobalFlag & FLG_HEAP_ENABLE_FREE_CHECK) {
00419
00420 Flags |= HEAP_FREE_CHECKING_ENABLED;
00421 }
00422
00423
if (
NtGlobalFlag & FLG_HEAP_DISABLE_COALESCING) {
00424
00425 Flags |= HEAP_DISABLE_COALESCE_ON_FREE;
00426 }
00427
00428
#ifndef NTOS_KERNEL_RUNTIME
00429
00430
00431
00432
00433
00434
00435 Peb = NtCurrentPeb();
00436
00437
if (
NtGlobalFlag & FLG_HEAP_VALIDATE_PARAMETERS) {
00438
00439 Flags |=
HEAP_VALIDATE_PARAMETERS_ENABLED;
00440 }
00441
00442
if (
NtGlobalFlag & FLG_HEAP_VALIDATE_ALL) {
00443
00444 Flags |=
HEAP_VALIDATE_ALL_ENABLED;
00445 }
00446
00447
if (
NtGlobalFlag & FLG_USER_STACK_TRACE_DB) {
00448
00449 Flags |=
HEAP_CAPTURE_STACK_BACKTRACES;
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
if (Parameters->SegmentReserve == 0) {
00459
00460 Parameters->SegmentReserve = Peb->HeapSegmentReserve;
00461 }
00462
00463
if (Parameters->SegmentCommit == 0) {
00464
00465 Parameters->SegmentCommit = Peb->HeapSegmentCommit;
00466 }
00467
00468
if (Parameters->DeCommitFreeBlockThreshold == 0) {
00469
00470 Parameters->DeCommitFreeBlockThreshold = Peb->HeapDeCommitFreeBlockThreshold;
00471 }
00472
00473
if (Parameters->DeCommitTotalFreeThreshold == 0) {
00474
00475 Parameters->DeCommitTotalFreeThreshold = Peb->HeapDeCommitTotalFreeThreshold;
00476 }
00477
#else // NTOS_KERNEL_RUNTIME
00478
00479
00480
00481
00482
00483
00484
if (Parameters->SegmentReserve == 0) {
00485
00486 Parameters->SegmentReserve =
MmHeapSegmentReserve;
00487 }
00488
00489
if (Parameters->SegmentCommit == 0) {
00490
00491 Parameters->SegmentCommit =
MmHeapSegmentCommit;
00492 }
00493
00494
if (Parameters->DeCommitFreeBlockThreshold == 0) {
00495
00496 Parameters->DeCommitFreeBlockThreshold =
MmHeapDeCommitFreeBlockThreshold;
00497 }
00498
00499
if (Parameters->DeCommitTotalFreeThreshold == 0) {
00500
00501 Parameters->DeCommitTotalFreeThreshold =
MmHeapDeCommitTotalFreeThreshold;
00502 }
00503
#endif // NTOS_KERNEL_RUNTIME
00504
00505
00506
00507
00508
00509
if (!
NT_SUCCESS(ZwQuerySystemInformation(SystemBasicInformation,
00510 &SystemInformation,
00511
sizeof(SystemInformation),
00512
NULL))) {
00513
return NULL;
00514 }
00515 HighestUserAddress = SystemInformation.MaximumUserModeAddress;
00516
00517
00518
00519
00520
00521
00522
00523
if (Parameters->MaximumAllocationSize == 0) {
00524
00525 Parameters->MaximumAllocationSize = (HighestUserAddress -
00526 (ULONG_PTR)MM_LOWEST_USER_ADDRESS -
00527
PAGE_SIZE );
00528 }
00529
00530
00531
00532
00533
00534
00535
00536
if ((Parameters->VirtualMemoryThreshold == 0) ||
00537 (Parameters->VirtualMemoryThreshold > MaximumHeapBlockSize)) {
00538
00539 Parameters->VirtualMemoryThreshold = MaximumHeapBlockSize;
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
if (!ARGUMENT_PRESENT( CommitSize )) {
00551
00552 CommitSize =
PAGE_SIZE;
00553
00554
if (!ARGUMENT_PRESENT( ReserveSize )) {
00555
00556 ReserveSize = 64 * CommitSize;
00557
00558 }
else {
00559
00560 ReserveSize =
ROUND_UP_TO_POWER2( ReserveSize,
PAGE_SIZE );
00561 }
00562
00563 }
else {
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 CommitSize =
ROUND_UP_TO_POWER2(CommitSize,
PAGE_SIZE);
00575
00576
if (!ARGUMENT_PRESENT( ReserveSize )) {
00577
00578 ReserveSize =
ROUND_UP_TO_POWER2( CommitSize, 16 *
PAGE_SIZE );
00579
00580 }
else {
00581
00582 ReserveSize =
ROUND_UP_TO_POWER2( ReserveSize,
PAGE_SIZE );
00583 }
00584
00585 }
00586
00587
#ifndef NTOS_KERNEL_RUNTIME
00588
00589
00590
00591
00592
00593
00594
if (
DEBUG_HEAP( Flags )) {
00595
00596
return RtlDebugCreateHeap( Flags,
00597 HeapBase,
00598 ReserveSize,
00599 CommitSize,
00600
Lock,
00601 Parameters );
00602 }
00603
00604
#endif // NTOS_KERNEL_RUNTIME
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614 SizeOfHeapHeader =
sizeof(
HEAP );
00615
00616
if (!(Flags & HEAP_NO_SERIALIZE)) {
00617
00618
if (ARGUMENT_PRESENT(
Lock )) {
00619
00620 Flags |=
HEAP_LOCK_USER_ALLOCATED;
00621
00622 }
else {
00623
00624 SizeOfHeapHeader +=
sizeof(
HEAP_LOCK );
00625
Lock = (
PHEAP_LOCK)-1;
00626 }
00627
00628 }
else if (ARGUMENT_PRESENT(
Lock )) {
00629
00630
00631
00632
00633
00634
00635
return NULL;
00636 }
00637
00638
00639
00640
00641
00642
if (ARGUMENT_PRESENT( HeapBase )) {
00643
00644
00645
00646
00647
00648
00649
if (Parameters->CommitRoutine !=
NULL) {
00650
00651
00652
00653
00654
00655
00656
00657
if ((Parameters->InitialCommit == 0) ||
00658 (Parameters->InitialReserve == 0) ||
00659 (Parameters->InitialCommit > Parameters->InitialReserve) ||
00660 (Flags & HEAP_GROWABLE)) {
00661
00662
return NULL;
00663 }
00664
00665
00666
00667
00668
00669
00670 CommittedBase = HeapBase;
00671 UnCommittedBase = (PCHAR)CommittedBase + Parameters->InitialCommit;
00672 ReserveSize = Parameters->InitialReserve;
00673
00674
00675
00676
00677
00678
00679
00680 RtlZeroMemory( CommittedBase,
PAGE_SIZE );
00681
00682 }
else {
00683
00684
00685
00686
00687
00688
00689
Status = ZwQueryVirtualMemory( NtCurrentProcess(),
00690 HeapBase,
00691 MemoryBasicInformation,
00692 &MemoryInformation,
00693
sizeof( MemoryInformation ),
00694
NULL );
00695
00696
if (!
NT_SUCCESS(
Status )) {
00697
00698
return NULL;
00699 }
00700
00701
00702
00703
00704
00705
00706
if (MemoryInformation.BaseAddress != HeapBase) {
00707
00708
return NULL;
00709 }
00710
00711
if (MemoryInformation.State == MEM_FREE) {
00712
00713
return NULL;
00714 }
00715
00716
00717
00718
00719
00720 CommittedBase = MemoryInformation.BaseAddress;
00721
00722
00723
00724
00725
00726
00727
if (MemoryInformation.State == MEM_COMMIT) {
00728
00729 RtlZeroMemory( CommittedBase,
PAGE_SIZE );
00730
00731
00732
00733
00734
00735
00736 CommitSize = MemoryInformation.RegionSize;
00737 UnCommittedBase = (PCHAR)CommittedBase + CommitSize;
00738
00739
00740
00741
00742
00743
00744
Status = ZwQueryVirtualMemory( NtCurrentProcess(),
00745 UnCommittedBase,
00746 MemoryBasicInformation,
00747 &MemoryInformation,
00748
sizeof( MemoryInformation ),
00749
NULL );
00750
00751 ReserveSize = CommitSize;
00752
00753
if ((
NT_SUCCESS(
Status )) &&
00754 (MemoryInformation.State == MEM_RESERVE)) {
00755
00756 ReserveSize += MemoryInformation.RegionSize;
00757 }
00758
00759 }
else {
00760
00761
00762
00763
00764
00765
00766 CommitSize =
PAGE_SIZE;
00767 UnCommittedBase = CommittedBase;
00768 }
00769 }
00770
00771
00772
00773
00774
00775
00776
00777 SegmentFlags =
HEAP_SEGMENT_USER_ALLOCATED;
00778 Heap = (
PHEAP)HeapBase;
00779
00780 }
else {
00781
00782
00783
00784
00785
00786
00787
if (Parameters->CommitRoutine !=
NULL) {
00788
00789
return NULL;
00790 }
00791
00792
00793
00794
00795
00796
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
00797 (PVOID *)&Heap,
00798 0,
00799 &ReserveSize,
00800 MEM_RESERVE,
00801 PAGE_READWRITE );
00802
00803
if (!
NT_SUCCESS(
Status )) {
00804
00805
return NULL;
00806 }
00807
00808
00809
00810
00811
00812 SegmentFlags = 0;
00813
00814
00815
00816
00817
00818
if (!ARGUMENT_PRESENT( CommitSize )) {
00819
00820 CommitSize =
PAGE_SIZE;
00821 }
00822
00823
00824
00825
00826
00827
00828 CommittedBase = Heap;
00829 UnCommittedBase = Heap;
00830 }
00831
00832
00833
00834
00835
00836
00837
00838
00839
if (CommittedBase == UnCommittedBase) {
00840
00841
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
00842 (PVOID *)&CommittedBase,
00843 0,
00844 &CommitSize,
00845 MEM_COMMIT,
00846 PAGE_READWRITE );
00847
00848
00849
00850
00851
00852
00853
if (!
NT_SUCCESS(
Status )) {
00854
00855
if (!ARGUMENT_PRESENT(HeapBase)) {
00856
00857
00858
00859
00860
00861 ZwFreeVirtualMemory( NtCurrentProcess(),
00862 (PVOID *)&Heap,
00863 &ReserveSize,
00864 MEM_RELEASE );
00865
00866 }
00867
00868
return NULL;
00869 }
00870
00871
00872
00873
00874
00875
00876 UnCommittedBase = (PVOID)((PCHAR)UnCommittedBase + CommitSize);
00877 }
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890 NextHeapHeaderAddress = Heap + 1;
00891
00892 UnCommittedRange = (
PHEAP_UNCOMMMTTED_RANGE)
ROUND_UP_TO_POWER2( NextHeapHeaderAddress,
00893
sizeof( QUAD ) );
00894
00895 InitialCountOfUnusedUnCommittedRanges = 8;
00896
00897 SizeOfHeapHeader += InitialCountOfUnusedUnCommittedRanges *
sizeof( *UnCommittedRange );
00898
00899
00900
00901
00902
00903
00904 pp = &Heap->UnusedUnCommittedRanges;
00905
00906
while (InitialCountOfUnusedUnCommittedRanges--) {
00907
00908 *pp = UnCommittedRange;
00909 pp = &UnCommittedRange->
Next;
00910 UnCommittedRange += 1;
00911 }
00912
00913 NextHeapHeaderAddress = UnCommittedRange;
00914
00915 *pp =
NULL;
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
if (
IS_HEAP_TAGGING_ENABLED()) {
00927
00928 Heap->PseudoTagEntries = (
PHEAP_PSEUDO_TAG_ENTRY)
ROUND_UP_TO_POWER2( NextHeapHeaderAddress,
00929
sizeof( QUAD ) );
00930
00931 SizeOfHeapHeader +=
HEAP_NUMBER_OF_PSEUDO_TAG *
sizeof(
HEAP_PSEUDO_TAG_ENTRY );
00932
00933
00934
00935
00936
00937
00938 NextHeapHeaderAddress = Heap->PseudoTagEntries +
HEAP_NUMBER_OF_PSEUDO_TAG;
00939 }
00940
00941
00942
00943
00944
00945 SizeOfHeapHeader = (ULONG)
ROUND_UP_TO_POWER2( SizeOfHeapHeader,
00946
HEAP_GRANULARITY );
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963 Heap->Entry.Size = (
USHORT)(SizeOfHeapHeader >>
HEAP_GRANULARITY_SHIFT);
00964 Heap->Entry.Flags =
HEAP_ENTRY_BUSY;
00965
00966 Heap->Signature =
HEAP_SIGNATURE;
00967 Heap->Flags = Flags;
00968 Heap->ForceFlags = (Flags & (HEAP_NO_SERIALIZE |
00969 HEAP_GENERATE_EXCEPTIONS |
00970 HEAP_ZERO_MEMORY |
00971 HEAP_REALLOC_IN_PLACE_ONLY |
00972
HEAP_VALIDATE_PARAMETERS_ENABLED |
00973
HEAP_VALIDATE_ALL_ENABLED |
00974 HEAP_TAIL_CHECKING_ENABLED |
00975 HEAP_CREATE_ALIGN_16 |
00976 HEAP_FREE_CHECKING_ENABLED));
00977
00978 Heap->FreeListsInUseTerminate = 0xFFFF;
00979 Heap->HeaderValidateLength = (
USHORT)((PCHAR)NextHeapHeaderAddress - (PCHAR)Heap);
00980 Heap->HeaderValidateCopy =
NULL;
00981
00982
00983
00984
00985
00986 FreeListHead = &Heap->FreeLists[ 0 ];
00987
n =
HEAP_MAXIMUM_FREELISTS;
00988
00989
while (
n--) {
00990
00991 InitializeListHead( FreeListHead );
00992 FreeListHead++;
00993 }
00994
00995
00996
00997
00998
00999 InitializeListHead( &Heap->VirtualAllocdBlocks );
01000
01001
01002
01003
01004
01005
01006
01007
01008
if (
Lock == (
PHEAP_LOCK)-1) {
01009
01010
Lock = (
PHEAP_LOCK)NextHeapHeaderAddress;
01011
01012
Status =
RtlInitializeLockRoutine(
Lock );
01013
01014
if (!
NT_SUCCESS(
Status )) {
01015
01016
return NULL;
01017 }
01018
01019 NextHeapHeaderAddress = (
PHEAP_LOCK)
Lock + 1;
01020 }
01021
01022 Heap->LockVariable =
Lock;
01023
01024
01025
01026
01027
01028
01029
if (!
RtlpInitializeHeapSegment( Heap,
01030 (
PHEAP_SEGMENT)((PCHAR)Heap + SizeOfHeapHeader),
01031 0,
01032 SegmentFlags,
01033 CommittedBase,
01034 UnCommittedBase,
01035 (PCHAR)CommittedBase + ReserveSize )) {
01036
01037
return NULL;
01038 }
01039
01040
01041
01042
01043
01044 Heap->ProcessHeapsListIndex = 0;
01045 Heap->SegmentReserve = Parameters->SegmentReserve;
01046 Heap->SegmentCommit = Parameters->SegmentCommit;
01047 Heap->DeCommitFreeBlockThreshold = Parameters->DeCommitFreeBlockThreshold >>
HEAP_GRANULARITY_SHIFT;
01048 Heap->DeCommitTotalFreeThreshold = Parameters->DeCommitTotalFreeThreshold >>
HEAP_GRANULARITY_SHIFT;
01049 Heap->MaximumAllocationSize = Parameters->MaximumAllocationSize;
01050
01051 Heap->VirtualMemoryThreshold = (ULONG) (
ROUND_UP_TO_POWER2( Parameters->VirtualMemoryThreshold,
01052
HEAP_GRANULARITY ) >>
HEAP_GRANULARITY_SHIFT);
01053
01054 Heap->CommitRoutine = Parameters->CommitRoutine;
01055
01056
01057
01058
01059
01060
01061
01062
01063
if (Flags & HEAP_CREATE_ALIGN_16) {
01064
01065 Heap->AlignRound = 15 +
sizeof(
HEAP_ENTRY );
01066 Heap->AlignMask = (ULONG)~15;
01067
01068 }
else {
01069
01070 Heap->AlignRound =
HEAP_GRANULARITY - 1 +
sizeof(
HEAP_ENTRY );
01071 Heap->AlignMask = (ULONG)~(
HEAP_GRANULARITY - 1);
01072 }
01073
01074
if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED) {
01075
01076 Heap->AlignRound +=
CHECK_HEAP_TAIL_SIZE;
01077 }
01078
01079
#ifndef NTOS_KERNEL_RUNTIME
01080
01081
01082
01083
01084
01085
01086
RtlpAddHeapToProcessList( Heap );
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099 Heap->Lookaside =
NULL;
01100 Heap->LookasideLockCount = 0;
01101
01102
if ((!(Flags & HEAP_NO_SERIALIZE)) &&
01103 ( (Flags & HEAP_GROWABLE)) &&
01104 (!(
RtlpDisableHeapLookaside))) {
01105
01106 ULONG i;
01107
01108 Heap->Lookaside =
RtlAllocateHeap( Heap,
01109 Flags,
01110
sizeof(
HEAP_LOOKASIDE) *
HEAP_MAXIMUM_FREELISTS );
01111
01112
if (Heap->Lookaside !=
NULL) {
01113
01114
for (i = 0; i <
HEAP_MAXIMUM_FREELISTS; i += 1) {
01115
01116
RtlpInitializeHeapLookaside( &(((
PHEAP_LOOKASIDE)(Heap->Lookaside))[i]),
01117 32 );
01118 }
01119 }
01120 }
01121
01122
#endif // NTOS_KERNEL_RUNTIME
01123
01124
01125
01126
01127
01128
return (PVOID)Heap;
01129 }
01130
01131
01132 PVOID
01133 RtlDestroyHeap (
01134 IN PVOID HeapHandle
01135 )
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156 {
01157
PHEAP Heap = (
PHEAP)
HeapHandle;
01158
PHEAP_SEGMENT Segment;
01159
PHEAP_UCR_SEGMENT UCRSegments;
01160 PLIST_ENTRY Head, Next;
01161 PVOID BaseAddress;
01162 SIZE_T RegionSize;
01163 UCHAR SegmentIndex;
01164
01165
01166
01167
01168
01169
RTL_PAGED_CODE();
01170
01171
if (
HeapHandle ==
NULL) {
01172
01173
HeapDebugPrint((
"Ignoring RtlDestroyHeap( NULL )\n" ));
01174
01175
return NULL;
01176 }
01177
01178
#ifndef NTOS_KERNEL_RUNTIME
01179
#ifdef NTHEAP_ENABLED
01180
{
01181
if (Heap->
Flags & NTHEAP_ENABLED_FLAG) {
01182
01183
return RtlDestroyNtHeap(
HeapHandle );
01184 }
01185 }
01186
#endif // NTHEAP_ENABLED
01187
#endif // NTOS_KERNEL_RUNTIME
01188
01189
01190
01191
01192
01193
01194
IF_DEBUG_PAGE_HEAP_THEN_RETURN(
HeapHandle,
01195
RtlpDebugPageHeapDestroy(
HeapHandle ));
01196
01197
#ifndef NTOS_KERNEL_RUNTIME
01198
01199
01200
01201
01202
01203
01204
if (
DEBUG_HEAP( Heap->
Flags )) {
01205
01206
if (!
RtlDebugDestroyHeap(
HeapHandle )) {
01207
01208
return HeapHandle;
01209 }
01210 }
01211
01212
01213
01214
01215
01216
if (
HeapHandle == NtCurrentPeb()->ProcessHeap) {
01217
01218
return HeapHandle;
01219 }
01220
01221
#endif // NTOS_KERNEL_RUNTIME
01222
01223
01224
01225
01226
01227
01228 Head = &Heap->
VirtualAllocdBlocks;
01229 Next = Head->Flink;
01230
01231
while (Head != Next) {
01232
01233 BaseAddress = CONTAINING_RECORD( Next,
HEAP_VIRTUAL_ALLOC_ENTRY, Entry );
01234
01235 Next = Next->Flink;
01236 RegionSize = 0;
01237
01238 ZwFreeVirtualMemory( NtCurrentProcess(),
01239 (PVOID *)&BaseAddress,
01240 &RegionSize,
01241 MEM_RELEASE );
01242 }
01243
01244
#ifndef NTOS_KERNEL_RUNTIME
01245
01246
01247
01248
01249
01250
01251
RtlpDestroyTags( Heap );
01252
RtlpRemoveHeapFromProcessList( Heap );
01253
01254
#endif // NTOS_KERNEL_RUNTIME
01255
01256
01257
01258
01259
01260
01261
if (!(Heap->
Flags & HEAP_NO_SERIALIZE)) {
01262
01263
if (!(Heap->
Flags &
HEAP_LOCK_USER_ALLOCATED)) {
01264
01265 (
VOID)
RtlDeleteLockRoutine( Heap->
LockVariable );
01266 }
01267
01268 Heap->
LockVariable =
NULL;
01269 }
01270
01271
01272
01273
01274
01275 UCRSegments = Heap->
UCRSegments;
01276 Heap->
UCRSegments =
NULL;
01277
01278
while (UCRSegments) {
01279
01280 BaseAddress = UCRSegments;
01281 UCRSegments = UCRSegments->
Next;
01282 RegionSize = 0;
01283
01284 ZwFreeVirtualMemory( NtCurrentProcess(),
01285 &BaseAddress,
01286 &RegionSize,
01287 MEM_RELEASE );
01288 }
01289
01290
01291
01292
01293
01294
01295 SegmentIndex =
HEAP_MAXIMUM_SEGMENTS;
01296
01297
while (SegmentIndex--) {
01298
01299 Segment = Heap->
Segments[ SegmentIndex ];
01300
01301
if (Segment) {
01302
01303
RtlpDestroyHeapSegment( Segment );
01304 }
01305 }
01306
01307
01308
01309
01310
01311
return NULL;
01312 }
01313
01314
01315 PVOID
01316 RtlAllocateHeap (
01317 IN PVOID HeapHandle,
01318 IN ULONG Flags,
01319 IN SIZE_T Size
01320 )
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343 {
01344
PHEAP Heap = (
PHEAP)
HeapHandle;
01345 PULONG FreeListsInUse;
01346 ULONG FreeListsInUseUlong;
01347 SIZE_T AllocationSize;
01348 SIZE_T FreeSize, AllocationIndex;
01349 PLIST_ENTRY FreeListHead, Next;
01350
PHEAP_ENTRY BusyBlock;
01351
PHEAP_FREE_ENTRY FreeBlock, SplitBlock, SplitBlock2;
01352 ULONG InUseIndex;
01353 UCHAR FreeFlags;
01354
NTSTATUS Status;
01355 EXCEPTION_RECORD ExceptionRecord;
01356 PVOID ReturnValue;
01357 BOOLEAN LockAcquired =
FALSE;
01358
01359
RTL_PAGED_CODE();
01360
01361
01362
#ifndef NTOS_KERNEL_RUNTIME
01363
#ifdef NTHEAP_ENABLED
01364
{
01365
if (Heap->
Flags & NTHEAP_ENABLED_FLAG) {
01366
01367
return RtlAllocateNtHeap(
HeapHandle,
01368 Flags,
01369
Size);
01370 }
01371 }
01372
#endif // NTHEAP_ENABLED
01373
#endif // NTOS_KERNEL_RUNTIME
01374
01375
01376
01377
01378
01379
01380
01381 Flags |= Heap->
ForceFlags;
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
if ((Flags &
HEAP_SLOW_FLAGS) || (
Size >= 0x80000000)) {
01415
01416
return RtlAllocateHeapSlowly(
HeapHandle, Flags,
Size );
01417 }
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 AllocationSize = ((
Size ?
Size : 1) +
HEAP_GRANULARITY - 1 +
sizeof(
HEAP_ENTRY ))
01434 & ~(
HEAP_GRANULARITY -1);
01435 AllocationIndex = AllocationSize >>
HEAP_GRANULARITY_SHIFT;
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
#ifndef NTOS_KERNEL_RUNTIME
01449
01450 {
01451
PHEAP_LOOKASIDE Lookaside = (
PHEAP_LOOKASIDE)Heap->
Lookaside;
01452
01453
if ((Lookaside !=
NULL) &&
01454 (Heap->
LookasideLockCount == 0) &&
01455 (AllocationIndex <
HEAP_MAXIMUM_FREELISTS)) {
01456
01457
01458
01459
01460
01461
01462
if ((LONG)(Lookaside[AllocationIndex].
TotalAllocates - Lookaside[AllocationIndex].
LastTotalAllocates) >=
01463 (Lookaside[AllocationIndex].
Depth * 128)) {
01464
01465
RtlpAdjustHeapLookasideDepth(&(Lookaside[AllocationIndex]));
01466 }
01467
01468 ReturnValue =
RtlpAllocateFromHeapLookaside(&(Lookaside[AllocationIndex]));
01469
01470
if (ReturnValue !=
NULL) {
01471
01472
PHEAP_ENTRY BusyBlock;
01473
01474 BusyBlock = ((
PHEAP_ENTRY)ReturnValue) - 1;
01475 BusyBlock->
UnusedBytes = (UCHAR)(AllocationSize -
Size);
01476 BusyBlock->
SmallTagIndex = 0;
01477
01478
if (Flags & HEAP_ZERO_MEMORY) {
01479
01480 RtlZeroMemory( ReturnValue,
Size );
01481 }
01482
01483
return ReturnValue;
01484 }
01485 }
01486 }
01487
01488
#endif // NTOS_KERNEL_RUNTIME
01489
01490
try {
01491
01492
01493
01494
01495
01496
if (!(Flags & HEAP_NO_SERIALIZE)) {
01497
01498
01499
01500
01501
01502
RtlAcquireLockRoutine( Heap->
LockVariable );
01503
01504 LockAcquired =
TRUE;
01505 }
01506
01507
01508
01509
01510
01511
01512
01513
01514
if (AllocationIndex <
HEAP_MAXIMUM_FREELISTS) {
01515
01516
01517
01518
01519
01520
01521 FreeListHead = &Heap->
FreeLists[ AllocationIndex ];
01522
01523
if ( !IsListEmpty( FreeListHead )) {
01524
01525
01526
01527
01528
01529
01530 FreeBlock = CONTAINING_RECORD( FreeListHead->Blink,
01531
HEAP_FREE_ENTRY,
01532 FreeList );
01533
01534 FreeFlags = FreeBlock->
Flags;
01535
01536
RtlpFastRemoveDedicatedFreeBlock( Heap, FreeBlock );
01537
01538
01539
01540
01541
01542 Heap->
TotalFreeSize -= AllocationIndex;
01543
01544
01545
01546
01547
01548
01549
01550 BusyBlock = (
PHEAP_ENTRY)FreeBlock;
01551 BusyBlock->
Flags =
HEAP_ENTRY_BUSY | (FreeFlags &
HEAP_ENTRY_LAST_ENTRY);
01552 BusyBlock->
UnusedBytes = (UCHAR)(AllocationSize -
Size);
01553 BusyBlock->
SmallTagIndex = 0;
01554
01555 }
else {
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568 InUseIndex = (ULONG) (AllocationIndex >> 5);
01569 FreeListsInUse = &Heap->
u.FreeListsInUseUlong[InUseIndex];
01570
01571
01572
01573
01574
01575
01576 FreeListsInUseUlong = *FreeListsInUse++ & ~((1 << ((ULONG) AllocationIndex & 0x1f)) - 1);
01577
01578
01579
01580
01581
01582
switch (InUseIndex) {
01583
01584
case 0:
01585
01586
if (FreeListsInUseUlong) {
01587
01588 FreeListHead = &Heap->
FreeLists[0];
01589
break;
01590 }
01591
01592 FreeListsInUseUlong = *FreeListsInUse++;
01593
01594
01595
01596
01597
01598
case 1:
01599
01600
if (FreeListsInUseUlong) {
01601
01602 FreeListHead = &Heap->
FreeLists[32];
01603
break;
01604 }
01605
01606 FreeListsInUseUlong = *FreeListsInUse++;
01607
01608
01609
01610
01611
01612
case 2:
01613
01614
if (FreeListsInUseUlong) {
01615
01616 FreeListHead = &Heap->
FreeLists[64];
01617
break;
01618 }
01619
01620 FreeListsInUseUlong = *FreeListsInUse++;
01621
01622
01623
01624
01625
01626
case 3:
01627
01628
if (FreeListsInUseUlong) {
01629
01630 FreeListHead = &Heap->
FreeLists[96];
01631
break;
01632 }
01633
01634
01635
01636
01637
01638
default:
01639
01640
01641
01642
01643
01644
goto LookInNonDedicatedList;
01645 }
01646
01647
01648
01649
01650
01651
01652
01653 FreeListHead +=
RtlFindFirstSetRightMember( FreeListsInUseUlong );
01654
01655
01656
01657
01658
01659 FreeBlock = CONTAINING_RECORD( FreeListHead->Blink,
01660
HEAP_FREE_ENTRY,
01661 FreeList );
01662
01663
RtlpFastRemoveDedicatedFreeBlock( Heap, FreeBlock );
01664
01665 SplitFreeBlock:
01666
01667
01668
01669
01670
01671
01672 FreeFlags = FreeBlock->
Flags;
01673 Heap->
TotalFreeSize -= FreeBlock->
Size;
01674
01675
01676
01677
01678
01679 BusyBlock = (
PHEAP_ENTRY)FreeBlock;
01680 BusyBlock->
Flags =
HEAP_ENTRY_BUSY;
01681
01682
01683
01684
01685
01686
01687 FreeSize = BusyBlock->
Size - AllocationIndex;
01688
01689
01690
01691
01692
01693 BusyBlock->
Size = (
USHORT)AllocationIndex;
01694 BusyBlock->
UnusedBytes = (UCHAR)(AllocationSize -
Size);
01695 BusyBlock->
SmallTagIndex = 0;
01696
01697
01698
01699
01700
01701
01702
if (FreeSize != 0) {
01703
01704
01705
01706
01707
01708
01709
01710
if (FreeSize == 1) {
01711
01712 BusyBlock->
Size += 1;
01713 BusyBlock->
UnusedBytes +=
sizeof(
HEAP_ENTRY );
01714
01715 }
else {
01716
01717
01718
01719
01720
01721
01722
01723
01724 SplitBlock = (
PHEAP_FREE_ENTRY)(BusyBlock + AllocationIndex);
01725
01726
01727
01728
01729
01730
01731 SplitBlock->
Flags = FreeFlags;
01732 SplitBlock->
PreviousSize = (
USHORT)AllocationIndex;
01733 SplitBlock->
SegmentIndex = BusyBlock->
SegmentIndex;
01734 SplitBlock->
Size = (
USHORT)FreeSize;
01735
01736
01737
01738
01739
01740
01741
01742
if (FreeFlags &
HEAP_ENTRY_LAST_ENTRY) {
01743
01744
RtlpFastInsertFreeBlockDirect( Heap, SplitBlock, (
USHORT)FreeSize);
01745 Heap->
TotalFreeSize += FreeSize;
01746
01747 }
else {
01748
01749
01750
01751
01752
01753
01754
01755
01756 SplitBlock2 = (
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)SplitBlock + FreeSize);
01757
01758
if (SplitBlock2->
Flags &
HEAP_ENTRY_BUSY) {
01759
01760 SplitBlock2->
PreviousSize = (
USHORT)FreeSize;
01761
01762
RtlpFastInsertFreeBlockDirect( Heap, SplitBlock, (
USHORT)FreeSize );
01763 Heap->
TotalFreeSize += FreeSize;
01764
01765 }
else {
01766
01767
01768
01769
01770
01771
01772 SplitBlock->
Flags = SplitBlock2->
Flags;
01773
01774
01775
01776
01777
01778
RtlpFastRemoveFreeBlock( Heap, SplitBlock2 );
01779
01780
01781
01782
01783
01784
01785
01786 Heap->
TotalFreeSize -= SplitBlock2->
Size;
01787 FreeSize += SplitBlock2->
Size;
01788
01789
01790
01791
01792
01793
01794
01795
if (FreeSize <=
HEAP_MAXIMUM_BLOCK_SIZE) {
01796
01797 SplitBlock->
Size = (
USHORT)FreeSize;
01798
01799
01800
01801
01802
01803
01804
01805
if (!(SplitBlock->
Flags &
HEAP_ENTRY_LAST_ENTRY)) {
01806
01807 ((
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (
USHORT)FreeSize;
01808 }
01809
01810
01811
01812
01813
01814
01815
RtlpFastInsertFreeBlockDirect( Heap, SplitBlock, (
USHORT)FreeSize );
01816 Heap->
TotalFreeSize += FreeSize;
01817
01818 }
else {
01819
01820
01821
01822
01823
01824
01825
01826
RtlpInsertFreeBlock( Heap, SplitBlock, FreeSize );
01827 }
01828 }
01829 }
01830
01831
01832
01833
01834
01835
01836 FreeFlags = 0;
01837
01838
01839
01840
01841
01842
if (SplitBlock->
Flags &
HEAP_ENTRY_LAST_ENTRY) {
01843
01844
PHEAP_SEGMENT Segment;
01845
01846 Segment = Heap->
Segments[SplitBlock->
SegmentIndex];
01847 Segment->
LastEntryInSegment = (
PHEAP_ENTRY)SplitBlock;
01848 }
01849 }
01850 }
01851
01852
01853
01854
01855
01856
01857
if (FreeFlags &
HEAP_ENTRY_LAST_ENTRY) {
01858
01859 BusyBlock->
Flags |=
HEAP_ENTRY_LAST_ENTRY;
01860 }
01861 }
01862
01863
01864
01865
01866
01867
01868 ReturnValue = BusyBlock + 1;
01869
01870
01871
01872
01873
01874
if (LockAcquired) {
01875
01876
RtlReleaseLockRoutine( Heap->
LockVariable );
01877
01878 LockAcquired =
FALSE;
01879 }
01880
01881
01882
01883
01884
01885
if (Flags & HEAP_ZERO_MEMORY) {
01886
01887 RtlZeroMemory( ReturnValue,
Size );
01888 }
01889
01890
01891
01892
01893
01894 leave;
01895
01896
01897
01898
01899
01900
01901
01902 }
else if (AllocationIndex <= Heap->
VirtualMemoryThreshold) {
01903
01904 LookInNonDedicatedList:
01905
01906
01907
01908
01909
01910
01911
01912 FreeListHead = &Heap->
FreeLists[0];
01913
01914
01915
01916
01917
01918 Next = FreeListHead->Blink;
01919
01920
if (FreeListHead != Next) {
01921
01922 FreeBlock = CONTAINING_RECORD( Next,
HEAP_FREE_ENTRY, FreeList );
01923
01924
if (FreeBlock->
Size >= AllocationIndex) {
01925
01926
01927
01928
01929
01930
01931 Next = FreeListHead->Flink;
01932
01933
while (FreeListHead != Next) {
01934
01935 FreeBlock = CONTAINING_RECORD( Next,
HEAP_FREE_ENTRY, FreeList );
01936
01937
if (FreeBlock->
Size >= AllocationIndex) {
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
RtlpFastRemoveNonDedicatedFreeBlock( Heap, FreeBlock );
01949
01950
goto SplitFreeBlock;
01951 }
01952
01953 Next = Next->Flink;
01954 }
01955 }
01956 }
01957
01958
01959
01960
01961
01962
01963
01964 FreeBlock =
RtlpExtendHeap( Heap, AllocationSize );
01965
01966
01967
01968
01969
01970
01971
if (FreeBlock !=
NULL) {
01972
01973
RtlpFastRemoveNonDedicatedFreeBlock( Heap, FreeBlock );
01974
01975
goto SplitFreeBlock;
01976 }
01977
01978
01979
01980
01981
01982
Status = STATUS_NO_MEMORY;
01983
01984
01985
01986
01987
01988
01989 }
else if (Heap->
Flags & HEAP_GROWABLE) {
01990
01991
PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
01992
01993 VirtualAllocBlock =
NULL;
01994
01995
01996
01997
01998
01999
02000
02001 AllocationSize += FIELD_OFFSET(
HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
02002
02003
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
02004 (PVOID *)&VirtualAllocBlock,
02005 0,
02006 &AllocationSize,
02007 MEM_COMMIT,
02008 PAGE_READWRITE );
02009
02010
if (
NT_SUCCESS(
Status)) {
02011
02012
02013
02014
02015
02016
02017 VirtualAllocBlock->BusyBlock.Size = (
USHORT)(AllocationSize -
Size);
02018 VirtualAllocBlock->BusyBlock.Flags =
HEAP_ENTRY_VIRTUAL_ALLOC |
HEAP_ENTRY_EXTRA_PRESENT |
HEAP_ENTRY_BUSY;
02019 VirtualAllocBlock->CommitSize = AllocationSize;
02020 VirtualAllocBlock->ReserveSize = AllocationSize;
02021
02022 InsertTailList( &Heap->
VirtualAllocdBlocks, (PLIST_ENTRY)VirtualAllocBlock );
02023
02024
02025
02026
02027
02028
02029 ReturnValue = (
PHEAP_ENTRY)(VirtualAllocBlock + 1);
02030
02031 leave;
02032 }
02033
02034 }
else {
02035
02036
Status = STATUS_BUFFER_TOO_SMALL;
02037 }
02038
02039
02040
02041
02042
02043
if (Flags & HEAP_GENERATE_EXCEPTIONS) {
02044
02045
02046
02047
02048
02049 ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
02050 ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)
NULL;
02051 ExceptionRecord.NumberParameters = 1;
02052 ExceptionRecord.ExceptionFlags = 0;
02053 ExceptionRecord.ExceptionInformation[ 0 ] = AllocationSize;
02054
02055
RtlRaiseException( &ExceptionRecord );
02056 }
02057
02058
SET_LAST_STATUS(
Status);
02059
02060 ReturnValue =
NULL;
02061
02062 } finally {
02063
02064
if (LockAcquired) {
02065
02066
RtlReleaseLockRoutine( Heap->
LockVariable );
02067 }
02068 }
02069
02070
return ReturnValue;
02071 }
02072
02073
02074 PVOID
02075 RtlAllocateHeapSlowly (
02076 IN PVOID HeapHandle,
02077 IN ULONG Flags,
02078 IN SIZE_T Size
02079 )
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102 {
02103
PHEAP Heap = (
PHEAP)
HeapHandle;
02104 BOOLEAN LockAcquired =
FALSE;
02105 PVOID ReturnValue =
NULL;
02106 PULONG FreeListsInUse;
02107 ULONG FreeListsInUseUlong;
02108 SIZE_T AllocationSize;
02109 SIZE_T FreeSize, AllocationIndex;
02110 UCHAR EntryFlags, FreeFlags;
02111 PLIST_ENTRY FreeListHead, Next;
02112
PHEAP_ENTRY BusyBlock;
02113
PHEAP_FREE_ENTRY FreeBlock, SplitBlock, SplitBlock2;
02114
PHEAP_ENTRY_EXTRA ExtraStuff;
02115
NTSTATUS Status;
02116 EXCEPTION_RECORD ExceptionRecord;
02117 SIZE_T ZeroSize = 0;
02118
02119
RTL_PAGED_CODE();
02120
02121
02122
02123
02124
02125
#ifndef NTOS_KERNEL_RUNTIME
02126
02127
02128
02129
02130
02131
02132
if (
DEBUG_HEAP( Flags )) {
02133
02134
return RtlDebugAllocateHeap(
HeapHandle, Flags,
Size );
02135 }
02136
02137
#endif // NTOS_KERNEL_RUNTIME
02138
02139
02140
02141
02142
02143
02144
if (
Size > 0x7fffffff) {
02145
02146
SET_LAST_STATUS( STATUS_NO_MEMORY );
02147
02148
return NULL;
02149 }
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159 AllocationSize = ((
Size ?
Size : 1) + Heap->
AlignRound) & Heap->
AlignMask;
02160
02161
02162
02163
02164
02165
02166
02167
02168 EntryFlags = (UCHAR)(
HEAP_ENTRY_BUSY | ((Flags & HEAP_SETTABLE_USER_FLAGS) >> 4));
02169
02170
if ((Flags &
HEAP_NEED_EXTRA_FLAGS) || (Heap->
PseudoTagEntries !=
NULL)) {
02171
02172 EntryFlags |=
HEAP_ENTRY_EXTRA_PRESENT;
02173 AllocationSize +=
sizeof(
HEAP_ENTRY_EXTRA );
02174 }
02175
02176 AllocationIndex = AllocationSize >>
HEAP_GRANULARITY_SHIFT;
02177
02178
try {
02179
02180
02181
02182
02183
02184
if (!(Flags & HEAP_NO_SERIALIZE)) {
02185
02186
RtlAcquireLockRoutine( Heap->
LockVariable );
02187
02188 LockAcquired =
TRUE;
02189 }
02190
02191
02192
02193
02194
02195
02196
try {
02197
02198
02199
02200
02201
02202
02203
02204
02205
if (AllocationIndex <
HEAP_MAXIMUM_FREELISTS) {
02206
02207
02208
02209
02210
02211
02212 FreeListHead = &Heap->
FreeLists[ AllocationIndex ];
02213
02214
if ( !IsListEmpty( FreeListHead )) {
02215
02216
02217
02218
02219
02220
02221 FreeBlock = CONTAINING_RECORD( FreeListHead->Flink,
02222
HEAP_FREE_ENTRY,
02223 FreeList );
02224
02225 FreeFlags = FreeBlock->
Flags;
02226
02227
RtlpRemoveFreeBlock( Heap, FreeBlock );
02228
02229
02230
02231
02232
02233 Heap->
TotalFreeSize -= AllocationIndex;
02234
02235
02236
02237
02238
02239
02240
02241 BusyBlock = (
PHEAP_ENTRY)FreeBlock;
02242 BusyBlock->
Flags = EntryFlags | (FreeFlags &
HEAP_ENTRY_LAST_ENTRY);
02243 BusyBlock->
UnusedBytes = (UCHAR)(AllocationSize -
Size);
02244
02245 }
else {
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
if (AllocationIndex < (
HEAP_MAXIMUM_FREELISTS * 1) / 4) {
02258
02259
02260
02261
02262
02263
02264
02265 FreeListsInUse = &Heap->
u.FreeListsInUseUlong[ 0 ];
02266 FreeListsInUseUlong = *FreeListsInUse++ >> ((ULONG) AllocationIndex & 0x1F);
02267
02268
02269
02270
02271
02272
02273
02274
02275
if (FreeListsInUseUlong) {
02276
02277 FreeListHead +=
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02278
02279 }
else {
02280
02281
02282
02283
02284
02285
02286 FreeListsInUseUlong = *FreeListsInUse++;
02287
02288
02289
02290
02291
02292
02293
02294
if (FreeListsInUseUlong) {
02295
02296 FreeListHead += ((
HEAP_MAXIMUM_FREELISTS * 1) / 4) -
02297 (AllocationIndex & 0x1F) +
02298
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02299
02300 }
else {
02301
02302
02303
02304
02305
02306 FreeListsInUseUlong = *FreeListsInUse++;
02307
02308
if (FreeListsInUseUlong) {
02309
02310 FreeListHead += ((
HEAP_MAXIMUM_FREELISTS * 2) / 4) -
02311 (AllocationIndex & 0x1F) +
02312
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02313
02314 }
else {
02315
02316
02317
02318
02319
02320
02321
02322 FreeListsInUseUlong = *FreeListsInUse++;
02323
02324
if (FreeListsInUseUlong) {
02325
02326 FreeListHead += ((
HEAP_MAXIMUM_FREELISTS * 3) / 4) -
02327 (AllocationIndex & 0x1F) +
02328
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02329
02330 }
else {
02331
02332
goto LookInNonDedicatedList;
02333 }
02334 }
02335 }
02336 }
02337
02338
02339
02340
02341
02342
02343
02344
02345 }
else if (AllocationIndex < (
HEAP_MAXIMUM_FREELISTS * 2) / 4) {
02346
02347 FreeListsInUse = &Heap->
u.FreeListsInUseUlong[ 1 ];
02348 FreeListsInUseUlong = *FreeListsInUse++ >> ((ULONG) AllocationIndex & 0x1F);
02349
02350
if (FreeListsInUseUlong) {
02351
02352 FreeListHead +=
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02353
02354 }
else {
02355
02356 FreeListsInUseUlong = *FreeListsInUse++;
02357
02358
if (FreeListsInUseUlong) {
02359
02360 FreeListHead += ((
HEAP_MAXIMUM_FREELISTS * 1) / 4) -
02361 (AllocationIndex & 0x1F) +
02362
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02363
02364 }
else {
02365
02366 FreeListsInUseUlong = *FreeListsInUse++;
02367
02368
if (FreeListsInUseUlong) {
02369
02370 FreeListHead += ((
HEAP_MAXIMUM_FREELISTS * 2) / 4) -
02371 (AllocationIndex & 0x1F) +
02372
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02373
02374 }
else {
02375
02376
goto LookInNonDedicatedList;
02377 }
02378 }
02379 }
02380
02381
02382
02383
02384
02385
02386
02387
02388 }
else if (AllocationIndex < (
HEAP_MAXIMUM_FREELISTS * 3) / 4) {
02389
02390 FreeListsInUse = &Heap->
u.FreeListsInUseUlong[ 2 ];
02391 FreeListsInUseUlong = *FreeListsInUse++ >> ((ULONG) AllocationIndex & 0x1F);
02392
02393
if (FreeListsInUseUlong) {
02394
02395 FreeListHead +=
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02396
02397 }
else {
02398
02399 FreeListsInUseUlong = *FreeListsInUse++;
02400
02401
if (FreeListsInUseUlong) {
02402
02403 FreeListHead += ((
HEAP_MAXIMUM_FREELISTS * 1) / 4) -
02404 (AllocationIndex & 0x1F) +
02405
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02406
02407 }
else {
02408
02409
goto LookInNonDedicatedList;
02410 }
02411 }
02412
02413
02414
02415
02416
02417
02418
02419 }
else {
02420
02421 FreeListsInUse = &Heap->
u.FreeListsInUseUlong[ 3 ];
02422 FreeListsInUseUlong = *FreeListsInUse++ >> ((ULONG) AllocationIndex & 0x1F);
02423
02424
if (FreeListsInUseUlong) {
02425
02426 FreeListHead +=
RtlFindFirstSetRightMember( FreeListsInUseUlong );
02427
02428 }
else {
02429
02430
goto LookInNonDedicatedList;
02431 }
02432 }
02433
02434
02435
02436
02437
02438
02439 FreeBlock = CONTAINING_RECORD( FreeListHead->Flink,
02440
HEAP_FREE_ENTRY,
02441 FreeList );
02442
02443 SplitFreeBlock:
02444
02445
02446
02447
02448
02449
02450 FreeFlags = FreeBlock->
Flags;
02451
02452
RtlpRemoveFreeBlock( Heap, FreeBlock );
02453
02454
02455
02456
02457
02458 Heap->
TotalFreeSize -= FreeBlock->
Size;
02459
02460
02461
02462
02463
02464 BusyBlock = (
PHEAP_ENTRY)FreeBlock;
02465 BusyBlock->
Flags = EntryFlags;
02466
02467
02468
02469
02470
02471
02472 FreeSize = BusyBlock->
Size - AllocationIndex;
02473
02474
02475
02476
02477
02478 BusyBlock->
Size = (
USHORT)AllocationIndex;
02479 BusyBlock->
UnusedBytes = (UCHAR)(AllocationSize -
Size);
02480
02481
02482
02483
02484
02485
02486
if (FreeSize != 0) {
02487
02488
02489
02490
02491
02492
02493
02494
if (FreeSize == 1) {
02495
02496 BusyBlock->
Size += 1;
02497 BusyBlock->
UnusedBytes +=
sizeof(
HEAP_ENTRY );
02498
02499 }
else {
02500
02501
02502
02503
02504
02505
02506
02507
02508 SplitBlock = (
PHEAP_FREE_ENTRY)(BusyBlock + AllocationIndex);
02509
02510
02511
02512
02513
02514
02515 SplitBlock->
Flags = FreeFlags;
02516 SplitBlock->
PreviousSize = (
USHORT)AllocationIndex;
02517 SplitBlock->
SegmentIndex = BusyBlock->
SegmentIndex;
02518 SplitBlock->
Size = (
USHORT)FreeSize;
02519
02520
02521
02522
02523
02524
02525
if (FreeFlags &
HEAP_ENTRY_LAST_ENTRY) {
02526
02527
RtlpInsertFreeBlockDirect( Heap, SplitBlock, (
USHORT)FreeSize );
02528
02529 Heap->
TotalFreeSize += FreeSize;
02530
02531 }
else {
02532
02533
02534
02535
02536
02537
02538
02539
02540 SplitBlock2 = (
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)SplitBlock + FreeSize);
02541
02542
if (SplitBlock2->
Flags &
HEAP_ENTRY_BUSY) {
02543
02544 SplitBlock2->
PreviousSize = (
USHORT)FreeSize;
02545
02546
RtlpInsertFreeBlockDirect( Heap, SplitBlock, (
USHORT)FreeSize );
02547
02548 Heap->
TotalFreeSize += FreeSize;
02549
02550 }
else {
02551
02552
02553
02554
02555
02556
02557 SplitBlock->
Flags = SplitBlock2->
Flags;
02558
02559
02560
02561
02562
02563
02564
RtlpRemoveFreeBlock( Heap, SplitBlock2 );
02565
02566
02567
02568
02569
02570
02571
02572 Heap->
TotalFreeSize -= SplitBlock2->
Size;
02573 FreeSize += SplitBlock2->
Size;
02574
02575
02576
02577
02578
02579
02580
02581
if (FreeSize <=
HEAP_MAXIMUM_BLOCK_SIZE) {
02582
02583 SplitBlock->
Size = (
USHORT)FreeSize;
02584
02585
02586
02587
02588
02589
02590
02591
if (!(SplitBlock->
Flags &
HEAP_ENTRY_LAST_ENTRY)) {
02592
02593 ((
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (
USHORT)FreeSize;
02594 }
02595
02596
02597
02598
02599
02600
02601
RtlpInsertFreeBlockDirect( Heap, SplitBlock, (
USHORT)FreeSize );
02602
02603 Heap->
TotalFreeSize += FreeSize;
02604
02605 }
else {
02606
02607
02608
02609
02610
02611
02612
02613
RtlpInsertFreeBlock( Heap, SplitBlock, FreeSize );
02614 }
02615 }
02616 }
02617
02618
02619
02620
02621
02622
02623 FreeFlags = 0;
02624
02625
02626
02627
02628
02629
if (SplitBlock->
Flags &
HEAP_ENTRY_LAST_ENTRY) {
02630
02631
PHEAP_SEGMENT Segment;
02632
02633 Segment = Heap->
Segments[SplitBlock->
SegmentIndex];
02634 Segment->
LastEntryInSegment = (
PHEAP_ENTRY)SplitBlock;
02635 }
02636
02637 }
02638 }
02639
02640
02641
02642
02643
02644
02645
if (FreeFlags &
HEAP_ENTRY_LAST_ENTRY) {
02646
02647 BusyBlock->
Flags |=
HEAP_ENTRY_LAST_ENTRY;
02648 }
02649 }
02650
02651
02652
02653
02654
02655
02656 ReturnValue = BusyBlock + 1;
02657
02658
02659
02660
02661
02662
02663
if (Flags & HEAP_ZERO_MEMORY) {
02664
02665 ZeroSize =
Size;
02666
02667
02668
02669
02670
02671
02672 }
else if (Heap->
Flags & HEAP_FREE_CHECKING_ENABLED) {
02673
02674 RtlFillMemoryUlong( (PCHAR)(BusyBlock + 1),
Size & ~0x3,
ALLOC_HEAP_FILL );
02675 }
02676
02677
02678
02679
02680
02681
02682
if (Heap->
Flags & HEAP_TAIL_CHECKING_ENABLED) {
02683
02684 RtlFillMemory( (PCHAR)ReturnValue +
Size,
02685
CHECK_HEAP_TAIL_SIZE,
02686
CHECK_HEAP_TAIL_FILL );
02687
02688 BusyBlock->Flags |=
HEAP_ENTRY_FILL_PATTERN;
02689 }
02690
02691 BusyBlock->SmallTagIndex = 0;
02692
02693
02694
02695
02696
02697
02698
if (BusyBlock->Flags &
HEAP_ENTRY_EXTRA_PRESENT) {
02699
02700 ExtraStuff =
RtlpGetExtraStuffPointer( BusyBlock );
02701
02702 RtlZeroMemory( ExtraStuff,
sizeof( *ExtraStuff ));
02703
02704
#ifndef NTOS_KERNEL_RUNTIME
02705
02706
02707
02708
02709
02710
02711
if (
IS_HEAP_TAGGING_ENABLED()) {
02712
02713 ExtraStuff->TagIndex =
RtlpUpdateTagEntry( Heap,
02714 (
USHORT)((Flags & HEAP_TAG_MASK) >> HEAP_TAG_SHIFT),
02715 0,
02716 BusyBlock->Size,
02717
AllocationAction );
02718 }
02719
02720 }
else if (
IS_HEAP_TAGGING_ENABLED()) {
02721
02722 BusyBlock->SmallTagIndex = (UCHAR)
RtlpUpdateTagEntry( Heap,
02723 (
USHORT)((Flags &
HEAP_SMALL_TAG_MASK) >> HEAP_TAG_SHIFT),
02724 0,
02725 BusyBlock->Size,
02726
AllocationAction );
02727
02728
#endif // NTOS_KERNEL_RUNTIME
02729
02730 }
02731
02732
02733
02734
02735
02736
02737 leave;
02738
02739
02740
02741
02742
02743
02744
02745 }
else if (AllocationIndex <= Heap->
VirtualMemoryThreshold) {
02746
02747 LookInNonDedicatedList:
02748
02749
02750
02751
02752
02753
02754
02755 FreeListHead = &Heap->
FreeLists[ 0 ];
02756 Next = FreeListHead->Flink;
02757
02758
while (FreeListHead != Next) {
02759
02760 FreeBlock = CONTAINING_RECORD( Next,
HEAP_FREE_ENTRY, FreeList );
02761
02762
if (FreeBlock->
Size >= AllocationIndex) {
02763
02764
02765
02766
02767
02768
02769
02770
02771
02772
02773
goto SplitFreeBlock;
02774
02775 }
else {
02776
02777 Next = Next->Flink;
02778 }
02779 }
02780
02781
02782
02783
02784
02785
02786
02787 FreeBlock =
RtlpExtendHeap( Heap, AllocationSize );
02788
02789
02790
02791
02792
02793
02794
if (FreeBlock !=
NULL) {
02795
02796
goto SplitFreeBlock;
02797 }
02798
02799
02800
02801
02802
02803
Status = STATUS_NO_MEMORY;
02804
02805
02806
02807
02808
02809
02810 }
else if (Heap->
Flags & HEAP_GROWABLE) {
02811
02812
PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
02813
02814 VirtualAllocBlock =
NULL;
02815
02816
02817
02818
02819
02820
02821
02822 AllocationSize += FIELD_OFFSET(
HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
02823
02824
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
02825 (PVOID *)&VirtualAllocBlock,
02826 0,
02827 &AllocationSize,
02828 MEM_COMMIT,
02829 PAGE_READWRITE );
02830
02831
if (
NT_SUCCESS(
Status )) {
02832
02833
02834
02835
02836
02837
02838 VirtualAllocBlock->BusyBlock.Size = (
USHORT)(AllocationSize -
Size);
02839 VirtualAllocBlock->BusyBlock.Flags = EntryFlags |
HEAP_ENTRY_VIRTUAL_ALLOC |
HEAP_ENTRY_EXTRA_PRESENT;
02840 VirtualAllocBlock->CommitSize = AllocationSize;
02841 VirtualAllocBlock->ReserveSize = AllocationSize;
02842
02843
#ifndef NTOS_KERNEL_RUNTIME
02844
02845
02846
02847
02848
02849
if (
IS_HEAP_TAGGING_ENABLED()) {
02850
02851 VirtualAllocBlock->ExtraStuff.TagIndex =
02852
RtlpUpdateTagEntry( Heap,
02853 (
USHORT)((Flags &
HEAP_SMALL_TAG_MASK) >> HEAP_TAG_SHIFT),
02854 0,
02855 VirtualAllocBlock->CommitSize >>
HEAP_GRANULARITY_SHIFT,
02856
VirtualAllocationAction );
02857 }
02858
02859
#endif // NTOS_KERNEL_RUNTIME
02860
02861 InsertTailList( &Heap->
VirtualAllocdBlocks, (PLIST_ENTRY)VirtualAllocBlock );
02862
02863
02864
02865
02866
02867
02868 ReturnValue = (
PHEAP_ENTRY)(VirtualAllocBlock + 1);
02869
02870 leave;
02871 }
02872
02873
02874
02875
02876
02877 }
else {
02878
02879
Status = STATUS_BUFFER_TOO_SMALL;
02880 }
02881
02882
SET_LAST_STATUS(
Status );
02883
02884
if (Flags & HEAP_GENERATE_EXCEPTIONS) {
02885
02886
02887
02888
02889
02890 ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
02891 ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)
NULL;
02892 ExceptionRecord.NumberParameters = 1;
02893 ExceptionRecord.ExceptionFlags = 0;
02894 ExceptionRecord.ExceptionInformation[ 0 ] = AllocationSize;
02895
02896
RtlRaiseException( &ExceptionRecord );
02897 }
02898
02899 } except( GetExceptionCode() == STATUS_NO_MEMORY ?
EXCEPTION_CONTINUE_SEARCH :
02900
EXCEPTION_EXECUTE_HANDLER ) {
02901
02902
SET_LAST_STATUS( GetExceptionCode() );
02903 }
02904
02905
02906
02907
02908
02909
if ( ZeroSize ) {
02910
02911 RtlZeroMemory( ReturnValue, ZeroSize );
02912 }
02913
02914 } finally {
02915
02916
if (LockAcquired) {
02917
02918
RtlReleaseLockRoutine( Heap->
LockVariable );
02919 }
02920 }
02921
02922
02923
02924
02925
02926
return ReturnValue;
02927 }
02928
02929
02930 BOOLEAN
02931 RtlFreeHeap (
02932 IN PVOID HeapHandle,
02933 IN ULONG Flags,
02934 IN PVOID BaseAddress
02935 )
02936
02937
02938
02939
02940
02941
02942
02943
02944
02945
02946
02947
02948
02949
02950
02951
02952
02953
02954
02955
02956
02957 {
02958
NTSTATUS Status;
02959
PHEAP Heap = (
PHEAP)
HeapHandle;
02960
PHEAP_ENTRY BusyBlock;
02961
PHEAP_ENTRY_EXTRA ExtraStuff;
02962 SIZE_T FreeSize;
02963 BOOLEAN LockAcquired =
FALSE;
02964 BOOLEAN ReturnValue =
TRUE;
02965
02966
RTL_PAGED_CODE();
02967
02968
02969
02970
02971
02972
02973
if (BaseAddress ==
NULL) {
02974
02975
return TRUE;
02976 }
02977
02978
#ifndef NTOS_KERNEL_RUNTIME
02979
#ifdef NTHEAP_ENABLED
02980
{
02981
if (Heap->
Flags & NTHEAP_ENABLED_FLAG) {
02982
02983
return RtlFreeNtHeap(
HeapHandle,
02984 Flags,
02985 BaseAddress);
02986 }
02987 }
02988
#endif // NTHEAP_ENABLED
02989
#endif // NTOS_KERNEL_RUNTIME
02990
02991
02992
02993
02994
02995
02996 Flags |= Heap->
ForceFlags;
02997
02998
02999
03000
03001
03002
if (Flags &
HEAP_SLOW_FLAGS) {
03003
03004
return RtlFreeHeapSlowly(
HeapHandle, Flags, BaseAddress);
03005 }
03006
03007
03008
03009
03010
03011
03012 BusyBlock = (
PHEAP_ENTRY)BaseAddress - 1;
03013
03014
03015
03016
03017
03018
03019
03020
03021
03022
03023
03024
03025
03026
03027
03028
03029
try {
03030
if ((!(BusyBlock->
Flags &
HEAP_ENTRY_BUSY)) ||
03031 (((ULONG_PTR)BaseAddress & 0x7) != 0) ||
03032 (BusyBlock->
SegmentIndex >=
HEAP_MAXIMUM_SEGMENTS)) {
03033
03034
03035
03036
03037
03038
03039
SET_LAST_STATUS( STATUS_INVALID_PARAMETER );
03040
03041
return FALSE;
03042 }
03043 } except(
EXCEPTION_EXECUTE_HANDLER) {
03044
03045
SET_LAST_STATUS( STATUS_INVALID_PARAMETER );
03046
return FALSE;
03047 }
03048
03049
03050
03051
03052
03053
03054
03055
03056
03057
03058
03059
03060
03061
#ifndef NTOS_KERNEL_RUNTIME
03062
03063 {
03064
PHEAP_LOOKASIDE Lookaside = (
PHEAP_LOOKASIDE)Heap->
Lookaside;
03065
03066
if ((Lookaside !=
NULL) &&
03067 (Heap->
LookasideLockCount == 0) &&
03068 (!(BusyBlock->
Flags &
HEAP_ENTRY_VIRTUAL_ALLOC)) &&
03069 ((FreeSize = BusyBlock->
Size) <
HEAP_MAXIMUM_FREELISTS)) {
03070
03071
if (
RtlpFreeToHeapLookaside( &Lookaside[FreeSize], BaseAddress)) {
03072
03073
return TRUE;
03074 }
03075 }
03076 }
03077
03078
#endif // NTOS_KERNEL_RUNTIME
03079
03080
try {
03081
03082
03083
03084
03085
03086
if (!(Flags & HEAP_NO_SERIALIZE)) {
03087
03088
RtlAcquireLockRoutine( Heap->
LockVariable );
03089
03090 LockAcquired =
TRUE;
03091 }
03092
03093
03094
03095
03096
03097
03098
03099
if (!(BusyBlock->
Flags &
HEAP_ENTRY_VIRTUAL_ALLOC)) {
03100
03101
03102
03103
03104
03105
03106
03107
03108
03109 FreeSize = BusyBlock->
Size;
03110
03111
#ifdef NTOS_KERNEL_RUNTIME
03112
03113 BusyBlock = (
PHEAP_ENTRY)
RtlpCoalesceFreeBlocks( Heap,
03114 (
PHEAP_FREE_ENTRY)BusyBlock,
03115 &FreeSize,
03116
FALSE );
03117
03118
#else // NTOS_KERNEL_RUNTIME
03119
03120
if (!(Heap->
Flags & HEAP_DISABLE_COALESCE_ON_FREE)) {
03121
03122 BusyBlock = (
PHEAP_ENTRY)
RtlpCoalesceFreeBlocks( Heap,
03123 (
PHEAP_FREE_ENTRY)BusyBlock,
03124 &FreeSize,
03125
FALSE );
03126 }
03127
03128
#endif // NTOS_KERNEL_RUNTIME
03129
03130
03131
03132
03133
03134
03135
HEAPASSERT(HEAP_MAXIMUM_FREELISTS < Heap->DeCommitFreeBlockThreshold);
03136
03137
03138
03139
03140
03141
03142
03143
03144
if (FreeSize <
HEAP_MAXIMUM_FREELISTS) {
03145
03146
RtlpFastInsertDedicatedFreeBlockDirect( Heap,
03147 (
PHEAP_FREE_ENTRY)BusyBlock,
03148 (
USHORT)FreeSize );
03149
03150
if (!(BusyBlock->
Flags &
HEAP_ENTRY_LAST_ENTRY)) {
03151
03152
HEAPASSERT((BusyBlock + FreeSize)->PreviousSize == (
USHORT)FreeSize);
03153 }
03154
03155 Heap->
TotalFreeSize += FreeSize;
03156
03157
03158
03159
03160
03161
03162
03163
03164 }
else if ((FreeSize < Heap->
DeCommitFreeBlockThreshold) ||
03165 ((Heap->
TotalFreeSize + FreeSize) < Heap->
DeCommitTotalFreeThreshold)) {
03166
03167
03168
03169
03170
03171
03172
03173
03174
if (FreeSize <= (ULONG)
HEAP_MAXIMUM_BLOCK_SIZE) {
03175
03176
RtlpFastInsertNonDedicatedFreeBlockDirect( Heap,
03177 (
PHEAP_FREE_ENTRY)BusyBlock,
03178 (
USHORT)FreeSize );
03179
03180
if (!(BusyBlock->
Flags &
HEAP_ENTRY_LAST_ENTRY)) {
03181
03182
HEAPASSERT((BusyBlock + FreeSize)->PreviousSize == (
USHORT)FreeSize);
03183 }
03184
03185 Heap->
TotalFreeSize += FreeSize;
03186
03187 }
else {
03188
03189
03190
03191
03192
03193
03194
03195
03196
RtlpInsertFreeBlock( Heap, (
PHEAP_FREE_ENTRY)BusyBlock, FreeSize );
03197 }
03198
03199
03200
03201
03202
03203
03204 }
else {
03205
03206
RtlpDeCommitFreeBlock( Heap, (
PHEAP_FREE_ENTRY)BusyBlock, FreeSize );
03207 }
03208
03209 }
else {
03210
03211
03212
03213
03214
03215
03216
03217
PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
03218
03219 VirtualAllocBlock = CONTAINING_RECORD( BusyBlock,
HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
03220
03221 RemoveEntryList( &VirtualAllocBlock->
Entry );
03222
03223
03224
03225
03226
03227
03228
if (LockAcquired) {
03229
03230
RtlReleaseLockRoutine( Heap->
LockVariable );
03231 LockAcquired =
FALSE;
03232 }
03233
03234 FreeSize = 0;
03235
03236
Status = ZwFreeVirtualMemory( NtCurrentProcess(),
03237 (PVOID *)&VirtualAllocBlock,
03238 &FreeSize,
03239 MEM_RELEASE );
03240
03241
03242
03243
03244
03245
03246
03247
if (!
NT_SUCCESS(
Status )) {
03248
03249
SET_LAST_STATUS(
Status );
03250
03251 ReturnValue =
FALSE;
03252 }
03253 }
03254
03255 } finally {
03256
03257
if (LockAcquired) {
03258
03259
RtlReleaseLockRoutine( Heap->
LockVariable );
03260 }
03261 }
03262
03263
03264
03265
03266
03267
03268
return ReturnValue;
03269 }
03270
03271
03272 BOOLEAN
03273 RtlFreeHeapSlowly (
03274 IN PVOID HeapHandle,
03275 IN ULONG Flags,
03276 IN PVOID BaseAddress
03277 )
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301 {
03302
NTSTATUS Status;
03303
PHEAP Heap = (
PHEAP)
HeapHandle;
03304
PHEAP_ENTRY BusyBlock;
03305
PHEAP_ENTRY_EXTRA ExtraStuff;
03306 SIZE_T FreeSize;
03307 BOOLEAN Result;
03308 BOOLEAN LockAcquired =
FALSE;
03309
03310
#ifndef NTOS_KERNEL_RUNTIME
03311
03312
USHORT TagIndex;
03313
03314
#endif // NTOS_KERNEL_RUNTIME
03315
03316
RTL_PAGED_CODE();
03317
03318
03319
03320
03321
03322
#ifndef NTOS_KERNEL_RUNTIME
03323
03324
03325
03326
03327
03328
03329
if (
DEBUG_HEAP( Flags )) {
03330
03331
return RtlDebugFreeHeap(
HeapHandle, Flags, BaseAddress );
03332 }
03333
03334
#endif // NTOS_KERNEL_RUNTIME
03335
03336
03337
03338
03339
03340 Result =
FALSE;
03341
03342
try {
03343
03344
03345
03346
03347
03348
if (!(Flags & HEAP_NO_SERIALIZE)) {
03349
03350
RtlAcquireLockRoutine( Heap->
LockVariable );
03351
03352 LockAcquired =
TRUE;
03353 }
03354
03355
try {
03356
03357
03358
03359
03360
03361 BusyBlock = (
PHEAP_ENTRY)BaseAddress - 1;
03362
03363
03364
03365
03366
03367
03368
03369
03370
03371
03372
03373
03374
03375
03376
03377
03378
03379
03380
03381
if ((BusyBlock->
Flags &
HEAP_ENTRY_BUSY) &&
03382 (((ULONG_PTR)BaseAddress & 0x7) == 0) &&
03383 (BusyBlock->
SegmentIndex <
HEAP_MAXIMUM_SEGMENTS)) {
03384
03385
03386
03387
03388
03389
if (BusyBlock->
Flags &
HEAP_ENTRY_VIRTUAL_ALLOC) {
03390
03391
PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
03392
03393
03394
03395
03396
03397
03398
03399
03400 VirtualAllocBlock = CONTAINING_RECORD( BusyBlock,
HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
03401
03402 RemoveEntryList( &VirtualAllocBlock->
Entry );
03403
03404
#ifndef NTOS_KERNEL_RUNTIME
03405
03406
03407
03408
03409
03410
if (
IS_HEAP_TAGGING_ENABLED()) {
03411
03412
RtlpUpdateTagEntry( Heap,
03413 VirtualAllocBlock->
ExtraStuff.
TagIndex,
03414 VirtualAllocBlock->
CommitSize >>
HEAP_GRANULARITY_SHIFT,
03415 0,
03416
VirtualFreeAction );
03417 }
03418
03419
#endif // NTOS_KERNEL_RUNTIME
03420
03421 FreeSize = 0;
03422
03423
Status = ZwFreeVirtualMemory( NtCurrentProcess(),
03424 (PVOID *)&VirtualAllocBlock,
03425 &FreeSize,
03426 MEM_RELEASE );
03427
03428
03429
03430
03431
03432
03433
if (
NT_SUCCESS(
Status )) {
03434
03435 Result =
TRUE;
03436
03437 }
else {
03438
03439
SET_LAST_STATUS(
Status );
03440 }
03441
03442 }
else {
03443
03444
03445
03446
03447
03448
03449
03450
03451
03452
#ifndef NTOS_KERNEL_RUNTIME
03453
03454
03455
03456
03457
03458
03459
03460
if (
IS_HEAP_TAGGING_ENABLED()) {
03461
03462
if (BusyBlock->
Flags &
HEAP_ENTRY_EXTRA_PRESENT) {
03463
03464 ExtraStuff = (
PHEAP_ENTRY_EXTRA)(BusyBlock + BusyBlock->
Size - 1);
03465
03466 TagIndex =
RtlpUpdateTagEntry( Heap,
03467 ExtraStuff->
TagIndex,
03468 BusyBlock->
Size,
03469 0,
03470
FreeAction );
03471
03472 }
else {
03473
03474 TagIndex =
RtlpUpdateTagEntry( Heap,
03475 BusyBlock->
SmallTagIndex,
03476 BusyBlock->
Size,
03477 0,
03478
FreeAction );
03479 }
03480
03481 }
else {
03482
03483 TagIndex = 0;
03484 }
03485
03486
#endif // NTOS_KERNEL_RUNTIME
03487
03488
03489
03490
03491
03492 FreeSize = BusyBlock->
Size;
03493
03494
#ifndef NTOS_KERNEL_RUNTIME
03495
03496
03497
03498
03499
03500
if (!(Heap->
Flags & HEAP_DISABLE_COALESCE_ON_FREE)) {
03501
03502
#endif // NTOS_KERNEL_RUNTIME
03503
03504
03505
03506
03507
03508
03509 BusyBlock = (
PHEAP_ENTRY)
RtlpCoalesceFreeBlocks( Heap, (
PHEAP_FREE_ENTRY)BusyBlock, &FreeSize,
FALSE );
03510
03511
#ifndef NTOS_KERNEL_RUNTIME
03512
03513 }
03514
03515
#endif // NTOS_KERNEL_RUNTIME
03516
03517
03518
03519
03520
03521
03522
if ((FreeSize < Heap->
DeCommitFreeBlockThreshold) ||
03523 ((Heap->
TotalFreeSize + FreeSize) < Heap->
DeCommitTotalFreeThreshold)) {
03524
03525
03526
03527
03528
03529
03530
if (FreeSize <= (ULONG)
HEAP_MAXIMUM_BLOCK_SIZE) {
03531
03532
03533
03534
03535
03536
RtlpInsertFreeBlockDirect( Heap, (
PHEAP_FREE_ENTRY)BusyBlock, (
USHORT)FreeSize );
03537
03538
03539
03540
03541
03542
03543
if (!(BusyBlock->
Flags &
HEAP_ENTRY_LAST_ENTRY)) {
03544
03545
HEAPASSERT((BusyBlock + FreeSize)->PreviousSize == (
USHORT)FreeSize);
03546 }
03547
03548
03549
03550
03551
03552
03553 Heap->
TotalFreeSize += FreeSize;
03554
03555 }
else {
03556
03557
03558
03559
03560
03561
RtlpInsertFreeBlock( Heap, (
PHEAP_FREE_ENTRY)BusyBlock, FreeSize );
03562 }
03563
03564
#ifndef NTOS_KERNEL_RUNTIME
03565
03566
03567
03568
03569
03570
03571
if (TagIndex != 0) {
03572
03573
PHEAP_FREE_ENTRY_EXTRA FreeExtra;
03574
03575 BusyBlock->
Flags |=
HEAP_ENTRY_EXTRA_PRESENT;
03576
03577 FreeExtra = (
PHEAP_FREE_ENTRY_EXTRA)(BusyBlock + BusyBlock->
Size) - 1;
03578
03579 FreeExtra->
TagIndex = TagIndex;
03580 FreeExtra->
FreeBackTraceIndex = 0;
03581
03582
#if i386
03583
03584
03585
03586
03587
03588
03589
if (Heap->
Flags &
HEAP_CAPTURE_STACK_BACKTRACES) {
03590
03591 FreeExtra->
FreeBackTraceIndex = (
USHORT)RtlLogStackBackTrace();
03592 }
03593
03594
#endif // i386
03595
03596 }
03597
03598
#endif // NTOS_KERNEL_RUNTIME
03599
03600 }
else {
03601
03602
03603
03604
03605
03606
03607
RtlpDeCommitFreeBlock( Heap, (
PHEAP_FREE_ENTRY)BusyBlock, FreeSize );
03608 }
03609
03610
03611
03612
03613
03614 Result =
TRUE;
03615 }
03616
03617 }
else {
03618
03619
03620
03621
03622
03623
03624
SET_LAST_STATUS( STATUS_INVALID_PARAMETER );
03625 }
03626
03627 } except(
EXCEPTION_EXECUTE_HANDLER ) {
03628
03629
SET_LAST_STATUS( GetExceptionCode() );
03630
03631 Result =
FALSE;
03632 }
03633
03634 } finally {
03635
03636
03637
03638
03639
03640
if (LockAcquired) {
03641
03642
RtlReleaseLockRoutine( Heap->
LockVariable );
03643 }
03644 }
03645
03646
03647
03648
03649
03650
return Result;
03651 }
03652
03653
03654 SIZE_T
03655 RtlSizeHeap (
03656 IN PVOID HeapHandle,
03657 IN ULONG Flags,
03658 IN PVOID BaseAddress
03659 )
03660
03661
03662
03663
03664
03665
03666
03667
03668
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686 {
03687
PHEAP Heap = (
PHEAP)
HeapHandle;
03688
PHEAP_ENTRY BusyBlock;
03689 SIZE_T BusySize;
03690
03691
03692
03693
03694
03695 Flags |= Heap->
ForceFlags;
03696
03697
03698
03699
03700
03701
#ifndef NTOS_KERNEL_RUNTIME
03702
03703
if (
DEBUG_HEAP( Flags )) {
03704
03705
return RtlDebugSizeHeap(
HeapHandle, Flags, BaseAddress );
03706 }
03707
03708
#endif // NTOS_KERNEL_RUNTIME
03709
03710
03711
03712
03713
03714
03715
03716 BusyBlock = (
PHEAP_ENTRY)BaseAddress - 1;
03717
03718
03719
03720
03721
03722
03723
if (!(BusyBlock->
Flags &
HEAP_ENTRY_BUSY)) {
03724
03725 BusySize = -1;
03726
03727
SET_LAST_STATUS( STATUS_INVALID_PARAMETER );
03728
03729
03730
03731
03732
03733
03734 }
else if (BusyBlock->
Flags &
HEAP_ENTRY_VIRTUAL_ALLOC) {
03735
03736 BusySize =
RtlpGetSizeOfBigBlock( BusyBlock );
03737
03738
03739
03740
03741
03742
03743
03744
03745
03746
03747 }
else {
03748
03749 BusySize = (BusyBlock->
Size <<
HEAP_GRANULARITY_SHIFT) -
03750 BusyBlock->
UnusedBytes;
03751 }
03752
03753
03754
03755
03756
03757
return BusySize;
03758 }
03759
03760
03761
NTSTATUS
03762 RtlZeroHeap (
03763 IN PVOID HeapHandle,
03764 IN ULONG Flags
03765 )
03766
03767
03768
03769
03770
03771
03772
03773
03774
03775
03776
03777
03778
03779
03780
03781
03782
03783
03784
03785
03786
03787 {
03788
PHEAP Heap = (
PHEAP)
HeapHandle;
03789
NTSTATUS Status;
03790 BOOLEAN LockAcquired =
FALSE;
03791
PHEAP_SEGMENT Segment;
03792 ULONG SegmentIndex;
03793
PHEAP_ENTRY CurrentBlock;
03794
PHEAP_FREE_ENTRY FreeBlock;
03795 SIZE_T
Size;
03796
PHEAP_UNCOMMMTTED_RANGE UnCommittedRange;
03797
03798
RTL_PAGED_CODE();
03799
03800
03801
03802
03803
03804 Flags |= Heap->
ForceFlags;
03805
03806
03807
03808
03809
03810
#ifndef NTOS_KERNEL_RUNTIME
03811
03812
if (
DEBUG_HEAP( Flags )) {
03813
03814
return RtlDebugZeroHeap(
HeapHandle, Flags );
03815 }
03816
03817
#endif // NTOS_KERNEL_RUNTIME
03818
03819
03820
03821
03822
03823
03824
Status = STATUS_SUCCESS;
03825
03826
try {
03827
03828
03829
03830
03831
03832
if (!(Flags & HEAP_NO_SERIALIZE)) {
03833
03834
RtlAcquireLockRoutine( Heap->
LockVariable );
03835
03836 LockAcquired =
TRUE;
03837 }
03838
03839
try {
03840
03841
03842
03843
03844
03845
for (SegmentIndex=0; SegmentIndex<
HEAP_MAXIMUM_SEGMENTS; SegmentIndex++) {
03846
03847 Segment = Heap->
Segments[ SegmentIndex ];
03848
03849
if (!Segment) {
03850
03851
continue;
03852 }
03853
03854 UnCommittedRange = Segment->
UnCommittedRanges;
03855 CurrentBlock = Segment->
FirstEntry;
03856
03857
03858
03859
03860
03861
03862
while (CurrentBlock < Segment->
LastValidEntry) {
03863
03864
Size = CurrentBlock->
Size <<
HEAP_GRANULARITY_SHIFT;
03865
03866
03867
03868
03869
03870
03871
if (!(CurrentBlock->
Flags &
HEAP_ENTRY_BUSY)) {
03872
03873 FreeBlock = (
PHEAP_FREE_ENTRY)CurrentBlock;
03874
03875
if ((Heap->
Flags & HEAP_FREE_CHECKING_ENABLED) &&
03876 (CurrentBlock->
Flags &
HEAP_ENTRY_FILL_PATTERN)) {
03877
03878 RtlFillMemoryUlong( FreeBlock + 1,
03879
Size -
sizeof( *FreeBlock ),
03880
FREE_HEAP_FILL );
03881
03882 }
else {
03883
03884 RtlFillMemoryUlong( FreeBlock + 1,
03885
Size -
sizeof( *FreeBlock ),
03886 0 );
03887 }
03888 }
03889
03890
03891
03892
03893
03894
03895
03896
03897
if (CurrentBlock->
Flags &
HEAP_ENTRY_LAST_ENTRY) {
03898
03899 CurrentBlock += CurrentBlock->
Size;
03900
03901
03902
03903
03904
03905
03906
03907
03908
03909
if (UnCommittedRange ==
NULL) {
03910
03911 CurrentBlock = Segment->
LastValidEntry;
03912
03913
03914
03915
03916
03917 }
else {
03918
03919 CurrentBlock = (
PHEAP_ENTRY)
03920 ((PCHAR)UnCommittedRange->
Address + UnCommittedRange->
Size);
03921
03922 UnCommittedRange = UnCommittedRange->
Next;
03923 }
03924
03925
03926
03927
03928
03929 }
else {
03930
03931 CurrentBlock += CurrentBlock->
Size;
03932 }
03933 }
03934 }
03935
03936 } except(
EXCEPTION_EXECUTE_HANDLER ) {
03937
03938
Status = GetExceptionCode();
03939 }
03940
03941 } finally {
03942
03943
03944
03945
03946
03947
if (LockAcquired) {
03948
03949
RtlReleaseLockRoutine( Heap->
LockVariable );
03950 }
03951 }
03952
03953
return Status;
03954 }
03955
03956
03957
03958
03959
03960
03961
PHEAP_UNCOMMMTTED_RANGE
03962 RtlpCreateUnCommittedRange (
03963 IN
PHEAP_SEGMENT Segment
03964 )
03965
03966
03967
03968
03969
03970
03971
03972
03973
03974
03975
03976
03977
03978
03979
03980
03981
03982
03983
03984
03985
03986 {
03987
NTSTATUS Status;
03988 PVOID FirstEntry, LastEntry;
03989
PHEAP_UNCOMMMTTED_RANGE UnCommittedRange, *pp;
03990 SIZE_T ReserveSize, CommitSize;
03991
PHEAP_UCR_SEGMENT UCRSegment;
03992
03993
RTL_PAGED_CODE();
03994
03995
03996
03997
03998
03999
04000 pp = &Segment->Heap->UnusedUnCommittedRanges;
04001
04002
04003
04004
04005
04006
04007
if (*pp ==
NULL) {
04008
04009
04010
04011
04012
04013 UCRSegment = Segment->Heap->UCRSegments;
04014
04015
04016
04017
04018
04019
04020
04021
04022
if ((UCRSegment ==
NULL) ||
04023 (UCRSegment->
CommittedSize == UCRSegment->
ReservedSize)) {
04024
04025
04026
04027
04028
04029
04030 ReserveSize =
PAGE_SIZE * 16;
04031 UCRSegment =
NULL;
04032
04033
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
04034 &UCRSegment,
04035 0,
04036 &ReserveSize,
04037 MEM_RESERVE,
04038 PAGE_READWRITE );
04039
04040
if (!
NT_SUCCESS(
Status )) {
04041
04042
return NULL;
04043 }
04044
04045 CommitSize =
PAGE_SIZE;
04046
04047
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
04048 &UCRSegment,
04049 0,
04050 &CommitSize,
04051 MEM_COMMIT,
04052 PAGE_READWRITE );
04053
04054
if (!
NT_SUCCESS(
Status )) {
04055
04056 ZwFreeVirtualMemory( NtCurrentProcess(),
04057 &UCRSegment,
04058 &ReserveSize,
04059 MEM_RELEASE );
04060
04061
return NULL;
04062 }
04063
04064
04065
04066
04067
04068 UCRSegment->
Next = Segment->Heap->UCRSegments;
04069 Segment->Heap->UCRSegments = UCRSegment;
04070
04071
04072
04073
04074
04075 UCRSegment->
ReservedSize = ReserveSize;
04076 UCRSegment->
CommittedSize = CommitSize;
04077
04078
04079
04080
04081
04082 FirstEntry = (PCHAR)(UCRSegment + 1);
04083
04084 }
else {
04085
04086
04087
04088
04089
04090
04091
04092 CommitSize =
PAGE_SIZE;
04093 FirstEntry = (PCHAR)UCRSegment + UCRSegment->
CommittedSize;
04094
04095
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
04096 &FirstEntry,
04097 0,
04098 &CommitSize,
04099 MEM_COMMIT,
04100 PAGE_READWRITE );
04101
04102
if (!
NT_SUCCESS(
Status )) {
04103
04104
return NULL;
04105 }
04106
04107
04108
04109
04110
04111 UCRSegment->
CommittedSize += CommitSize;
04112 }
04113
04114
04115
04116
04117
04118
04119
04120 LastEntry = (PCHAR)UCRSegment + UCRSegment->
CommittedSize;
04121
04122
04123
04124
04125
04126
04127
04128 UnCommittedRange = (
PHEAP_UNCOMMMTTED_RANGE)FirstEntry;
04129
04130 pp = &Segment->Heap->UnusedUnCommittedRanges;
04131
04132
while ((PCHAR)UnCommittedRange < (PCHAR)LastEntry) {
04133
04134 *pp = UnCommittedRange;
04135 pp = &UnCommittedRange->
Next;
04136 UnCommittedRange += 1;
04137 }
04138
04139
04140
04141
04142
04143 *pp =
NULL;
04144
04145
04146
04147
04148
04149 pp = &Segment->Heap->UnusedUnCommittedRanges;
04150 }
04151
04152
04153
04154
04155
04156
04157 UnCommittedRange = *pp;
04158 *pp = UnCommittedRange->
Next;
04159
04160
return UnCommittedRange;
04161 }
04162
04163
04164
04165
04166
04167
04168
VOID
04169 RtlpDestroyUnCommittedRange (
04170 IN
PHEAP_SEGMENT Segment,
04171 IN
PHEAP_UNCOMMMTTED_RANGE UnCommittedRange
04172 )
04173
04174
04175
04176
04177
04178
04179
04180
04181
04182
04183
04184
04185
04186
04187
04188
04189
04190
04191
04192
04193
04194
04195 {
04196
RTL_PAGED_CODE();
04197
04198
04199
04200
04201
04202
04203 UnCommittedRange->Next = Segment->Heap->UnusedUnCommittedRanges;
04204 Segment->Heap->UnusedUnCommittedRanges = UnCommittedRange;
04205
04206
04207
04208
04209
04210
04211 UnCommittedRange->Address = 0;
04212 UnCommittedRange->Size = 0;
04213
04214
04215
04216
04217
04218
return;
04219 }
04220
04221
04222
04223
04224
04225
04226
VOID
04227 RtlpInsertUnCommittedPages (
04228 IN
PHEAP_SEGMENT Segment,
04229 IN ULONG_PTR Address,
04230 IN SIZE_T Size
04231 )
04232
04233
04234
04235
04236
04237
04238
04239
04240
04241
04242
04243
04244
04245
04246
04247
04248
04249
04250
04251
04252
04253
04254
04255 {
04256
PHEAP_UNCOMMMTTED_RANGE UnCommittedRange, *pp;
04257
04258
RTL_PAGED_CODE();
04259
04260
04261
04262
04263
04264
04265 pp = &Segment->UnCommittedRanges;
04266
04267
04268
04269
04270
04271
04272
while (UnCommittedRange = *pp) {
04273
04274
04275
04276
04277
04278
04279
if (UnCommittedRange->
Address > Address) {
04280
04281
04282
04283
04284
04285
04286
04287
if ((Address +
Size) == UnCommittedRange->
Address) {
04288
04289 UnCommittedRange->
Address = Address;
04290 UnCommittedRange->
Size +=
Size;
04291
04292
04293
04294
04295
04296
04297
if (UnCommittedRange->
Size > Segment->LargestUnCommittedRange) {
04298
04299 Segment->LargestUnCommittedRange = UnCommittedRange->
Size;
04300 }
04301
04302
04303
04304
04305
04306
return;
04307 }
04308
04309
04310
04311
04312
04313
04314
04315
break;
04316
04317
04318
04319
04320
04321
04322 }
else if ((UnCommittedRange->
Address + UnCommittedRange->
Size) == Address) {
04323
04324
04325
04326
04327
04328 Address = UnCommittedRange->
Address;
04329
Size += UnCommittedRange->
Size;
04330
04331
04332
04333
04334
04335
04336 *pp = UnCommittedRange->
Next;
04337
04338
RtlpDestroyUnCommittedRange( Segment, UnCommittedRange );
04339
04340
04341
04342
04343
04344
04345
04346
04347 Segment->NumberOfUnCommittedRanges -= 1;
04348
04349
if (
Size > Segment->LargestUnCommittedRange) {
04350
04351 Segment->LargestUnCommittedRange =
Size;
04352 }
04353
04354
04355
04356
04357
04358 }
else {
04359
04360 pp = &UnCommittedRange->
Next;
04361 }
04362 }
04363
04364
04365
04366
04367
04368
04369
04370
04371
04372
04373
04374 UnCommittedRange =
RtlpCreateUnCommittedRange( Segment );
04375
04376
if (UnCommittedRange ==
NULL) {
04377
04378
HeapDebugPrint((
"Abandoning uncommitted range (%x for %x)\n", Address,
Size ));
04379
04380
04381
return;
04382 }
04383
04384
04385
04386
04387
04388 UnCommittedRange->
Address = Address;
04389 UnCommittedRange->
Size =
Size;
04390
04391
04392
04393
04394
04395 UnCommittedRange->
Next = *pp;
04396 *pp = UnCommittedRange;
04397
04398
04399
04400
04401
04402 Segment->NumberOfUnCommittedRanges += 1;
04403
04404
if (
Size >= Segment->LargestUnCommittedRange) {
04405
04406 Segment->LargestUnCommittedRange =
Size;
04407 }
04408
04409
04410
04411
04412
04413
return;
04414 }
04415
04416
04417
04418
04419
04420
04421
PHEAP_FREE_ENTRY
04422 RtlpFindAndCommitPages (
04423 IN
PHEAP Heap,
04424 IN
PHEAP_SEGMENT Segment,
04425 IN OUT PSIZE_T Size,
04426 IN PVOID AddressWanted OPTIONAL
04427 )
04428
04429
04430
04431
04432
04433
04434
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447
04448
04449
04450
04451
04452
04453
04454
04455
04456
04457 {
04458
NTSTATUS Status;
04459
PHEAP_ENTRY FirstEntry, LastEntry, PreviousLastEntry;
04460
PHEAP_UNCOMMMTTED_RANGE PreviousUnCommittedRange, UnCommittedRange, *pp;
04461 ULONG_PTR Address;
04462 SIZE_T Length;
04463
04464
RTL_PAGED_CODE();
04465
04466
04467
04468
04469
04470
04471 PreviousUnCommittedRange =
NULL;
04472 pp = &Segment->UnCommittedRanges;
04473
04474
while (UnCommittedRange = *pp) {
04475
04476
04477
04478
04479
04480
04481
04482
if ((UnCommittedRange->
Size >= *
Size) &&
04483 (!ARGUMENT_PRESENT( AddressWanted ) || (UnCommittedRange->
Address == (ULONG_PTR)AddressWanted ))) {
04484
04485
04486
04487
04488
04489 Address = UnCommittedRange->
Address;
04490
04491
04492
04493
04494
04495
04496
if (Heap->CommitRoutine !=
NULL) {
04497
04498
Status = (Heap->CommitRoutine)( Heap,
04499 (PVOID *)&Address,
04500
Size );
04501
04502 }
else {
04503
04504
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
04505 (PVOID *)&Address,
04506 0,
04507
Size,
04508 MEM_COMMIT,
04509 PAGE_READWRITE );
04510
04511 }
04512
04513
if (!
NT_SUCCESS(
Status )) {
04514
04515
return NULL;
04516 }
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526 Segment->NumberOfUnCommittedPages -= (ULONG) (*
Size /
PAGE_SIZE);
04527
04528
if (Segment->LargestUnCommittedRange == UnCommittedRange->
Size) {
04529
04530 Segment->LargestUnCommittedRange = 0;
04531 }
04532
04533
04534
04535
04536
04537 FirstEntry = (
PHEAP_ENTRY)Address;
04538
04539
04540
04541
04542
04543
04544
04545
04546
04547
04548
if ((Segment->LastEntryInSegment->Flags &
HEAP_ENTRY_LAST_ENTRY) &&
04549 (ULONG_PTR)(Segment->LastEntryInSegment + Segment->LastEntryInSegment->Size) == UnCommittedRange->
Address) {
04550
04551 LastEntry = Segment->LastEntryInSegment;
04552
04553 }
else {
04554
04555
if (PreviousUnCommittedRange ==
NULL) {
04556
04557 LastEntry = Segment->FirstEntry;
04558
04559 }
else {
04560
04561 LastEntry = (
PHEAP_ENTRY)(PreviousUnCommittedRange->
Address +
04562 PreviousUnCommittedRange->
Size);
04563 }
04564
04565
04566
04567
04568
04569
04570
while (!(LastEntry->
Flags &
HEAP_ENTRY_LAST_ENTRY)) {
04571
04572 PreviousLastEntry = LastEntry;
04573 LastEntry += LastEntry->
Size;
04574
04575
if (((PCHAR)LastEntry >= (PCHAR)Segment->LastValidEntry) || (LastEntry->Size == 0)) {
04576
04577
04578
04579
04580
04581
04582
04583
if (LastEntry == (
PHEAP_ENTRY)Address) {
04584
04585 LastEntry = PreviousLastEntry;
04586
04587
break;
04588 }
04589
04590
HeapDebugPrint((
"Heap missing last entry in committed range near %x\n", PreviousLastEntry ));
04591
HeapDebugBreak( PreviousLastEntry );
04592
04593
return NULL;
04594 }
04595 }
04596 }
04597
04598
04599
04600
04601
04602
04603 LastEntry->
Flags &= ~
HEAP_ENTRY_LAST_ENTRY;
04604
04605
04606
04607
04608
04609 UnCommittedRange->
Address += *
Size;
04610 UnCommittedRange->
Size -= *
Size;
04611
04612
04613
04614
04615
04616
04617
04618
if (UnCommittedRange->
Size == 0) {
04619
04620
04621
04622
04623
04624
04625
04626
if (UnCommittedRange->
Address == (ULONG_PTR)Segment->LastValidEntry) {
04627
04628 FirstEntry->
Flags =
HEAP_ENTRY_LAST_ENTRY;
04629
04630 Segment->LastEntryInSegment = FirstEntry;
04631
04632 }
else {
04633
04634 FirstEntry->
Flags = 0;
04635
04636 Segment->LastEntryInSegment = Segment->FirstEntry;
04637 }
04638
04639
04640
04641
04642
04643
04644 *pp = UnCommittedRange->
Next;
04645
04646
RtlpDestroyUnCommittedRange( Segment, UnCommittedRange );
04647
04648 Segment->NumberOfUnCommittedRanges -= 1;
04649
04650 }
else {
04651
04652
04653
04654
04655
04656
04657 FirstEntry->
Flags =
HEAP_ENTRY_LAST_ENTRY;
04658
04659 Segment->LastEntryInSegment = FirstEntry;
04660 }
04661
04662
04663
04664
04665
04666
04667 FirstEntry->
SegmentIndex = LastEntry->
SegmentIndex;
04668 FirstEntry->
Size = (
USHORT)(*
Size >>
HEAP_GRANULARITY_SHIFT);
04669 FirstEntry->
PreviousSize = LastEntry->
Size;
04670
04671
if (!(FirstEntry->
Flags &
HEAP_ENTRY_LAST_ENTRY)) {
04672
04673 (FirstEntry + FirstEntry->
Size)->PreviousSize = FirstEntry->
Size;
04674 }
04675
04676
04677
04678
04679
04680
04681
04682
04683
if (Segment->LargestUnCommittedRange == 0) {
04684
04685 UnCommittedRange = Segment->UnCommittedRanges;
04686
04687
while (UnCommittedRange !=
NULL) {
04688
04689
if (UnCommittedRange->
Size >= Segment->LargestUnCommittedRange) {
04690
04691 Segment->LargestUnCommittedRange = UnCommittedRange->
Size;
04692 }
04693
04694 UnCommittedRange = UnCommittedRange->
Next;
04695 }
04696 }
04697
04698
04699
04700
04701
04702
return (
PHEAP_FREE_ENTRY)FirstEntry;
04703
04704 }
else {
04705
04706
04707
04708
04709
04710
04711
04712 PreviousUnCommittedRange = UnCommittedRange;
04713 pp = &UnCommittedRange->
Next;
04714 }
04715 }
04716
04717
04718
04719
04720
04721
04722
04723
return NULL;
04724 }
04725
04726
04727
04728
04729
04730
04731 BOOLEAN
04732 RtlpInitializeHeapSegment (
04733 IN
PHEAP Heap,
04734 IN
PHEAP_SEGMENT Segment,
04735 IN UCHAR SegmentIndex,
04736 IN ULONG Flags,
04737 IN PVOID BaseAddress,
04738 IN PVOID UnCommittedAddress,
04739 IN PVOID CommitLimitAddress
04740 )
04741
04742
04743
04744
04745
04746
04747
04748
04749
04750
04751
04752
04753
04754
04755
04756
04757
04758
04759
04760
04761
04762
04763
04764
04765
04766
04767
04768
04769
04770
04771
04772
04773
04774
04775
04776 {
04777
NTSTATUS Status;
04778
PHEAP_ENTRY FirstEntry;
04779
USHORT PreviousSize,
Size;
04780 ULONG NumberOfPages;
04781 ULONG NumberOfCommittedPages;
04782 ULONG NumberOfUnCommittedPages;
04783 SIZE_T CommitSize;
04784 ULONG
NtGlobalFlag =
RtlGetNtGlobalFlags();
04785
04786
RTL_PAGED_CODE();
04787
04788
04789
04790
04791
04792 NumberOfPages = (ULONG) (((PCHAR)CommitLimitAddress - (PCHAR)BaseAddress) /
PAGE_SIZE);
04793
04794
04795
04796
04797
04798
04799 FirstEntry = (
PHEAP_ENTRY)
ROUND_UP_TO_POWER2( Segment + 1,
04800
HEAP_GRANULARITY );
04801
04802
04803
04804
04805
04806
04807
04808
if ((PVOID)Heap == BaseAddress) {
04809
04810 PreviousSize = Heap->Entry.Size;
04811
04812 }
else {
04813
04814 PreviousSize = 0;
04815 }
04816
04817
04818
04819
04820
04821
Size = (
USHORT)(((PCHAR)FirstEntry - (PCHAR)Segment) >>
HEAP_GRANULARITY_SHIFT);
04822
04823
04824
04825
04826
04827
04828
if ((PCHAR)(FirstEntry + 1) >= (PCHAR)UnCommittedAddress) {
04829
04830
if ((PCHAR)(FirstEntry + 1) >= (PCHAR)CommitLimitAddress) {
04831
04832
return FALSE;
04833 }
04834
04835
04836
04837
04838
04839
04840 CommitSize = (PCHAR)(FirstEntry + 1) - (PCHAR)UnCommittedAddress;
04841
04842
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
04843 (PVOID *)&UnCommittedAddress,
04844 0,
04845 &CommitSize,
04846 MEM_COMMIT,
04847 PAGE_READWRITE );
04848
04849
if (!
NT_SUCCESS(
Status )) {
04850
04851
return FALSE;
04852 }
04853
04854
04855
04856
04857
04858
04859 UnCommittedAddress = (PVOID)((PCHAR)UnCommittedAddress + CommitSize);
04860 }
04861
04862
04863
04864
04865
04866
04867
04868
04869
04870 NumberOfUnCommittedPages = (ULONG)(((PCHAR)CommitLimitAddress - (PCHAR)UnCommittedAddress) /
PAGE_SIZE);
04871 NumberOfCommittedPages = NumberOfPages - NumberOfUnCommittedPages;
04872
04873
04874
04875
04876
04877
04878 Segment->Entry.PreviousSize = PreviousSize;
04879 Segment->Entry.Size =
Size;
04880 Segment->Entry.Flags =
HEAP_ENTRY_BUSY;
04881 Segment->Entry.SegmentIndex = SegmentIndex;
04882
04883
#if i386 && !NTOS_KERNEL_RUNTIME
04884
04885
04886
04887
04888
04889
04890
if (
NtGlobalFlag & FLG_USER_STACK_TRACE_DB) {
04891
04892 Segment->AllocatorBackTraceIndex = (
USHORT)RtlLogStackBackTrace();
04893 }
04894
04895
#endif // i386 && !NTOS_KERNEL_RUNTIME
04896
04897
04898
04899
04900
04901 Segment->Signature =
HEAP_SEGMENT_SIGNATURE;
04902 Segment->Flags = Flags;
04903 Segment->Heap = Heap;
04904 Segment->BaseAddress = BaseAddress;
04905 Segment->FirstEntry = FirstEntry;
04906 Segment->LastValidEntry = (
PHEAP_ENTRY)((PCHAR)BaseAddress + (NumberOfPages *
PAGE_SIZE));
04907 Segment->NumberOfPages = NumberOfPages;
04908 Segment->NumberOfUnCommittedPages = NumberOfUnCommittedPages;
04909
04910
04911
04912
04913
04914
04915
if (NumberOfUnCommittedPages) {
04916
04917
RtlpInsertUnCommittedPages( Segment,
04918 (ULONG_PTR)UnCommittedAddress,
04919 NumberOfUnCommittedPages *
PAGE_SIZE );
04920 }
04921
04922
04923
04924
04925
04926 Heap->Segments[ SegmentIndex ] = Segment;
04927
04928
04929
04930
04931
04932
04933
04934 PreviousSize = Segment->Entry.Size;
04935 FirstEntry->
Flags =
HEAP_ENTRY_LAST_ENTRY;
04936
04937 Segment->LastEntryInSegment = FirstEntry;
04938
04939 FirstEntry->
PreviousSize = PreviousSize;
04940 FirstEntry->
SegmentIndex = SegmentIndex;
04941
04942
RtlpInsertFreeBlock( Heap,
04943 (
PHEAP_FREE_ENTRY)FirstEntry,
04944 (
PHEAP_ENTRY)UnCommittedAddress - FirstEntry);
04945
04946
04947
04948
04949
04950
return TRUE;
04951 }
04952
04953
04954
04955
04956
04957
04958
NTSTATUS
04959 RtlpDestroyHeapSegment (
04960 IN
PHEAP_SEGMENT Segment
04961 )
04962
04963
04964
04965
04966
04967
04968
04969
04970
04971
04972
04973
04974
04975
04976
04977
04978
04979
04980 {
04981 PVOID BaseAddress;
04982 SIZE_T BytesToFree;
04983
04984
RTL_PAGED_CODE();
04985
04986
04987
04988
04989
04990
04991
04992
if (!(Segment->Flags &
HEAP_SEGMENT_USER_ALLOCATED)) {
04993
04994 BaseAddress = Segment->BaseAddress;
04995 BytesToFree = 0;
04996
04997
04998
04999
05000
05001
05002
return ZwFreeVirtualMemory( NtCurrentProcess(),
05003 (PVOID *)&BaseAddress,
05004 &BytesToFree,
05005 MEM_RELEASE );
05006
05007 }
else {
05008
05009
05010
05011
05012
05013
return STATUS_SUCCESS;
05014 }
05015 }
05016
05017
05018
05019
05020
05021
05022
05023
PHEAP_FREE_ENTRY
05024 RtlpExtendHeap (
05025 IN
PHEAP Heap,
05026 IN SIZE_T AllocationSize
05027 )
05028
05029
05030
05031
05032
05033
05034
05035
05036
05037
05038
05039
05040
05041
05042
05043
05044
05045
05046
05047
05048
05049 {
05050
NTSTATUS Status;
05051
PHEAP_SEGMENT Segment;
05052
PHEAP_FREE_ENTRY FreeBlock;
05053 UCHAR SegmentIndex, EmptySegmentIndex;
05054 ULONG NumberOfPages;
05055 SIZE_T CommitSize;
05056 SIZE_T ReserveSize;
05057 SIZE_T FreeSize;
05058
05059
RTL_PAGED_CODE();
05060
05061
05062
05063
05064
05065
05066
05067 NumberOfPages = (ULONG) ((AllocationSize +
PAGE_SIZE - 1) /
PAGE_SIZE);
05068 FreeSize = NumberOfPages *
PAGE_SIZE;
05069
05070
05071
05072
05073
05074
05075
05076
05077 EmptySegmentIndex =
HEAP_MAXIMUM_SEGMENTS;
05078
05079
for (SegmentIndex=0; SegmentIndex<
HEAP_MAXIMUM_SEGMENTS; SegmentIndex++) {
05080
05081 Segment = Heap->Segments[ SegmentIndex ];
05082
05083
05084
05085
05086
05087
05088
05089
05090
05091
05092
if ((Segment) &&
05093 (NumberOfPages <= Segment->
NumberOfUnCommittedPages) &&
05094 (FreeSize <= Segment->
LargestUnCommittedRange)) {
05095
05096
05097
05098
05099
05100
05101 FreeBlock =
RtlpFindAndCommitPages( Heap,
05102 Segment,
05103 &FreeSize,
05104
NULL );
05105
05106
05107
05108
05109
05110
05111
05112
if (FreeBlock !=
NULL) {
05113
05114
05115
05116
05117
05118
05119
05120 FreeSize = FreeSize >>
HEAP_GRANULARITY_SHIFT;
05121
05122 FreeBlock =
RtlpCoalesceFreeBlocks( Heap, FreeBlock, &FreeSize,
FALSE );
05123
05124
RtlpInsertFreeBlock( Heap, FreeBlock, FreeSize );
05125
05126
return FreeBlock;
05127 }
05128
05129
05130
05131
05132
05133
05134
05135 }
else if ((Segment ==
NULL) &&
05136 (EmptySegmentIndex ==
HEAP_MAXIMUM_SEGMENTS)) {
05137
05138 EmptySegmentIndex = SegmentIndex;
05139 }
05140 }
05141
05142
05143
05144
05145
05146
05147
05148
if ((EmptySegmentIndex !=
HEAP_MAXIMUM_SEGMENTS) &&
05149 (Heap->Flags & HEAP_GROWABLE)) {
05150
05151 Segment =
NULL;
05152
05153
05154
05155
05156
05157
05158
05159
if ((AllocationSize +
PAGE_SIZE) > Heap->SegmentReserve) {
05160
05161 ReserveSize = AllocationSize +
PAGE_SIZE;
05162
05163 }
else {
05164
05165 ReserveSize = Heap->SegmentReserve;
05166 }
05167
05168
05169
05170
05171
05172
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
05173 (PVOID *)&Segment,
05174 0,
05175 &ReserveSize,
05176 MEM_RESERVE,
05177 PAGE_READWRITE );
05178
05179
05180
05181
05182
05183
05184
05185
05186
05187
while ((!
NT_SUCCESS(
Status )) && (ReserveSize != (AllocationSize +
PAGE_SIZE))) {
05188
05189 ReserveSize = ReserveSize / 2;
05190
05191
if( ReserveSize < (AllocationSize +
PAGE_SIZE) ) {
05192
05193 ReserveSize = (AllocationSize +
PAGE_SIZE);
05194 }
05195
05196
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
05197 (PVOID *)&Segment,
05198 0,
05199 &ReserveSize,
05200 MEM_RESERVE,
05201 PAGE_READWRITE );
05202 }
05203
05204
if (
NT_SUCCESS(
Status )) {
05205
05206
05207
05208
05209
05210 Heap->SegmentReserve += ReserveSize;
05211
05212
05213
05214
05215
05216
05217
05218
if ((AllocationSize +
PAGE_SIZE) > Heap->SegmentCommit) {
05219
05220 CommitSize = AllocationSize +
PAGE_SIZE;
05221
05222 }
else {
05223
05224 CommitSize = Heap->SegmentCommit;
05225 }
05226
05227
05228
05229
05230
05231
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
05232 (PVOID *)&Segment,
05233 0,
05234 &CommitSize,
05235 MEM_COMMIT,
05236 PAGE_READWRITE );
05237
05238
05239
05240
05241
05242
05243
05244
if (
NT_SUCCESS(
Status ) &&
05245 !
RtlpInitializeHeapSegment( Heap,
05246 Segment,
05247 EmptySegmentIndex,
05248 0,
05249 Segment,
05250 (PCHAR)Segment + CommitSize,
05251 (PCHAR)Segment + ReserveSize)) {
05252
05253
Status = STATUS_NO_MEMORY;
05254 }
05255
05256
05257
05258
05259
05260
05261
if (
NT_SUCCESS(
Status)) {
05262
05263
return (
PHEAP_FREE_ENTRY)Segment->FirstEntry;
05264 }
05265
05266
05267
05268
05269
05270
05271 ZwFreeVirtualMemory( NtCurrentProcess(),
05272 (PVOID *)&Segment,
05273 &ReserveSize,
05274 MEM_RELEASE );
05275 }
05276 }
05277
05278
#ifndef NTOS_KERNEL_RUNTIME
05279
05280
05281
05282
05283
05284
05285
05286
if (Heap->Flags & HEAP_DISABLE_COALESCE_ON_FREE) {
05287
05288 FreeBlock =
RtlpCoalesceHeap( Heap );
05289
05290
if ((FreeBlock !=
NULL) && (FreeBlock->
Size >= AllocationSize)) {
05291
05292
return FreeBlock;
05293 }
05294 }
05295
05296
#endif // NTOS_KERNEL_RUNTIME
05297
05298
05299
05300
05301
05302
05303
return NULL;
05304 }
05305
05306
05307
05308
05309
05310
05311
PHEAP_FREE_ENTRY
05312 RtlpCoalesceFreeBlocks (
05313 IN
PHEAP Heap,
05314 IN
PHEAP_FREE_ENTRY FreeBlock,
05315 IN OUT PSIZE_T FreeSize,
05316 IN BOOLEAN RemoveFromFreeList
05317 )
05318
05319
05320
05321
05322
05323
05324
05325
05326
05327
05328
05329
05330
05331
05332
05333
05334
05335
05336
05337
05338
05339
05340
05341
05342
05343 {
05344
PHEAP_FREE_ENTRY FreeBlock1, NextFreeBlock;
05345
05346
RTL_PAGED_CODE();
05347
05348
05349
05350
05351
05352 FreeBlock1 = (
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)FreeBlock - FreeBlock->PreviousSize);
05353
05354
05355
05356
05357
05358
05359
if ((FreeBlock1 != FreeBlock) &&
05360 !(FreeBlock1->
Flags &
HEAP_ENTRY_BUSY) &&
05361 ((*FreeSize + FreeBlock1->
Size) <=
HEAP_MAXIMUM_BLOCK_SIZE)) {
05362
05363
05364
05365
05366
05367
HEAPASSERT(FreeBlock->PreviousSize == FreeBlock1->
Size);
05368
05369
05370
05371
05372
05373
if (RemoveFromFreeList) {
05374
05375
RtlpRemoveFreeBlock( Heap, FreeBlock );
05376
05377 Heap->TotalFreeSize -= FreeBlock->Size;
05378
05379
05380
05381
05382
05383 RemoveFromFreeList =
FALSE;
05384 }
05385
05386
05387
05388
05389
05390
RtlpRemoveFreeBlock( Heap, FreeBlock1 );
05391
05392
05393
05394
05395
05396
05397 FreeBlock1->
Flags = FreeBlock->Flags &
HEAP_ENTRY_LAST_ENTRY;
05398
05399
if( FreeBlock1->
Flags &
HEAP_ENTRY_LAST_ENTRY ) {
05400
05401
PHEAP_SEGMENT Segment;
05402
05403 Segment = Heap->Segments[FreeBlock1->
SegmentIndex];
05404 Segment->
LastEntryInSegment = (
PHEAP_ENTRY)FreeBlock1;
05405 }
05406
05407
05408
05409
05410
05411
05412 FreeBlock = FreeBlock1;
05413
05414 *FreeSize += FreeBlock1->
Size;
05415
05416 Heap->TotalFreeSize -= FreeBlock1->Size;
05417
05418 FreeBlock->Size = (
USHORT)*FreeSize;
05419
05420
05421
05422
05423
05424
05425
if (!(FreeBlock->Flags &
HEAP_ENTRY_LAST_ENTRY)) {
05426
05427 ((
PHEAP_ENTRY)FreeBlock + *FreeSize)->PreviousSize = (
USHORT)*FreeSize;
05428 }
05429 }
05430
05431
05432
05433
05434
05435
if (!(FreeBlock->Flags &
HEAP_ENTRY_LAST_ENTRY)) {
05436
05437
05438
05439
05440
05441
05442
05443 NextFreeBlock = (
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)FreeBlock + *FreeSize);
05444
05445
if (!(NextFreeBlock->
Flags &
HEAP_ENTRY_BUSY) &&
05446 ((*FreeSize + NextFreeBlock->
Size) <=
HEAP_MAXIMUM_BLOCK_SIZE)) {
05447
05448
05449
05450
05451
05452
HEAPASSERT(*FreeSize == NextFreeBlock->
PreviousSize);
05453
05454
05455
05456
05457
05458
if (RemoveFromFreeList) {
05459
05460
RtlpRemoveFreeBlock( Heap, FreeBlock );
05461
05462 Heap->TotalFreeSize -= FreeBlock->Size;
05463
05464
05465
05466
05467
05468
05469 RemoveFromFreeList =
FALSE;
05470 }
05471
05472
05473
05474
05475
05476
05477 FreeBlock->Flags = NextFreeBlock->
Flags &
HEAP_ENTRY_LAST_ENTRY;
05478
05479
if( FreeBlock->Flags &
HEAP_ENTRY_LAST_ENTRY ) {
05480
05481
PHEAP_SEGMENT Segment;
05482
05483 Segment = Heap->Segments[FreeBlock->SegmentIndex];
05484 Segment->
LastEntryInSegment = (
PHEAP_ENTRY)FreeBlock;
05485 }
05486
05487
05488
05489
05490
05491
RtlpRemoveFreeBlock( Heap, NextFreeBlock );
05492
05493
05494
05495
05496
05497 *FreeSize += NextFreeBlock->
Size;
05498
05499 Heap->TotalFreeSize -= NextFreeBlock->
Size;
05500
05501 FreeBlock->Size = (
USHORT)*FreeSize;
05502
05503
05504
05505
05506
05507
if (!(FreeBlock->Flags &
HEAP_ENTRY_LAST_ENTRY)) {
05508
05509 ((
PHEAP_ENTRY)FreeBlock + *FreeSize)->PreviousSize = (
USHORT)*FreeSize;
05510 }
05511 }
05512 }
05513
05514
05515
05516
05517
05518
return FreeBlock;
05519 }
05520
05521
05522
05523
05524
05525
05526
VOID
05527 RtlpDeCommitFreeBlock (
05528 IN
PHEAP Heap,
05529 IN
PHEAP_FREE_ENTRY FreeBlock,
05530 IN SIZE_T FreeSize
05531 )
05532
05533
05534
05535
05536
05537
05538
05539
05540
05541
05542
05543
05544
05545
05546
05547
05548
05549
05550
05551
05552
05553
05554 {
05555
NTSTATUS Status;
05556 ULONG_PTR DeCommitAddress;
05557 SIZE_T DeCommitSize;
05558
USHORT LeadingFreeSize, TrailingFreeSize;
05559
PHEAP_SEGMENT Segment;
05560
PHEAP_FREE_ENTRY LeadingFreeBlock, TrailingFreeBlock;
05561
PHEAP_ENTRY LeadingBusyBlock, TrailingBusyBlock;
05562
PHEAP_UNCOMMMTTED_RANGE UnCommittedRange;
05563
05564
RTL_PAGED_CODE();
05565
05566
05567
05568
05569
05570
05571
05572
if (Heap->CommitRoutine !=
NULL) {
05573
05574
RtlpInsertFreeBlock( Heap, FreeBlock, FreeSize );
05575
05576
return;
05577 }
05578
05579
05580
05581
05582
05583 Segment = Heap->Segments[ FreeBlock->SegmentIndex ];
05584
05585
05586
05587
05588
05589
05590
05591
05592
05593
05594
05595
05596
05597 LeadingBusyBlock =
NULL;
05598 LeadingFreeBlock = FreeBlock;
05599
05600
05601
05602
05603
05604
05605
05606
05607 DeCommitAddress =
ROUND_UP_TO_POWER2( LeadingFreeBlock,
PAGE_SIZE );
05608 LeadingFreeSize = (
USHORT)((
PHEAP_ENTRY)DeCommitAddress - (
PHEAP_ENTRY)LeadingFreeBlock);
05609
05610
05611
05612
05613
05614
05615
05616
05617
05618
if (LeadingFreeSize == 1) {
05619
05620 DeCommitAddress +=
PAGE_SIZE;
05621 LeadingFreeSize +=
PAGE_SIZE >>
HEAP_GRANULARITY_SHIFT;
05622
05623 }
else if (LeadingFreeBlock->
PreviousSize != 0) {
05624
05625
if (DeCommitAddress == (ULONG_PTR)LeadingFreeBlock) {
05626
05627 LeadingBusyBlock = (
PHEAP_ENTRY)LeadingFreeBlock - LeadingFreeBlock->
PreviousSize;
05628 }
05629 }
05630
05631
05632
05633
05634
05635
05636
05637
05638
05639
05640
05641
05642 TrailingBusyBlock =
NULL;
05643 TrailingFreeBlock = (
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)FreeBlock + FreeSize);
05644
05645
05646
05647
05648
05649
05650
05651
05652 DeCommitSize =
ROUND_DOWN_TO_POWER2( (ULONG_PTR)TrailingFreeBlock,
PAGE_SIZE );
05653 TrailingFreeSize = (
USHORT)((
PHEAP_ENTRY)TrailingFreeBlock - (
PHEAP_ENTRY)DeCommitSize);
05654
05655
05656
05657
05658
05659
05660
05661
05662
05663
if (TrailingFreeSize == (
sizeof(
HEAP_ENTRY ) >>
HEAP_GRANULARITY_SHIFT)) {
05664
05665 DeCommitSize -=
PAGE_SIZE;
05666 TrailingFreeSize +=
PAGE_SIZE >>
HEAP_GRANULARITY_SHIFT;
05667
05668 }
else if ((TrailingFreeSize == 0) && !(FreeBlock->Flags &
HEAP_ENTRY_LAST_ENTRY)) {
05669
05670 TrailingBusyBlock = (
PHEAP_ENTRY)TrailingFreeBlock;
05671 }
05672
05673
05674
05675
05676
05677
05678 TrailingFreeBlock = (
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)TrailingFreeBlock - TrailingFreeSize);
05679
05680
05681
05682
05683
05684
05685
05686
if (DeCommitSize > DeCommitAddress) {
05687
05688 DeCommitSize -= DeCommitAddress;
05689
05690 }
else {
05691
05692 DeCommitSize = 0;
05693 }
05694
05695
05696
05697
05698
05699
05700
05701
if (DeCommitSize != 0) {
05702
05703
05704
05705
05706
05707
05708 UnCommittedRange =
RtlpCreateUnCommittedRange(Segment);
05709
05710
if (UnCommittedRange ==
NULL) {
05711
05712
HeapDebugPrint((
"Failing creating uncommitted range (%x for %x)\n", DeCommitAddress, DeCommitSize ));
05713
05714
05715
05716
05717
05718
05719
RtlpInsertFreeBlock( Heap, LeadingFreeBlock, FreeSize );
05720
05721
return;
05722 }
05723
05724
05725
05726
05727
05728
Status = ZwFreeVirtualMemory( NtCurrentProcess(),
05729 (PVOID *)&DeCommitAddress,
05730 &DeCommitSize,
05731 MEM_DECOMMIT );
05732
05733
05734
05735
05736
05737
RtlpDestroyUnCommittedRange( Segment, UnCommittedRange );
05738
05739
if (
NT_SUCCESS(
Status )) {
05740
05741
05742
05743
05744
05745
05746
RtlpInsertUnCommittedPages( Segment,
05747 DeCommitAddress,
05748 DeCommitSize );
05749
05750
05751
05752
05753 Segment->
NumberOfUnCommittedPages += (ULONG)(DeCommitSize /
PAGE_SIZE);
05754
05755
05756
05757
05758
05759
05760
if (LeadingFreeSize != 0) {
05761
05762 LeadingFreeBlock->
Flags =
HEAP_ENTRY_LAST_ENTRY;
05763 LeadingFreeBlock->
Size = LeadingFreeSize;
05764 Heap->TotalFreeSize += LeadingFreeSize;
05765
05766 Segment->
LastEntryInSegment = (
PHEAP_ENTRY)LeadingFreeBlock;
05767
05768
RtlpInsertFreeBlockDirect( Heap, LeadingFreeBlock, LeadingFreeSize );
05769
05770
05771
05772
05773
05774
05775 }
else if (LeadingBusyBlock !=
NULL) {
05776
05777 LeadingBusyBlock->
Flags |=
HEAP_ENTRY_LAST_ENTRY;
05778
05779 Segment->
LastEntryInSegment = LeadingBusyBlock;
05780
05781 }
else if ((Segment->
LastEntryInSegment >= (
PHEAP_ENTRY)DeCommitAddress)
05782 &&
05783 ((PCHAR)Segment->
LastEntryInSegment < ((PCHAR)DeCommitAddress + DeCommitSize))) {
05784
05785 Segment->
LastEntryInSegment = Segment->
FirstEntry;
05786 }
05787
05788
05789
05790
05791
05792
05793
if (TrailingFreeSize != 0) {
05794
05795 TrailingFreeBlock->
PreviousSize = 0;
05796 TrailingFreeBlock->SegmentIndex = Segment->
Entry.
SegmentIndex;
05797 TrailingFreeBlock->Flags = 0;
05798 TrailingFreeBlock->Size = TrailingFreeSize;
05799
05800 ((
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)TrailingFreeBlock + TrailingFreeSize))->PreviousSize = (
USHORT)TrailingFreeSize;
05801
05802
RtlpInsertFreeBlockDirect( Heap, TrailingFreeBlock, TrailingFreeSize );
05803
05804 Heap->TotalFreeSize += TrailingFreeSize;
05805
05806
05807
05808
05809
05810
05811 }
else if (TrailingBusyBlock !=
NULL) {
05812
05813 TrailingBusyBlock->
PreviousSize = 0;
05814 }
05815
05816 }
else {
05817
05818
05819
05820
05821
05822
05823
RtlpInsertFreeBlock( Heap, LeadingFreeBlock, FreeSize );
05824 }
05825
05826 }
else {
05827
05828
05829
05830
05831
05832
05833
RtlpInsertFreeBlock( Heap, LeadingFreeBlock, FreeSize );
05834 }
05835
05836
05837
05838
05839
05840
return;
05841 }
05842
05843
05844
05845
05846
05847
05848
VOID
05849 RtlpInsertFreeBlock (
05850 IN
PHEAP Heap,
05851 IN
PHEAP_FREE_ENTRY FreeBlock,
05852 IN SIZE_T FreeSize
05853 )
05854
05855
05856
05857
05858
05859
05860
05861
05862
05863
05864
05865
05866
05867
05868
05869
05870
05871
05872
05873
05874
05875
05876
05877
05878
05879 {
05880
USHORT PreviousSize,
Size;
05881 UCHAR Flags;
05882 UCHAR SegmentIndex;
05883
PHEAP_SEGMENT Segment;
05884
05885
RTL_PAGED_CODE();
05886
05887
05888
05889
05890
05891
05892 PreviousSize = FreeBlock->PreviousSize;
05893
05894 SegmentIndex = FreeBlock->SegmentIndex;
05895 Segment = Heap->Segments[ SegmentIndex ];
05896
05897 Flags = FreeBlock->
Flags;
05898
05899
05900
05901
05902
05903 Heap->TotalFreeSize += FreeSize;
05904
05905
05906
05907
05908
05909
05910
while (FreeSize != 0) {
05911
05912
05913
05914
05915
05916
05917
if (FreeSize > (ULONG)
HEAP_MAXIMUM_BLOCK_SIZE) {
05918
05919
Size =
HEAP_MAXIMUM_BLOCK_SIZE;
05920
05921
05922
05923
05924
05925
05926
05927
if (FreeSize == ((ULONG)
HEAP_MAXIMUM_BLOCK_SIZE + 1)) {
05928
05929
Size -= 16;
05930 }
05931
05932
05933
05934
05935
05936
05937 FreeBlock->Flags = 0;
05938
05939 }
else {
05940
05941
Size = (
USHORT)FreeSize;
05942
05943
05944
05945
05946
05947 FreeBlock->Flags = Flags;
05948 }
05949
05950
05951
05952
05953
05954
05955 FreeBlock->PreviousSize = PreviousSize;
05956 FreeBlock->SegmentIndex = SegmentIndex;
05957 FreeBlock->Size =
Size;
05958
05959
RtlpInsertFreeBlockDirect( Heap, FreeBlock,
Size );
05960
05961
05962
05963
05964
05965
05966
05967 PreviousSize =
Size;
05968
05969 FreeSize -=
Size;
05970 FreeBlock = (
PHEAP_FREE_ENTRY)((
PHEAP_ENTRY)FreeBlock +
Size);
05971
05972
05973
05974
05975
05976
05977
05978
05979
if ((
PHEAP_ENTRY)FreeBlock >= Segment->
LastValidEntry) {
05980
05981
return;
05982 }
05983 }
05984
05985
05986
05987
05988
05989
05990
if (!(Flags &
HEAP_ENTRY_LAST_ENTRY)) {
05991
05992 FreeBlock->PreviousSize = PreviousSize;
05993 }
05994
05995
05996
05997
05998
05999
return;
06000 }
06001
06002
06003
06004
06005
06006
06007
PHEAP_ENTRY_EXTRA
06008 RtlpGetExtraStuffPointer (
06009
PHEAP_ENTRY BusyBlock
06010 )
06011
06012
06013
06014
06015
06016
06017
06018
06019
06020
06021
06022
06023
06024
06025
06026
06027
06028
06029
06030 {
06031 ULONG AllocationIndex;
06032
06033
06034
06035
06036
06037
06038
if (BusyBlock->
Flags &
HEAP_ENTRY_VIRTUAL_ALLOC) {
06039
06040
PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
06041
06042 VirtualAllocBlock = CONTAINING_RECORD( BusyBlock,
HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
06043
06044
return &VirtualAllocBlock->
ExtraStuff;
06045
06046 }
else {
06047
06048
06049
06050
06051
06052
06053
06054
06055
06056
06057
06058 AllocationIndex = BusyBlock->
Size;
06059
06060
return (
PHEAP_ENTRY_EXTRA)(BusyBlock + AllocationIndex - 1);
06061 }
06062 }
06063
06064
06065
06066
06067
06068
06069 SIZE_T
06070 RtlpGetSizeOfBigBlock (
06071 IN
PHEAP_ENTRY BusyBlock
06072 )
06073
06074
06075
06076
06077
06078
06079
06080
06081
06082
06083
06084
06085
06086
06087
06088
06089
06090
06091 {
06092
PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
06093
06094
RTL_PAGED_CODE();
06095
06096
06097
06098
06099
06100 VirtualAllocBlock = CONTAINING_RECORD( BusyBlock,
HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
06101
06102
06103
06104
06105
06106
06107
06108
return VirtualAllocBlock->
CommitSize - BusyBlock->Size;
06109 }
06110
06111
06112
06113
06114
06115
06116 BOOLEAN
06117 RtlpCheckBusyBlockTail (
06118 IN
PHEAP_ENTRY BusyBlock
06119 )
06120
06121
06122
06123
06124
06125
06126
06127
06128
06129
06130
06131
06132
06133
06134
06135
06136
06137
06138
06139 {
06140 PCHAR Tail;
06141 SIZE_T
Size, cbEqual;
06142
06143
RTL_PAGED_CODE();
06144
06145
06146
06147
06148
06149
if (BusyBlock->Flags &
HEAP_ENTRY_VIRTUAL_ALLOC) {
06150
06151
Size =
RtlpGetSizeOfBigBlock( BusyBlock );
06152
06153 }
else {
06154
06155
Size = (BusyBlock->Size <<
HEAP_GRANULARITY_SHIFT) - BusyBlock->UnusedBytes;
06156 }
06157
06158
06159
06160
06161
06162
06163 Tail = (PCHAR)(BusyBlock + 1) +
Size;
06164
06165
06166
06167
06168
06169 cbEqual = RtlCompareMemory( Tail,
06170
CheckHeapFillPattern,
06171
CHECK_HEAP_TAIL_SIZE );
06172
06173
06174
06175
06176
06177
06178
06179
if (cbEqual !=
CHECK_HEAP_TAIL_SIZE) {
06180
06181
06182
06183
06184
06185
HeapDebugPrint((
"Heap block at %p modified at %p past requested size of %lx\n",
06186 BusyBlock,
06187 Tail + cbEqual,
06188
Size ));
06189
06190
HeapDebugBreak( BusyBlock );
06191
06192
06193
06194
06195
06196
return FALSE;
06197
06198 }
else {
06199
06200
06201
06202
06203
06204
return TRUE;
06205 }
06206 }