Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

heapdll.c

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

Generated on Sat May 15 19:40:16 2004 for test by doxygen 1.3.7