Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenheappage.c
Go to the documentation of this file.
00001 /* COPYRIGHT: See COPYING in the top level directory 00002 * PROJECT: ReactOS system libraries 00003 * FILE: lib/rtl/heappage.c 00004 * PURPOSE: RTL Page Heap implementation 00005 * PROGRAMMERS: Copyright 2011 Aleksey Bragin 00006 */ 00007 00008 /* Useful references: 00009 http://msdn.microsoft.com/en-us/library/ms220938(VS.80).aspx 00010 http://blogs.msdn.com/b/jiangyue/archive/2010/03/16/windows-heap-overrun-monitoring.aspx 00011 */ 00012 00013 /* INCLUDES *****************************************************************/ 00014 00015 #include <rtl.h> 00016 #include <heap.h> 00017 00018 #define NDEBUG 00019 #include <debug.h> 00020 00021 /* TYPES **********************************************************************/ 00022 00023 typedef struct _DPH_BLOCK_INFORMATION 00024 { 00025 ULONG StartStamp; 00026 PVOID Heap; 00027 SIZE_T RequestedSize; 00028 SIZE_T ActualSize; 00029 union 00030 { 00031 LIST_ENTRY FreeQueue; 00032 SINGLE_LIST_ENTRY FreePushList; 00033 WORD TraceIndex; 00034 }; 00035 PVOID StackTrace; 00036 ULONG EndStamp; 00037 } DPH_BLOCK_INFORMATION, *PDPH_BLOCK_INFORMATION; 00038 00039 typedef struct _DPH_HEAP_BLOCK 00040 { 00041 union 00042 { 00043 struct _DPH_HEAP_BLOCK *pNextAlloc; 00044 LIST_ENTRY AvailableEntry; 00045 RTL_BALANCED_LINKS TableLinks; 00046 }; 00047 PUCHAR pUserAllocation; 00048 PUCHAR pVirtualBlock; 00049 SIZE_T nVirtualBlockSize; 00050 SIZE_T nVirtualAccessSize; 00051 SIZE_T nUserRequestedSize; 00052 SIZE_T nUserActualSize; 00053 PVOID UserValue; 00054 ULONG UserFlags; 00055 PRTL_TRACE_BLOCK StackTrace; 00056 LIST_ENTRY AdjacencyEntry; 00057 PUCHAR pVirtualRegion; 00058 } DPH_HEAP_BLOCK, *PDPH_HEAP_BLOCK; 00059 00060 typedef struct _DPH_HEAP_ROOT 00061 { 00062 ULONG Signature; 00063 ULONG HeapFlags; 00064 PRTL_CRITICAL_SECTION HeapCritSect; 00065 ULONG nRemoteLockAcquired; 00066 00067 PDPH_HEAP_BLOCK pVirtualStorageListHead; 00068 PDPH_HEAP_BLOCK pVirtualStorageListTail; 00069 ULONG nVirtualStorageRanges; 00070 SIZE_T nVirtualStorageBytes; 00071 00072 RTL_AVL_TABLE BusyNodesTable; 00073 PDPH_HEAP_BLOCK NodeToAllocate; 00074 ULONG nBusyAllocations; 00075 SIZE_T nBusyAllocationBytesCommitted; 00076 00077 PDPH_HEAP_BLOCK pFreeAllocationListHead; 00078 PDPH_HEAP_BLOCK pFreeAllocationListTail; 00079 ULONG nFreeAllocations; 00080 SIZE_T nFreeAllocationBytesCommitted; 00081 00082 LIST_ENTRY AvailableAllocationHead; 00083 ULONG nAvailableAllocations; 00084 SIZE_T nAvailableAllocationBytesCommitted; 00085 00086 PDPH_HEAP_BLOCK pUnusedNodeListHead; 00087 PDPH_HEAP_BLOCK pUnusedNodeListTail; 00088 ULONG nUnusedNodes; 00089 SIZE_T nBusyAllocationBytesAccessible; 00090 PDPH_HEAP_BLOCK pNodePoolListHead; 00091 PDPH_HEAP_BLOCK pNodePoolListTail; 00092 ULONG nNodePools; 00093 SIZE_T nNodePoolBytes; 00094 00095 LIST_ENTRY NextHeap; 00096 ULONG ExtraFlags; 00097 ULONG Seed; 00098 PVOID NormalHeap; 00099 PRTL_TRACE_BLOCK CreateStackTrace; 00100 PVOID FirstThread; 00101 } DPH_HEAP_ROOT, *PDPH_HEAP_ROOT; 00102 00103 /* GLOBALS ********************************************************************/ 00104 00105 BOOLEAN RtlpPageHeapEnabled = FALSE; 00106 ULONG RtlpDphGlobalFlags; 00107 ULONG RtlpPageHeapSizeRangeStart, RtlpPageHeapSizeRangeEnd; 00108 ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd; 00109 WCHAR RtlpDphTargetDlls[512]; 00110 00111 LIST_ENTRY RtlpDphPageHeapList; 00112 BOOLEAN RtlpDphPageHeapListInitialized; 00113 RTL_CRITICAL_SECTION RtlpDphPageHeapListLock; 00114 ULONG RtlpDphPageHeapListLength; 00115 UNICODE_STRING RtlpDphTargetDllsUnicode; 00116 00117 RTL_CRITICAL_SECTION RtlpDphDelayedFreeQueueLock; 00118 LIST_ENTRY RtlpDphDelayedFreeQueue; 00119 SLIST_HEADER RtlpDphDelayedTemporaryPushList; 00120 SIZE_T RtlpDphMemoryUsedByDelayedFreeBlocks; 00121 ULONG RtlpDphNumberOfDelayedFreeBlocks; 00122 00123 /* Counters */ 00124 LONG RtlpDphCounter; 00125 LONG RtlpDphAllocFails; 00126 LONG RtlpDphReleaseFails; 00127 LONG RtlpDphFreeFails; 00128 LONG RtlpDphProtectFails; 00129 00130 #define DPH_RESERVE_SIZE 0x100000 00131 #define DPH_POOL_SIZE 0x4000 00132 #define DPH_FREE_LIST_MINIMUM 8 00133 00134 /* RtlpDphBreakOptions */ 00135 #define DPH_BREAK_ON_RESERVE_FAIL 0x01 00136 #define DPH_BREAK_ON_COMMIT_FAIL 0x02 00137 #define DPH_BREAK_ON_RELEASE_FAIL 0x04 00138 #define DPH_BREAK_ON_FREE_FAIL 0x08 00139 #define DPH_BREAK_ON_PROTECT_FAIL 0x10 00140 #define DPH_BREAK_ON_NULL_FREE 0x80 00141 00142 /* RtlpDphDebugOptions */ 00143 #define DPH_DEBUG_INTERNAL_VALIDATE 0x01 00144 #define DPH_DEBUG_VERBOSE 0x04 00145 00146 /* DPH ExtraFlags */ 00147 #define DPH_EXTRA_LOG_STACK_TRACES 0x02 00148 #define DPH_EXTRA_CHECK_UNDERRUN 0x10 00149 00150 /* Fillers */ 00151 #define DPH_FILL 0xEEEEEEEE 00152 #define DPH_FILL_START_STAMP_1 0xABCDBBBB 00153 #define DPH_FILL_START_STAMP_2 0xABCDBBBA 00154 #define DPH_FILL_END_STAMP_1 0xDCBABBBB 00155 #define DPH_FILL_END_STAMP_2 0xDCBABBBA 00156 #define DPH_FILL_SUFFIX 0xD0 00157 #define DPH_FILL_INFIX 0xC0 00158 00159 /* Validation info flags */ 00160 #define DPH_VALINFO_BAD_START_STAMP 0x01 00161 #define DPH_VALINFO_BAD_END_STAMP 0x02 00162 #define DPH_VALINFO_BAD_POINTER 0x04 00163 #define DPH_VALINFO_BAD_PREFIX_PATTERN 0x08 00164 #define DPH_VALINFO_BAD_SUFFIX_PATTERN 0x10 00165 #define DPH_VALINFO_EXCEPTION 0x20 00166 #define DPH_VALINFO_1 0x40 00167 #define DPH_VALINFO_BAD_INFIX_PATTERN 0x80 00168 #define DPH_VALINFO_ALREADY_FREED 0x100 00169 #define DPH_VALINFO_CORRUPTED_AFTER_FREE 0x200 00170 00171 /* Signatures */ 00172 #define DPH_SIGNATURE 0xFFEEDDCC 00173 00174 /* Biased pointer macros */ 00175 #define IS_BIASED_POINTER(ptr) ((ULONG_PTR)(ptr) & 1) 00176 #define POINTER_REMOVE_BIAS(ptr) ((ULONG_PTR)(ptr) & ~(ULONG_PTR)1) 00177 #define POINTER_ADD_BIAS(ptr) ((ULONG_PTR)(ptr) | 1) 00178 00179 00180 ULONG RtlpDphBreakOptions = 0;//0xFFFFFFFF; 00181 ULONG RtlpDphDebugOptions; 00182 00183 /* FUNCTIONS ******************************************************************/ 00184 00185 BOOLEAN NTAPI 00186 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot, SIZE_T Size); 00187 00188 BOOLEAN NTAPI 00189 RtlpDphIsNormalFreeHeapBlock(PVOID Block, PULONG ValidationInformation, BOOLEAN CheckFillers); 00190 00191 VOID NTAPI 00192 RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot, ULONG Reserved, PVOID Block, ULONG ValidationInfo); 00193 00194 BOOLEAN NTAPI 00195 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot, ULONG Flags, PVOID BaseAddress); 00196 00197 00198 VOID NTAPI 00199 RtlpDphRaiseException(NTSTATUS Status) 00200 { 00201 EXCEPTION_RECORD Exception; 00202 00203 /* Initialize exception record */ 00204 Exception.ExceptionCode = Status; 00205 Exception.ExceptionAddress = RtlpDphRaiseException; 00206 Exception.ExceptionFlags = 0; 00207 Exception.ExceptionRecord = NULL; 00208 Exception.NumberParameters = 0; 00209 00210 /* Raise the exception */ 00211 RtlRaiseException(&Exception); 00212 } 00213 00214 PVOID NTAPI 00215 RtlpDphPointerFromHandle(PVOID Handle) 00216 { 00217 PHEAP NormalHeap = (PHEAP)Handle; 00218 PDPH_HEAP_ROOT DphHeap = (PDPH_HEAP_ROOT)((PUCHAR)Handle + PAGE_SIZE); 00219 00220 if (NormalHeap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) 00221 { 00222 if (DphHeap->Signature == DPH_SIGNATURE) 00223 return DphHeap; 00224 } 00225 00226 DPRINT1("heap handle with incorrect signature\n"); 00227 DbgBreakPoint(); 00228 return NULL; 00229 } 00230 00231 VOID NTAPI 00232 RtlpDphEnterCriticalSection(PDPH_HEAP_ROOT DphRoot, ULONG Flags) 00233 { 00234 if (Flags & HEAP_NO_SERIALIZE) 00235 { 00236 /* More complex scenario */ 00237 if (!RtlTryEnterCriticalSection(DphRoot->HeapCritSect)) 00238 { 00239 if (!DphRoot->nRemoteLockAcquired) 00240 { 00241 DPRINT1("multithreaded access in HEAP_NO_SERIALIZE heap\n"); 00242 DbgBreakPoint(); 00243 00244 /* Clear out the no serialize flag */ 00245 DphRoot->HeapFlags &= ~HEAP_NO_SERIALIZE; 00246 } 00247 00248 /* Enter the heap's critical section */ 00249 RtlEnterCriticalSection(DphRoot->HeapCritSect); 00250 } 00251 } 00252 else 00253 { 00254 /* Just enter the heap's critical section */ 00255 RtlEnterCriticalSection(DphRoot->HeapCritSect); 00256 } 00257 } 00258 00259 VOID NTAPI 00260 RtlpDphLeaveCriticalSection(PDPH_HEAP_ROOT DphRoot) 00261 { 00262 /* Just leave the heap's critical section */ 00263 RtlLeaveCriticalSection(DphRoot->HeapCritSect); 00264 } 00265 00266 00267 VOID NTAPI 00268 RtlpDphPreProcessing(PDPH_HEAP_ROOT DphRoot, ULONG Flags) 00269 { 00270 RtlpDphEnterCriticalSection(DphRoot, Flags); 00271 00272 /* FIXME: Validate integrity, internal lists if necessary */ 00273 } 00274 00275 VOID NTAPI 00276 RtlpDphPostProcessing(PDPH_HEAP_ROOT DphRoot) 00277 { 00278 if (!DphRoot) return; 00279 00280 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 00281 { 00282 /* FIXME: Validate integrity, internal lists if necessary */ 00283 } 00284 00285 /* Release the lock */ 00286 RtlpDphLeaveCriticalSection(DphRoot); 00287 } 00288 00289 NTSTATUS NTAPI 00290 RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type) 00291 { 00292 NTSTATUS Status; 00293 //PVOID *SavedBase = Base; 00294 //PSIZE_T SavedSize = Size; 00295 00296 /* Free the memory */ 00297 Status = ZwFreeVirtualMemory(Process, Base, Size, Type); 00298 00299 /* Flush secure memory cache if needed and retry freeing */ 00300 #if 0 00301 if (Status == STATUS_INVALID_PAGE_PROTECTION && 00302 Process == NtCurrentProcess() && 00303 RtlFlushSecureMemoryCache(*SavedBase, *SavedSize)) 00304 { 00305 Status = ZwFreeVirtualMemory(NtCurrentProcess(), SavedBase, SavedSize, Type); 00306 } 00307 #endif 00308 00309 return Status; 00310 } 00311 00312 NTSTATUS NTAPI 00313 RtlpDphAllocateVm(PVOID *Base, SIZE_T Size, ULONG Type, ULONG Protection) 00314 { 00315 NTSTATUS Status; 00316 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 00317 Base, 00318 0, 00319 &Size, 00320 Type, 00321 Protection); 00322 DPRINT("Page heap: AllocVm (%p, %p, %x) status %x \n", Base, Size, Type, Status); 00323 /* Check for failures */ 00324 if (!NT_SUCCESS(Status)) 00325 { 00326 if (Type == MEM_RESERVE) 00327 { 00328 _InterlockedIncrement(&RtlpDphCounter); 00329 if (RtlpDphBreakOptions & DPH_BREAK_ON_RESERVE_FAIL) 00330 { 00331 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status); 00332 DbgBreakPoint(); 00333 return Status; 00334 } 00335 } 00336 else 00337 { 00338 _InterlockedIncrement(&RtlpDphAllocFails); 00339 if (RtlpDphBreakOptions & DPH_BREAK_ON_COMMIT_FAIL) 00340 { 00341 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status); 00342 DbgBreakPoint(); 00343 return Status; 00344 } 00345 } 00346 } 00347 00348 return Status; 00349 } 00350 00351 NTSTATUS NTAPI 00352 RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type) 00353 { 00354 NTSTATUS Status; 00355 00356 /* Free the memory */ 00357 Status = RtlpSecMemFreeVirtualMemory(NtCurrentProcess(), &Base, &Size, Type); 00358 DPRINT1("Page heap: FreeVm (%p, %p, %x) status %x \n", Base, Size, Type, Status); 00359 /* Log/report failures */ 00360 if (!NT_SUCCESS(Status)) 00361 { 00362 if (Type == MEM_RELEASE) 00363 { 00364 _InterlockedIncrement(&RtlpDphReleaseFails); 00365 if (RtlpDphBreakOptions & DPH_BREAK_ON_RELEASE_FAIL) 00366 { 00367 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status); 00368 DbgBreakPoint(); 00369 return Status; 00370 } 00371 } 00372 else 00373 { 00374 _InterlockedIncrement(&RtlpDphFreeFails); 00375 if (RtlpDphBreakOptions & DPH_BREAK_ON_FREE_FAIL) 00376 { 00377 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status); 00378 DbgBreakPoint(); 00379 return Status; 00380 } 00381 } 00382 } 00383 00384 return Status; 00385 } 00386 00387 NTSTATUS NTAPI 00388 RtlpDphProtectVm(PVOID Base, SIZE_T Size, ULONG Protection) 00389 { 00390 NTSTATUS Status; 00391 ULONG OldProtection; 00392 00393 /* Change protection */ 00394 Status = ZwProtectVirtualMemory(NtCurrentProcess(), &Base, &Size, Protection, &OldProtection); 00395 00396 /* Log/report failures */ 00397 if (!NT_SUCCESS(Status)) 00398 { 00399 _InterlockedIncrement(&RtlpDphProtectFails); 00400 if (RtlpDphBreakOptions & DPH_BREAK_ON_PROTECT_FAIL) 00401 { 00402 DPRINT1("Page heap: ProtectVm (%p, %p, %x) failed with %x \n", Base, Size, Protection, Status); 00403 DbgBreakPoint(); 00404 return Status; 00405 } 00406 } 00407 00408 return Status; 00409 } 00410 00411 BOOLEAN NTAPI 00412 RtlpDphWritePageHeapBlockInformation(PDPH_HEAP_ROOT DphRoot, PVOID UserAllocation, SIZE_T Size, SIZE_T UserSize) 00413 { 00414 PDPH_BLOCK_INFORMATION BlockInfo; 00415 PUCHAR FillPtr; 00416 00417 /* Get pointer to the block info structure */ 00418 BlockInfo = (PDPH_BLOCK_INFORMATION)UserAllocation - 1; 00419 00420 /* Set up basic fields */ 00421 BlockInfo->Heap = DphRoot; 00422 BlockInfo->ActualSize = UserSize; 00423 BlockInfo->RequestedSize = Size; 00424 BlockInfo->StartStamp = DPH_FILL_START_STAMP_1; 00425 BlockInfo->EndStamp = DPH_FILL_END_STAMP_1; 00426 00427 /* Fill with a pattern */ 00428 FillPtr = (PUCHAR)UserAllocation + Size; 00429 RtlFillMemory(FillPtr, ROUND_UP(FillPtr, PAGE_SIZE) - (ULONG_PTR)FillPtr, DPH_FILL_SUFFIX); 00430 00431 /* FIXME: Check if logging stack traces is turned on */ 00432 //if (DphRoot->ExtraFlags & 00433 00434 return TRUE; 00435 } 00436 00437 VOID NTAPI 00438 RtlpDphPlaceOnBusyList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode) 00439 { 00440 BOOLEAN NewElement; 00441 PVOID AddressUserData; 00442 00443 DPRINT("RtlpDphPlaceOnBusyList(%p %p)\n", DphRoot, DphNode); 00444 00445 /* Add it to the AVL busy nodes table */ 00446 DphRoot->NodeToAllocate = DphNode; 00447 AddressUserData = RtlInsertElementGenericTableAvl(&DphRoot->BusyNodesTable, 00448 &DphNode->pUserAllocation, 00449 sizeof(ULONG_PTR), 00450 &NewElement); 00451 00452 ASSERT(AddressUserData == &DphNode->pUserAllocation); 00453 ASSERT(NewElement == TRUE); 00454 00455 /* Update heap counters */ 00456 DphRoot->nBusyAllocations++; 00457 DphRoot->nBusyAllocationBytesAccessible += DphNode->nVirtualAccessSize; 00458 DphRoot->nBusyAllocationBytesCommitted += DphNode->nVirtualBlockSize; 00459 } 00460 00461 VOID NTAPI 00462 RtlpDphPlaceOnFreeList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK Node) 00463 { 00464 DPRINT("RtlpDphPlaceOnFreeList(%p %p)\n", DphRoot, Node); 00465 00466 /* Node is being added to the tail of the list */ 00467 Node->pNextAlloc = NULL; 00468 00469 /* Add it to the tail of the linked list */ 00470 if (DphRoot->pFreeAllocationListTail) 00471 DphRoot->pFreeAllocationListTail->pNextAlloc = Node; 00472 else 00473 DphRoot->pFreeAllocationListHead = Node; 00474 DphRoot->pFreeAllocationListTail = Node; 00475 00476 /* Update byte counts taking in account this new node */ 00477 DphRoot->nFreeAllocations++; 00478 DphRoot->nFreeAllocationBytesCommitted += Node->nVirtualBlockSize; 00479 } 00480 00481 VOID NTAPI 00482 RtlpDphPlaceOnPoolList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK Node) 00483 { 00484 DPRINT("RtlpDphPlaceOnPoolList(%p %p)\n", DphRoot, Node); 00485 00486 /* Node is being added to the tail of the list */ 00487 Node->pNextAlloc = NULL; 00488 00489 /* Add it to the tail of the linked list */ 00490 if (DphRoot->pNodePoolListTail) 00491 DphRoot->pNodePoolListTail->pNextAlloc = Node; 00492 else 00493 DphRoot->pNodePoolListHead = Node; 00494 DphRoot->pNodePoolListTail = Node; 00495 00496 /* Update byte counts taking in account this new node */ 00497 DphRoot->nNodePools++; 00498 DphRoot->nNodePoolBytes += Node->nVirtualBlockSize; 00499 } 00500 00501 VOID NTAPI 00502 RtlpDphPlaceOnVirtualList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK Node) 00503 { 00504 DPRINT("RtlpDphPlaceOnVirtualList(%p %p)\n", DphRoot, Node); 00505 00506 /* Add it to the head of the virtual list */ 00507 Node->pNextAlloc = DphRoot->pVirtualStorageListHead; 00508 if (!DphRoot->pVirtualStorageListHead) 00509 DphRoot->pVirtualStorageListTail = Node; 00510 DphRoot->pVirtualStorageListHead = Node; 00511 00512 /* Update byte counts taking in account this new node */ 00513 DphRoot->nVirtualStorageRanges++; 00514 DphRoot->nVirtualStorageBytes += Node->nVirtualBlockSize; 00515 } 00516 00517 PDPH_HEAP_BLOCK NTAPI 00518 RtlpDphTakeNodeFromUnusedList(PDPH_HEAP_ROOT DphRoot) 00519 { 00520 PDPH_HEAP_BLOCK Node = DphRoot->pUnusedNodeListHead; 00521 PDPH_HEAP_BLOCK Next; 00522 00523 DPRINT("RtlpDphTakeNodeFromUnusedList(%p), ret %p\n", DphRoot, Node); 00524 00525 /* Take the first entry */ 00526 if (!Node) return NULL; 00527 00528 /* Remove that entry (Node) from the list */ 00529 Next = Node->pNextAlloc; 00530 if (DphRoot->pUnusedNodeListHead == Node) DphRoot->pUnusedNodeListHead = Next; 00531 if (DphRoot->pUnusedNodeListTail == Node) DphRoot->pUnusedNodeListTail = NULL; 00532 00533 /* Decrease amount of unused nodes */ 00534 DphRoot->nUnusedNodes--; 00535 00536 return Node; 00537 } 00538 00539 VOID NTAPI 00540 RtlpDphReturnNodeToUnusedList(PDPH_HEAP_ROOT DphRoot, 00541 PDPH_HEAP_BLOCK Node) 00542 { 00543 DPRINT("RtlpDphReturnNodeToUnusedList(%p, %p)\n", DphRoot, Node); 00544 00545 /* Add it back to the head of the unused list */ 00546 Node->pNextAlloc = DphRoot->pUnusedNodeListHead; 00547 if (!DphRoot->pUnusedNodeListHead) 00548 DphRoot->pUnusedNodeListTail = Node; 00549 DphRoot->pUnusedNodeListHead = Node; 00550 00551 /* Increase amount of unused nodes */ 00552 DphRoot->nUnusedNodes++; 00553 } 00554 00555 VOID NTAPI 00556 RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot, 00557 PDPH_HEAP_BLOCK Node) 00558 { 00559 /* Make sure Adjacency list pointers are biased */ 00560 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink)); 00561 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink)); 00562 00563 DPRINT("RtlpDphRemoveFromAvailableList(%p %p)\n", DphRoot, Node); 00564 00565 /* Check if it is in the list */ 00566 #if 0 00567 { 00568 PLIST_ENTRY CurEntry; 00569 PDPH_HEAP_BLOCK NodeEntry; 00570 BOOLEAN Found = FALSE; 00571 00572 /* Find where to put this node according to its virtual address */ 00573 CurEntry = DphRoot->AvailableAllocationHead.Flink; 00574 00575 while (CurEntry != &DphRoot->AvailableAllocationHead) 00576 { 00577 NodeEntry = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry); 00578 00579 if (NodeEntry == Node) 00580 { 00581 Found = TRUE; 00582 break; 00583 } 00584 00585 CurEntry = CurEntry->Flink; 00586 } 00587 00588 if (!Found) 00589 { 00590 DPRINT1("Trying to remove non-existing in availlist node!\n"); 00591 DbgBreakPoint(); 00592 } 00593 } 00594 #endif 00595 00596 /* Remove it from the list */ 00597 RemoveEntryList(&Node->AvailableEntry); 00598 00599 /* Decrease heap counters */ 00600 DphRoot->nAvailableAllocations--; 00601 DphRoot->nAvailableAllocationBytesCommitted -= Node->nVirtualBlockSize; 00602 00603 /* Remove bias from the AdjacencyEntry pointer */ 00604 Node->AdjacencyEntry.Flink = (PLIST_ENTRY)POINTER_REMOVE_BIAS(Node->AdjacencyEntry.Flink); 00605 Node->AdjacencyEntry.Blink = (PLIST_ENTRY)POINTER_REMOVE_BIAS(Node->AdjacencyEntry.Blink); 00606 } 00607 00608 VOID NTAPI 00609 RtlpDphRemoveFromBusyList(PDPH_HEAP_ROOT DphRoot, 00610 PDPH_HEAP_BLOCK Node) 00611 { 00612 BOOLEAN ElementPresent; 00613 00614 DPRINT("RtlpDphRemoveFromBusyList(%p %p)\n", DphRoot, Node); 00615 00616 /* Delete it from busy nodes table */ 00617 ElementPresent = RtlDeleteElementGenericTableAvl(&DphRoot->BusyNodesTable, &Node->pUserAllocation); 00618 ASSERT(ElementPresent == TRUE); 00619 00620 /* Update counters */ 00621 DphRoot->nBusyAllocations--; 00622 DphRoot->nBusyAllocationBytesCommitted -= Node->nVirtualBlockSize; 00623 DphRoot->nBusyAllocationBytesAccessible -= Node->nVirtualAccessSize; 00624 } 00625 00626 VOID NTAPI 00627 RtlpDphRemoveFromFreeList(PDPH_HEAP_ROOT DphRoot, 00628 PDPH_HEAP_BLOCK Node, 00629 PDPH_HEAP_BLOCK Prev) 00630 { 00631 PDPH_HEAP_BLOCK Next; 00632 00633 DPRINT("RtlpDphRemoveFromFreeList(%p %p %p)\n", DphRoot, Node, Prev); 00634 00635 /* Detach it from the list */ 00636 Next = Node->pNextAlloc; 00637 if (DphRoot->pFreeAllocationListHead == Node) 00638 DphRoot->pFreeAllocationListHead = Next; 00639 if (DphRoot->pFreeAllocationListTail == Node) 00640 DphRoot->pFreeAllocationListTail = Prev; 00641 if (Prev) Prev->pNextAlloc = Next; 00642 00643 /* Decrease heap counters */ 00644 DphRoot->nFreeAllocations--; 00645 DphRoot->nFreeAllocationBytesCommitted -= Node->nVirtualBlockSize; 00646 00647 Node->StackTrace = NULL; 00648 } 00649 00650 VOID NTAPI 00651 RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot, 00652 PDPH_HEAP_BLOCK Node) 00653 { 00654 PDPH_HEAP_BLOCK NodeEntry, PrevNode = NULL, NextNode; 00655 PLIST_ENTRY AvailListHead; 00656 PLIST_ENTRY CurEntry; 00657 00658 DPRINT("RtlpDphCoalesceNodeIntoAvailable(%p %p)\n", DphRoot, Node); 00659 00660 /* Update heap counters */ 00661 DphRoot->nAvailableAllocationBytesCommitted += Node->nVirtualBlockSize; 00662 DphRoot->nAvailableAllocations++; 00663 00664 /* Find where to put this node according to its virtual address */ 00665 AvailListHead = &DphRoot->AvailableAllocationHead; 00666 00667 /* Find a point where to insert an available node */ 00668 CurEntry = AvailListHead->Flink; 00669 00670 while (CurEntry != AvailListHead) 00671 { 00672 NodeEntry = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry); 00673 if (NodeEntry->pVirtualBlock >= Node->pVirtualBlock) 00674 { 00675 PrevNode = NodeEntry; 00676 break; 00677 } 00678 CurEntry = CurEntry->Flink; 00679 } 00680 00681 if (!PrevNode) 00682 { 00683 /* That means either this list is empty, or we should add to the head of it */ 00684 InsertHeadList(AvailListHead, &Node->AvailableEntry); 00685 } 00686 else 00687 { 00688 /* Check the previous node and merge if possible */ 00689 if (PrevNode->pVirtualBlock + PrevNode->nVirtualBlockSize == Node->pVirtualBlock) 00690 { 00691 /* They are adjacent - merge! */ 00692 PrevNode->nVirtualBlockSize += Node->nVirtualBlockSize; 00693 RtlpDphReturnNodeToUnusedList(DphRoot, Node); 00694 DphRoot->nAvailableAllocations--; 00695 00696 Node = PrevNode; 00697 } 00698 else 00699 { 00700 /* Insert after PrevNode */ 00701 InsertTailList(&PrevNode->AvailableEntry, &Node->AvailableEntry); 00702 } 00703 00704 /* Now check the next entry after our one */ 00705 if (Node->AvailableEntry.Flink != AvailListHead) 00706 { 00707 NextNode = CONTAINING_RECORD(Node->AvailableEntry.Flink, DPH_HEAP_BLOCK, AvailableEntry); 00708 /* Node is not at the tail of the list, check if it's adjacent */ 00709 if (Node->pVirtualBlock + Node->nVirtualBlockSize == NextNode->pVirtualBlock) 00710 { 00711 /* They are adjacent - merge! */ 00712 Node->nVirtualBlockSize += NextNode->nVirtualBlockSize; 00713 00714 /* Remove next entry from the list and put it into unused entries list */ 00715 RemoveEntryList(&NextNode->AvailableEntry); 00716 RtlpDphReturnNodeToUnusedList(DphRoot, NextNode); 00717 DphRoot->nAvailableAllocations--; 00718 } 00719 } 00720 } 00721 } 00722 00723 VOID NTAPI 00724 RtlpDphCoalesceFreeIntoAvailable(PDPH_HEAP_ROOT DphRoot, 00725 ULONG LeaveOnFreeList) 00726 { 00727 PDPH_HEAP_BLOCK Node = DphRoot->pFreeAllocationListHead, Next; 00728 SIZE_T FreeAllocations = DphRoot->nFreeAllocations; 00729 00730 /* Make sure requested size is not too big */ 00731 ASSERT(FreeAllocations >= LeaveOnFreeList); 00732 00733 DPRINT("RtlpDphCoalesceFreeIntoAvailable(%p %d)\n", DphRoot, LeaveOnFreeList); 00734 00735 while (Node) 00736 { 00737 FreeAllocations--; 00738 if (FreeAllocations < LeaveOnFreeList) break; 00739 00740 /* Get the next pointer, because it may be changed after following two calls */ 00741 Next = Node->pNextAlloc; 00742 00743 /* Remove it from the free list */ 00744 RtlpDphRemoveFromFreeList(DphRoot, Node, NULL); 00745 00746 /* And put into the available */ 00747 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node); 00748 00749 /* Go to the next node */ 00750 Node = Next; 00751 } 00752 } 00753 00754 VOID NTAPI 00755 RtlpDphAddNewPool(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK NodeBlock, PVOID Virtual, SIZE_T Size, BOOLEAN PlaceOnPool) 00756 { 00757 PDPH_HEAP_BLOCK DphNode, DphStartNode; 00758 ULONG NodeCount, i; 00759 00760 //NodeCount = (Size >> 6) - 1; 00761 NodeCount = (ULONG)(Size / sizeof(DPH_HEAP_BLOCK)); 00762 DphStartNode = Virtual; 00763 00764 /* Set pNextAlloc for all blocks */ 00765 for (DphNode = Virtual, i=NodeCount-1; i > 0; i--) 00766 { 00767 DphNode->pNextAlloc = DphNode + 1; 00768 DphNode = DphNode->pNextAlloc; 00769 } 00770 00771 /* and the last one */ 00772 DphNode->pNextAlloc = NULL; 00773 00774 /* Add it to the tail of unused node list */ 00775 if (DphRoot->pUnusedNodeListTail) 00776 DphRoot->pUnusedNodeListTail->pNextAlloc = DphStartNode; 00777 else 00778 DphRoot->pUnusedNodeListHead = DphStartNode; 00779 00780 DphRoot->pUnusedNodeListTail = DphNode; 00781 00782 /* Increase counters */ 00783 DphRoot->nUnusedNodes += NodeCount; 00784 00785 /* Check if we need to place it on the pool list */ 00786 if (PlaceOnPool) 00787 { 00788 /* Get a node from the unused list */ 00789 DphNode = RtlpDphTakeNodeFromUnusedList(DphRoot); 00790 ASSERT(DphNode); 00791 00792 /* Set its virtual block values */ 00793 DphNode->pVirtualBlock = Virtual; 00794 DphNode->nVirtualBlockSize = Size; 00795 00796 /* Place it on the pool list */ 00797 RtlpDphPlaceOnPoolList(DphRoot, DphNode); 00798 } 00799 } 00800 00801 PDPH_HEAP_BLOCK NTAPI 00802 RtlpDphSearchAvailableMemoryListForBestFit(PDPH_HEAP_ROOT DphRoot, 00803 SIZE_T Size) 00804 { 00805 PLIST_ENTRY CurEntry; 00806 PDPH_HEAP_BLOCK Node, NodeFound = NULL; 00807 00808 CurEntry = DphRoot->AvailableAllocationHead.Flink; 00809 00810 while (CurEntry != &DphRoot->AvailableAllocationHead) 00811 { 00812 /* Get the current available node */ 00813 Node = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry); 00814 00815 /* Check its size */ 00816 if (Node->nVirtualBlockSize >= Size) 00817 { 00818 NodeFound = Node; 00819 break; 00820 } 00821 00822 /* Move to the next available entry */ 00823 CurEntry = CurEntry->Flink; 00824 } 00825 00826 /* Make sure Adjacency list pointers are biased */ 00827 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink)); 00828 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink)); 00829 00830 return NodeFound; 00831 } 00832 00833 PDPH_HEAP_BLOCK NTAPI 00834 RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot, 00835 SIZE_T Size, 00836 BOOLEAN Grow) 00837 { 00838 PDPH_HEAP_BLOCK Node; 00839 ULONG NewSize; 00840 00841 /* Find an available best fitting node */ 00842 Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size); 00843 00844 /* If that didn't work, try to search a smaller one in the loop */ 00845 while (!Node) 00846 { 00847 /* Break if the free list becomes too small */ 00848 if (DphRoot->nFreeAllocations <= DPH_FREE_LIST_MINIMUM) break; 00849 00850 /* Calculate a new free list size */ 00851 NewSize = DphRoot->nFreeAllocations >> 2; 00852 if (NewSize < DPH_FREE_LIST_MINIMUM) NewSize = DPH_FREE_LIST_MINIMUM; 00853 00854 /* Coalesce free into available */ 00855 RtlpDphCoalesceFreeIntoAvailable(DphRoot, NewSize); 00856 00857 /* Try to find an available best fitting node again */ 00858 Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size); 00859 } 00860 00861 /* If Node is NULL, then we could fix the situation only by 00862 growing the available VM size */ 00863 if (!Node && Grow) 00864 { 00865 /* Grow VM size, if it fails - return failure directly */ 00866 if (!RtlpDphGrowVirtual(DphRoot, Size)) return NULL; 00867 00868 /* Try to find an available best fitting node again */ 00869 Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size); 00870 00871 if (!Node) 00872 { 00873 /* Do the last attempt: coalesce all free into available (if Size fits there) */ 00874 if (DphRoot->nFreeAllocationBytesCommitted + DphRoot->nAvailableAllocationBytesCommitted >= Size) 00875 { 00876 /* Coalesce free into available */ 00877 RtlpDphCoalesceFreeIntoAvailable(DphRoot, 0); 00878 00879 /* Try to find an available best fitting node again */ 00880 Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size); 00881 } 00882 } 00883 } 00884 00885 /* Return node we found */ 00886 return Node; 00887 } 00888 00889 PDPH_HEAP_BLOCK NTAPI 00890 RtlpDphFindBusyMemory(PDPH_HEAP_ROOT DphRoot, 00891 PVOID pUserMem) 00892 { 00893 PDPH_HEAP_BLOCK Node; 00894 PVOID Ptr; 00895 00896 /* Lookup busy block in AVL */ 00897 Ptr = RtlLookupElementGenericTableAvl(&DphRoot->BusyNodesTable, &pUserMem); 00898 if (!Ptr) return NULL; 00899 00900 /* Restore pointer to the heap block */ 00901 Node = CONTAINING_RECORD(Ptr, DPH_HEAP_BLOCK, pUserAllocation); 00902 ASSERT(Node->pUserAllocation == pUserMem); 00903 return Node; 00904 } 00905 00906 NTSTATUS NTAPI 00907 RtlpDphSetProtectionBeforeUse(PDPH_HEAP_ROOT DphRoot, PUCHAR VirtualBlock, ULONG UserSize) 00908 { 00909 ULONG Protection; 00910 PVOID Base; 00911 00912 if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN) 00913 { 00914 Base = VirtualBlock + PAGE_SIZE; 00915 } 00916 else 00917 { 00918 Base = VirtualBlock; 00919 } 00920 00921 // FIXME: It should be different, but for now it's fine 00922 Protection = PAGE_READWRITE; 00923 00924 return RtlpDphProtectVm(Base, UserSize, Protection); 00925 } 00926 00927 NTSTATUS NTAPI 00928 RtlpDphSetProtectionAfterUse(PDPH_HEAP_ROOT DphRoot, /*PUCHAR VirtualBlock*/PDPH_HEAP_BLOCK Node) 00929 { 00930 ASSERT((Node->nVirtualAccessSize + PAGE_SIZE) <= Node->nVirtualBlockSize); 00931 00932 // FIXME: Bring stuff here 00933 if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN) 00934 { 00935 } 00936 else 00937 { 00938 } 00939 00940 return STATUS_SUCCESS; 00941 } 00942 00943 PDPH_HEAP_BLOCK NTAPI 00944 RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot) 00945 { 00946 PDPH_HEAP_BLOCK Node; 00947 NTSTATUS Status; 00948 SIZE_T Size = DPH_POOL_SIZE, SizeVirtual; 00949 PVOID Ptr = NULL; 00950 00951 /* Check for the easy case */ 00952 if (DphRoot->pUnusedNodeListHead) 00953 { 00954 /* Just take a node from this list */ 00955 Node = RtlpDphTakeNodeFromUnusedList(DphRoot); 00956 ASSERT(Node); 00957 return Node; 00958 } 00959 00960 /* There is a need to make free space */ 00961 Node = RtlpDphFindAvailableMemory(DphRoot, DPH_POOL_SIZE, FALSE); 00962 00963 if (!DphRoot->pUnusedNodeListHead && !Node) 00964 { 00965 /* Retry with a smaller request */ 00966 Size = PAGE_SIZE; 00967 Node = RtlpDphFindAvailableMemory(DphRoot, PAGE_SIZE, FALSE); 00968 } 00969 00970 if (!DphRoot->pUnusedNodeListHead) 00971 { 00972 if (Node) 00973 { 00974 RtlpDphRemoveFromAvailableList(DphRoot, Node); 00975 Ptr = Node->pVirtualBlock; 00976 SizeVirtual = Node->nVirtualBlockSize; 00977 } 00978 else 00979 { 00980 /* No free space, need to alloc a new VM block */ 00981 Size = DPH_POOL_SIZE; 00982 SizeVirtual = DPH_RESERVE_SIZE; 00983 Status = RtlpDphAllocateVm(&Ptr, SizeVirtual, MEM_COMMIT, PAGE_NOACCESS); 00984 00985 if (!NT_SUCCESS(Status)) 00986 { 00987 /* Retry with a smaller size */ 00988 SizeVirtual = 0x10000; 00989 Status = RtlpDphAllocateVm(&Ptr, SizeVirtual, MEM_COMMIT, PAGE_NOACCESS); 00990 if (!NT_SUCCESS(Status)) return NULL; 00991 } 00992 } 00993 00994 /* VM is allocated at this point, set protection */ 00995 Status = RtlpDphProtectVm(Ptr, Size, PAGE_READWRITE); 00996 if (!NT_SUCCESS(Status)) 00997 { 00998 if (Node) 00999 { 01000 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node); 01001 } 01002 else 01003 { 01004 //RtlpDphFreeVm(); 01005 ASSERT(FALSE); 01006 } 01007 01008 return NULL; 01009 } 01010 01011 /* Zero the memory */ 01012 if (Node) RtlZeroMemory(Ptr, Size); 01013 01014 /* Add a new pool based on this VM */ 01015 RtlpDphAddNewPool(DphRoot, Node, Ptr, Size, TRUE); 01016 01017 if (Node) 01018 { 01019 if (Node->nVirtualBlockSize > Size) 01020 { 01021 Node->pVirtualBlock += Size; 01022 Node->nVirtualBlockSize -= Size; 01023 01024 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node); 01025 } 01026 else 01027 { 01028 RtlpDphReturnNodeToUnusedList(DphRoot, Node); 01029 } 01030 } 01031 else 01032 { 01033 /* The new VM block was just allocated a few code lines ago, 01034 so initialize it */ 01035 Node = RtlpDphTakeNodeFromUnusedList(DphRoot); 01036 Node->pVirtualBlock = Ptr; 01037 Node->nVirtualBlockSize = SizeVirtual; 01038 RtlpDphPlaceOnVirtualList(DphRoot, Node); 01039 01040 Node = RtlpDphTakeNodeFromUnusedList(DphRoot); 01041 Node->pVirtualBlock = (PUCHAR)Ptr + Size; 01042 Node->nVirtualBlockSize = SizeVirtual - Size; 01043 RtlpDphPlaceOnVirtualList(DphRoot, Node); 01044 01045 /* Coalesce them into available list */ 01046 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node); 01047 } 01048 } 01049 01050 return RtlpDphTakeNodeFromUnusedList(DphRoot); 01051 } 01052 01053 BOOLEAN NTAPI 01054 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot, 01055 SIZE_T Size) 01056 { 01057 PDPH_HEAP_BLOCK Node, AvailableNode; 01058 PVOID Base = NULL; 01059 SIZE_T VirtualSize; 01060 NTSTATUS Status; 01061 01062 /* Start with allocating a couple of nodes */ 01063 Node = RtlpDphAllocateNode(DphRoot); 01064 if (!Node) return FALSE; 01065 01066 AvailableNode = RtlpDphAllocateNode(DphRoot); 01067 if (!AvailableNode) 01068 { 01069 /* Free the allocated node and return failure */ 01070 RtlpDphReturnNodeToUnusedList(DphRoot, Node); 01071 return FALSE; 01072 } 01073 01074 /* Calculate size of VM to allocate by rounding it up */ 01075 Size = ROUND_UP(Size, 0xFFFF); 01076 VirtualSize = Size; 01077 if (Size < DPH_RESERVE_SIZE) 01078 VirtualSize = DPH_RESERVE_SIZE; 01079 01080 /* Allocate the virtual memory */ 01081 // FIXME: Shouldn't it be MEM_RESERVE with later committing? 01082 Status = RtlpDphAllocateVm(&Base, VirtualSize, MEM_COMMIT, PAGE_NOACCESS); 01083 if (!NT_SUCCESS(Status)) 01084 { 01085 /* Retry again with a smaller size */ 01086 VirtualSize = Size; 01087 Status = RtlpDphAllocateVm(&Base, VirtualSize, MEM_COMMIT, PAGE_NOACCESS); 01088 if (!NT_SUCCESS(Status)) 01089 { 01090 /* Free the allocated node and return failure */ 01091 RtlpDphReturnNodeToUnusedList(DphRoot, Node); 01092 RtlpDphReturnNodeToUnusedList(DphRoot, AvailableNode); 01093 return FALSE; 01094 } 01095 } 01096 01097 /* Set up our two nodes describing this VM */ 01098 Node->pVirtualBlock = Base; 01099 Node->nVirtualBlockSize = VirtualSize; 01100 AvailableNode->pVirtualBlock = Base; 01101 AvailableNode->nVirtualBlockSize = VirtualSize; 01102 01103 /* Add them to virtual and available lists respectively */ 01104 RtlpDphPlaceOnVirtualList(DphRoot, Node); 01105 RtlpDphCoalesceNodeIntoAvailable(DphRoot, AvailableNode); 01106 01107 /* Return success */ 01108 return TRUE; 01109 } 01110 01111 RTL_GENERIC_COMPARE_RESULTS 01112 NTAPI 01113 RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table, 01114 IN PVOID FirstStruct, 01115 IN PVOID SecondStruct) 01116 { 01117 ULONG_PTR FirstBlock, SecondBlock; 01118 01119 FirstBlock = *((ULONG_PTR *)FirstStruct); 01120 SecondBlock = *((ULONG_PTR *)SecondStruct); 01121 01122 if (FirstBlock < SecondBlock) 01123 return GenericLessThan; 01124 else if (FirstBlock > SecondBlock) 01125 return GenericGreaterThan; 01126 01127 return GenericEqual; 01128 } 01129 01130 PVOID 01131 NTAPI 01132 RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table, 01133 IN CLONG ByteSize) 01134 { 01135 PDPH_HEAP_BLOCK pBlock; 01136 PDPH_HEAP_ROOT DphRoot; 01137 01138 /* This mega-assert comes from a text search over Windows 2003 checked binary of ntdll.dll */ 01139 ASSERT((ULONG_PTR)(((PRTL_BALANCED_LINKS)0)+1) + sizeof(PUCHAR) == ByteSize); 01140 01141 /* Get pointer to the containing heap root record */ 01142 DphRoot = CONTAINING_RECORD(Table, DPH_HEAP_ROOT, BusyNodesTable); 01143 pBlock = DphRoot->NodeToAllocate; 01144 01145 DphRoot->NodeToAllocate = NULL; 01146 ASSERT(pBlock); 01147 01148 return &(pBlock->TableLinks); 01149 } 01150 01151 VOID 01152 NTAPI 01153 RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table, 01154 IN PVOID Buffer) 01155 { 01156 /* Nothing */ 01157 } 01158 01159 NTSTATUS NTAPI 01160 RtlpDphInitializeDelayedFreeQueue() 01161 { 01162 NTSTATUS Status; 01163 01164 Status = RtlInitializeCriticalSection(&RtlpDphDelayedFreeQueueLock); 01165 if (!NT_SUCCESS(Status)) 01166 { 01167 // TODO: Log this error! 01168 DPRINT1("Failure initializing delayed free queue critical section\n"); 01169 return Status; 01170 } 01171 01172 /* Initialize lists */ 01173 InitializeListHead(&RtlpDphDelayedFreeQueue); 01174 RtlInitializeSListHead(&RtlpDphDelayedTemporaryPushList); 01175 01176 /* Reset counters */ 01177 RtlpDphMemoryUsedByDelayedFreeBlocks = 0; 01178 RtlpDphNumberOfDelayedFreeBlocks = 0; 01179 01180 return Status; 01181 } 01182 01183 VOID NTAPI 01184 RtlpDphFreeDelayedBlocksFromHeap(PDPH_HEAP_ROOT DphRoot, 01185 PHEAP NormalHeap) 01186 { 01187 PLIST_ENTRY Current, Next; 01188 PDPH_BLOCK_INFORMATION BlockInfo; 01189 ULONG ValidationInfo; 01190 01191 /* The original routine seems to use a temporary SList to put blocks to be freed, 01192 then it releases the lock and frees the blocks. But let's make it simple for now */ 01193 01194 /* Acquire the delayed free queue lock */ 01195 RtlEnterCriticalSection(&RtlpDphDelayedFreeQueueLock); 01196 01197 /* Traverse the list */ 01198 Current = RtlpDphDelayedFreeQueue.Flink; 01199 while (Current != &RtlpDphDelayedFreeQueue) 01200 { 01201 /* Get the next entry pointer */ 01202 Next = Current->Flink; 01203 01204 BlockInfo = CONTAINING_RECORD(Current, DPH_BLOCK_INFORMATION, FreeQueue); 01205 01206 /* Check if it belongs to the same heap */ 01207 if (BlockInfo->Heap == DphRoot) 01208 { 01209 /* Remove it from the list */ 01210 RemoveEntryList(Current); 01211 01212 /* Reset its heap to NULL */ 01213 BlockInfo->Heap = NULL; 01214 01215 if (!RtlpDphIsNormalFreeHeapBlock(BlockInfo + 1, &ValidationInfo, TRUE)) 01216 { 01217 RtlpDphReportCorruptedBlock(DphRoot, 10, BlockInfo + 1, ValidationInfo); 01218 } 01219 01220 /* Decrement counters */ 01221 RtlpDphMemoryUsedByDelayedFreeBlocks -= BlockInfo->ActualSize; 01222 RtlpDphNumberOfDelayedFreeBlocks--; 01223 01224 /* Free the normal heap */ 01225 RtlFreeHeap (NormalHeap, 0, BlockInfo); 01226 } 01227 01228 /* Move to the next one */ 01229 Current = Next; 01230 } 01231 01232 /* Release the delayed free queue lock */ 01233 RtlLeaveCriticalSection(&RtlpDphDelayedFreeQueueLock); 01234 } 01235 01236 NTSTATUS NTAPI 01237 RtlpDphTargetDllsLogicInitialize() 01238 { 01239 UNIMPLEMENTED; 01240 return STATUS_SUCCESS; 01241 } 01242 01243 VOID NTAPI 01244 RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot, PVOID Address, ULONG Value) 01245 { 01246 UNIMPLEMENTED; 01247 } 01248 01249 VOID NTAPI 01250 RtlpDphVerifyIntegrity(PDPH_HEAP_ROOT DphRoot) 01251 { 01252 UNIMPLEMENTED; 01253 } 01254 01255 VOID NTAPI 01256 RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot, 01257 ULONG Reserved, 01258 PVOID Block, 01259 ULONG ValidationInfo) 01260 { 01261 //RtlpDphGetBlockSizeFromCorruptedBlock(); 01262 01263 if (ValidationInfo & DPH_VALINFO_CORRUPTED_AFTER_FREE) 01264 { 01265 DPRINT1("block corrupted after having been freed\n"); 01266 } 01267 01268 if (ValidationInfo & DPH_VALINFO_ALREADY_FREED) 01269 { 01270 DPRINT1("block already freed\n"); 01271 } 01272 01273 if (ValidationInfo & DPH_VALINFO_BAD_INFIX_PATTERN) 01274 { 01275 DPRINT1("corrupted infix pattern for freed block\n"); 01276 } 01277 01278 if (ValidationInfo & DPH_VALINFO_BAD_POINTER) 01279 { 01280 DPRINT1("corrupted heap pointer or using wrong heap\n"); 01281 } 01282 01283 if (ValidationInfo & DPH_VALINFO_BAD_SUFFIX_PATTERN) 01284 { 01285 DPRINT1("corrupted suffix pattern\n"); 01286 } 01287 01288 if (ValidationInfo & DPH_VALINFO_BAD_PREFIX_PATTERN) 01289 { 01290 DPRINT1("corrupted prefix pattern\n"); 01291 } 01292 01293 if (ValidationInfo & DPH_VALINFO_BAD_START_STAMP) 01294 { 01295 DPRINT1("corrupted start stamp\n"); 01296 } 01297 01298 if (ValidationInfo & DPH_VALINFO_BAD_END_STAMP) 01299 { 01300 DPRINT1("corrupted end stamp\n"); 01301 } 01302 01303 if (ValidationInfo & DPH_VALINFO_EXCEPTION) 01304 { 01305 DPRINT1("exception raised while verifying block\n"); 01306 } 01307 01308 DPRINT1("Corrupted heap block %p\n", Block); 01309 } 01310 01311 BOOLEAN NTAPI 01312 RtlpDphIsPageHeapBlock(PDPH_HEAP_ROOT DphRoot, 01313 PVOID Block, 01314 PULONG ValidationInformation, 01315 BOOLEAN CheckFillers) 01316 { 01317 PDPH_BLOCK_INFORMATION BlockInfo; 01318 BOOLEAN SomethingWrong = FALSE; 01319 PUCHAR Byte, Start, End; 01320 01321 ASSERT(ValidationInformation != NULL); 01322 *ValidationInformation = 0; 01323 01324 // _SEH2_TRY { 01325 BlockInfo = (PDPH_BLOCK_INFORMATION)Block - 1; 01326 01327 /* Check stamps */ 01328 if (BlockInfo->StartStamp != DPH_FILL_START_STAMP_1) 01329 { 01330 *ValidationInformation |= DPH_VALINFO_BAD_START_STAMP; 01331 SomethingWrong = TRUE; 01332 01333 /* Check if it has an alloc/free mismatch */ 01334 if (BlockInfo->StartStamp == DPH_FILL_START_STAMP_2) 01335 { 01336 /* Notify respectively */ 01337 *ValidationInformation = 0x101; 01338 } 01339 } 01340 01341 if (BlockInfo->EndStamp != DPH_FILL_END_STAMP_1) 01342 { 01343 *ValidationInformation |= DPH_VALINFO_BAD_END_STAMP; 01344 SomethingWrong = TRUE; 01345 } 01346 01347 /* Check root heap pointer */ 01348 if (BlockInfo->Heap != DphRoot) 01349 { 01350 *ValidationInformation |= DPH_VALINFO_BAD_POINTER; 01351 SomethingWrong = TRUE; 01352 } 01353 01354 /* Check other fillers if requested */ 01355 if (CheckFillers) 01356 { 01357 /* Check space after the block */ 01358 Start = (PUCHAR)Block + BlockInfo->RequestedSize; 01359 End = (PUCHAR)ROUND_UP(Start, PAGE_SIZE); 01360 for (Byte = Start; Byte < End; Byte++) 01361 { 01362 if (*Byte != DPH_FILL_SUFFIX) 01363 { 01364 *ValidationInformation |= DPH_VALINFO_BAD_SUFFIX_PATTERN; 01365 SomethingWrong = TRUE; 01366 break; 01367 } 01368 } 01369 } 01370 01371 return (SomethingWrong == FALSE); 01372 } 01373 01374 BOOLEAN NTAPI 01375 RtlpDphIsNormalFreeHeapBlock(PVOID Block, 01376 PULONG ValidationInformation, 01377 BOOLEAN CheckFillers) 01378 { 01379 ASSERT(ValidationInformation != NULL); 01380 01381 UNIMPLEMENTED; 01382 *ValidationInformation = 0; 01383 return TRUE; 01384 } 01385 01386 NTSTATUS NTAPI 01387 RtlpDphProcessStartupInitialization() 01388 { 01389 NTSTATUS Status; 01390 PTEB Teb = NtCurrentTeb(); 01391 01392 /* Initialize the DPH heap list and its critical section */ 01393 InitializeListHead(&RtlpDphPageHeapList); 01394 Status = RtlInitializeCriticalSection(&RtlpDphPageHeapListLock); 01395 if (!NT_SUCCESS(Status)) 01396 { 01397 ASSERT(FALSE); 01398 return Status; 01399 } 01400 01401 /* Initialize delayed-free queue */ 01402 Status = RtlpDphInitializeDelayedFreeQueue(); 01403 if (!NT_SUCCESS(Status)) return Status; 01404 01405 /* Initialize the target dlls string */ 01406 RtlInitUnicodeString(&RtlpDphTargetDllsUnicode, RtlpDphTargetDlls); 01407 Status = RtlpDphTargetDllsLogicInitialize(); 01408 01409 /* Per-process DPH init is done */ 01410 RtlpDphPageHeapListInitialized = TRUE; 01411 01412 DPRINT1("Page heap: pid 0x%X: page heap enabled with flags 0x%X.\n", Teb->ClientId.UniqueProcess, RtlpDphGlobalFlags); 01413 01414 return Status; 01415 } 01416 01417 BOOLEAN NTAPI 01418 RtlpDphShouldAllocateInPageHeap(PDPH_HEAP_ROOT DphRoot, 01419 SIZE_T Size) 01420 { 01421 //UNIMPLEMENTED; 01422 /* Always use page heap for now */ 01423 return TRUE; 01424 } 01425 01426 HANDLE NTAPI 01427 RtlpPageHeapCreate(ULONG Flags, 01428 PVOID Addr, 01429 SIZE_T TotalSize, 01430 SIZE_T CommitSize, 01431 PVOID Lock, 01432 PRTL_HEAP_PARAMETERS Parameters) 01433 { 01434 PVOID Base = NULL; 01435 PHEAP HeapPtr; 01436 PDPH_HEAP_ROOT DphRoot; 01437 PDPH_HEAP_BLOCK DphNode; 01438 ULONG MemSize; 01439 NTSTATUS Status; 01440 LARGE_INTEGER PerfCounter; 01441 01442 /* Check for a DPH bypass flag */ 01443 if ((ULONG_PTR)Parameters == -1) return NULL; 01444 01445 /* Make sure no user-allocated stuff was provided */ 01446 if (Addr || Lock) return NULL; 01447 01448 /* Allocate minimum amount of virtual memory */ 01449 MemSize = DPH_RESERVE_SIZE; 01450 Status = RtlpDphAllocateVm(&Base, MemSize, MEM_COMMIT, PAGE_NOACCESS); 01451 if (!NT_SUCCESS(Status)) 01452 { 01453 ASSERT(FALSE); 01454 return NULL; 01455 } 01456 01457 /* Set protection */ 01458 Status = RtlpDphProtectVm(Base, 2*PAGE_SIZE + DPH_POOL_SIZE, PAGE_READWRITE); 01459 if (!NT_SUCCESS(Status)) 01460 { 01461 //RtlpDphFreeVm(Base, 0, 0, 0); 01462 ASSERT(FALSE); 01463 return NULL; 01464 } 01465 01466 /* Start preparing the 1st page. Fill it with the default filler */ 01467 RtlFillMemoryUlong(Base, PAGE_SIZE, DPH_FILL); 01468 01469 /* Set flags in the "HEAP" structure */ 01470 HeapPtr = (PHEAP)Base; 01471 HeapPtr->Flags = Flags | HEAP_FLAG_PAGE_ALLOCS; 01472 HeapPtr->ForceFlags = Flags | HEAP_FLAG_PAGE_ALLOCS; 01473 01474 /* Set 1st page to read only now */ 01475 Status = RtlpDphProtectVm(Base, PAGE_SIZE, PAGE_READONLY); 01476 if (!NT_SUCCESS(Status)) 01477 { 01478 ASSERT(FALSE); 01479 return NULL; 01480 } 01481 01482 /* 2nd page is the real DPH root block */ 01483 DphRoot = (PDPH_HEAP_ROOT)((PCHAR)Base + PAGE_SIZE); 01484 01485 /* Initialize the DPH root */ 01486 DphRoot->Signature = DPH_SIGNATURE; 01487 DphRoot->HeapFlags = Flags; 01488 DphRoot->HeapCritSect = (PRTL_CRITICAL_SECTION)((PCHAR)DphRoot + DPH_POOL_SIZE); 01489 DphRoot->ExtraFlags = RtlpDphGlobalFlags; 01490 01491 ZwQueryPerformanceCounter(&PerfCounter, NULL); 01492 DphRoot->Seed = PerfCounter.LowPart; 01493 01494 RtlInitializeCriticalSection(DphRoot->HeapCritSect); 01495 InitializeListHead(&DphRoot->AvailableAllocationHead); 01496 01497 /* Create a normal heap for this paged heap */ 01498 DphRoot->NormalHeap = RtlCreateHeap(Flags, NULL, TotalSize, CommitSize, NULL, (PRTL_HEAP_PARAMETERS)-1); 01499 if (!DphRoot->NormalHeap) 01500 { 01501 ASSERT(FALSE); 01502 return NULL; 01503 } 01504 01505 /* 3rd page: a pool for DPH allocations */ 01506 RtlpDphAddNewPool(DphRoot, NULL, DphRoot + 1, DPH_POOL_SIZE - sizeof(DPH_HEAP_ROOT), FALSE); 01507 01508 /* Allocate internal heap blocks. For the root */ 01509 DphNode = RtlpDphAllocateNode(DphRoot); 01510 ASSERT(DphNode != NULL); 01511 DphNode->pVirtualBlock = (PUCHAR)DphRoot; 01512 DphNode->nVirtualBlockSize = DPH_POOL_SIZE; 01513 RtlpDphPlaceOnPoolList(DphRoot, DphNode); 01514 01515 /* For the memory we allocated as a whole */ 01516 DphNode = RtlpDphAllocateNode(DphRoot); 01517 ASSERT(DphNode != NULL); 01518 DphNode->pVirtualBlock = Base; 01519 DphNode->nVirtualBlockSize = MemSize; 01520 RtlpDphPlaceOnVirtualList(DphRoot, DphNode); 01521 01522 /* For the remaining part */ 01523 DphNode = RtlpDphAllocateNode(DphRoot); 01524 ASSERT(DphNode != NULL); 01525 DphNode->pVirtualBlock = (PUCHAR)Base + 2*PAGE_SIZE + DPH_POOL_SIZE; 01526 DphNode->nVirtualBlockSize = MemSize - (2*PAGE_SIZE + DPH_POOL_SIZE); 01527 RtlpDphCoalesceNodeIntoAvailable(DphRoot, DphNode); 01528 01529 //DphRoot->CreateStackTrace = RtlpDphLogStackTrace(1); 01530 01531 /* Initialize AVL-based busy nodes table */ 01532 RtlInitializeGenericTableAvl(&DphRoot->BusyNodesTable, 01533 RtlpDphCompareNodeForTable, 01534 RtlpDphAllocateNodeForTable, 01535 RtlpDphFreeNodeForTable, 01536 NULL); 01537 01538 /* Initialize per-process startup info */ 01539 if (!RtlpDphPageHeapListInitialized) RtlpDphProcessStartupInitialization(); 01540 01541 /* Acquire the heap list lock */ 01542 RtlEnterCriticalSection(&RtlpDphPageHeapListLock); 01543 01544 /* Insert this heap to the tail of the global list */ 01545 InsertTailList(&RtlpDphPageHeapList, &DphRoot->NextHeap); 01546 01547 /* Note we increased the size of the list */ 01548 RtlpDphPageHeapListLength++; 01549 01550 /* Release the heap list lock */ 01551 RtlLeaveCriticalSection(&RtlpDphPageHeapListLock); 01552 01553 if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE) 01554 { 01555 DPRINT1("Page heap: process 0x%X created heap @ %p (%p, flags 0x%X)\n", 01556 NtCurrentTeb()->ClientId.UniqueProcess, (PUCHAR)DphRoot - PAGE_SIZE, DphRoot->NormalHeap, DphRoot->ExtraFlags); 01557 } 01558 01559 /* Perform internal validation if required */ 01560 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 01561 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 01562 01563 return (PUCHAR)DphRoot - PAGE_SIZE; 01564 } 01565 01566 PVOID NTAPI 01567 RtlpPageHeapDestroy(HANDLE HeapPtr) 01568 { 01569 PDPH_HEAP_ROOT DphRoot; 01570 PDPH_HEAP_BLOCK Node, Next; 01571 PHEAP NormalHeap; 01572 ULONG Value; 01573 01574 /* Check if it's not a process heap */ 01575 if (HeapPtr == RtlGetProcessHeap()) 01576 { 01577 DbgBreakPoint(); 01578 return NULL; 01579 } 01580 01581 /* Get pointer to the heap root */ 01582 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 01583 if (!DphRoot) return NULL; 01584 01585 RtlpDphPreProcessing(DphRoot, DphRoot->HeapFlags); 01586 01587 /* Get the pointer to the normal heap */ 01588 NormalHeap = DphRoot->NormalHeap; 01589 01590 /* Free the delayed-free blocks */ 01591 RtlpDphFreeDelayedBlocksFromHeap(DphRoot, NormalHeap); 01592 01593 /* Go through the busy blocks */ 01594 Node = RtlEnumerateGenericTableAvl(&DphRoot->BusyNodesTable, TRUE); 01595 01596 while (Node) 01597 { 01598 if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)) 01599 { 01600 if (!RtlpDphIsPageHeapBlock(DphRoot, Node->pUserAllocation, &Value, TRUE)) 01601 { 01602 RtlpDphReportCorruptedBlock(DphRoot, 3, Node->pUserAllocation, Value); 01603 } 01604 } 01605 01606 /* FIXME: Call AV notification */ 01607 //AVrfInternalHeapFreeNotification(); 01608 01609 /* Go to the next node */ 01610 Node = RtlEnumerateGenericTableAvl(&DphRoot->BusyNodesTable, FALSE); 01611 } 01612 01613 /* Acquire the global heap list lock */ 01614 RtlEnterCriticalSection(&RtlpDphPageHeapListLock); 01615 01616 /* Remove the entry and decrement the global counter */ 01617 RemoveEntryList(&DphRoot->NextHeap); 01618 RtlpDphPageHeapListLength--; 01619 01620 /* Release the global heap list lock */ 01621 RtlLeaveCriticalSection(&RtlpDphPageHeapListLock); 01622 01623 /* Leave and delete this heap's critical section */ 01624 RtlLeaveCriticalSection(DphRoot->HeapCritSect); 01625 RtlDeleteCriticalSection(DphRoot->HeapCritSect); 01626 01627 /* Now go through all virtual list nodes and release the VM */ 01628 Node = DphRoot->pVirtualStorageListHead; 01629 while (Node) 01630 { 01631 Next = Node->pNextAlloc; 01632 /* Release the memory without checking result */ 01633 RtlpDphFreeVm(Node->pVirtualBlock, 0, MEM_RELEASE); 01634 Node = Next; 01635 } 01636 01637 /* Destroy the normal heap */ 01638 RtlDestroyHeap(NormalHeap); 01639 01640 /* Report success */ 01641 if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE) 01642 DPRINT1("Page heap: process 0x%X destroyed heap @ %p (%p)\n", NtCurrentTeb()->ClientId.UniqueProcess, HeapPtr, NormalHeap); 01643 01644 return NULL; 01645 } 01646 01647 PVOID NTAPI 01648 RtlpPageHeapAllocate(IN PVOID HeapPtr, 01649 IN ULONG Flags, 01650 IN SIZE_T Size) 01651 { 01652 PDPH_HEAP_ROOT DphRoot; 01653 PDPH_HEAP_BLOCK AvailableNode, BusyNode; 01654 BOOLEAN Biased = FALSE; 01655 ULONG AllocateSize, AccessSize; 01656 NTSTATUS Status; 01657 SIZE_T UserActualSize; 01658 PVOID Ptr; 01659 01660 /* Check requested size */ 01661 if (Size > 0x7FF00000) 01662 { 01663 DPRINT1("extreme size request\n"); 01664 01665 /* Generate an exception if needed */ 01666 if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY); 01667 01668 return NULL; 01669 } 01670 01671 /* Unbias the pointer if necessary */ 01672 if (IS_BIASED_POINTER(HeapPtr)) 01673 { 01674 HeapPtr = (PVOID)POINTER_REMOVE_BIAS(HeapPtr); 01675 Biased = TRUE; 01676 } 01677 01678 /* Get a pointer to the heap root */ 01679 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 01680 if (!DphRoot) return NULL; 01681 01682 /* Acquire the heap lock */ 01683 RtlpDphPreProcessing(DphRoot, Flags); 01684 01685 /* Perform internal validation if specified by flags */ 01686 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased) 01687 { 01688 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 01689 } 01690 01691 /* Add heap flags */ 01692 Flags |= DphRoot->HeapFlags; 01693 01694 if (!Biased && !RtlpDphShouldAllocateInPageHeap(DphRoot, Size)) 01695 { 01696 /* Perform allocation from a normal heap */ 01697 ASSERT(FALSE); 01698 } 01699 01700 /* Perform heap integrity check if specified by flags */ 01701 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 01702 { 01703 RtlpDphVerifyIntegrity(DphRoot); 01704 } 01705 01706 /* Calculate sizes */ 01707 AccessSize = ROUND_UP(Size + sizeof(DPH_BLOCK_INFORMATION), PAGE_SIZE); 01708 AllocateSize = AccessSize + PAGE_SIZE; 01709 01710 // FIXME: Move RtlpDphAllocateNode(DphRoot) to this place 01711 AvailableNode = RtlpDphFindAvailableMemory(DphRoot, AllocateSize, TRUE); 01712 if (!AvailableNode) 01713 { 01714 DPRINT1("Page heap: Unable to allocate virtual memory\n"); 01715 DbgBreakPoint(); 01716 01717 /* Release the lock */ 01718 RtlpDphPostProcessing(DphRoot); 01719 01720 return NULL; 01721 } 01722 ASSERT(AvailableNode->nVirtualBlockSize >= AllocateSize); 01723 01724 /* Set protection */ 01725 Status = RtlpDphSetProtectionBeforeUse(DphRoot, 01726 AvailableNode->pVirtualBlock, 01727 AccessSize); 01728 if (!NT_SUCCESS(Status)) 01729 { 01730 ASSERT(FALSE); 01731 } 01732 01733 /* Save available node pointer */ 01734 Ptr = AvailableNode->pVirtualBlock; 01735 01736 /* Check node's size */ 01737 if (AvailableNode->nVirtualBlockSize > AllocateSize) 01738 { 01739 /* The block contains too much free space, reduce it */ 01740 AvailableNode->pVirtualBlock += AllocateSize; 01741 AvailableNode->nVirtualBlockSize -= AllocateSize; 01742 DphRoot->nAvailableAllocationBytesCommitted -= AllocateSize; 01743 01744 /* Allocate a new node which will be our busy node */ 01745 BusyNode = RtlpDphAllocateNode(DphRoot); 01746 ASSERT(BusyNode != NULL); 01747 BusyNode->pVirtualBlock = Ptr; 01748 BusyNode->nVirtualBlockSize = AllocateSize; 01749 } 01750 else 01751 { 01752 /* The block's size fits exactly */ 01753 RtlpDphRemoveFromAvailableList(DphRoot, AvailableNode); 01754 BusyNode = AvailableNode; 01755 } 01756 01757 /* Calculate actual user size */ 01758 if (DphRoot->HeapFlags & HEAP_NO_ALIGNMENT) 01759 UserActualSize = Size; 01760 else 01761 UserActualSize = ROUND_UP(Size, 8); 01762 01763 /* Set up the block */ 01764 BusyNode->nVirtualAccessSize = AccessSize; 01765 BusyNode->nUserActualSize = UserActualSize; 01766 BusyNode->nUserRequestedSize = Size; 01767 01768 if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN) 01769 BusyNode->pUserAllocation = BusyNode->pVirtualBlock + PAGE_SIZE; 01770 else 01771 BusyNode->pUserAllocation = BusyNode->pVirtualBlock + BusyNode->nVirtualAccessSize - UserActualSize; 01772 01773 BusyNode->UserValue = NULL; 01774 BusyNode->UserFlags = Flags & HEAP_SETTABLE_USER_FLAGS; 01775 01776 // FIXME: Don't forget about stack traces if such flag was set 01777 BusyNode->StackTrace = NULL; 01778 01779 /* Place it on busy list */ 01780 RtlpDphPlaceOnBusyList(DphRoot, BusyNode); 01781 01782 /* Zero or patter-fill memory depending on flags */ 01783 if (Flags & HEAP_ZERO_MEMORY) 01784 RtlZeroMemory(BusyNode->pUserAllocation, Size); 01785 else 01786 RtlFillMemory(BusyNode->pUserAllocation, Size, DPH_FILL_INFIX); 01787 01788 /* Write DPH info */ 01789 if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)) 01790 { 01791 RtlpDphWritePageHeapBlockInformation(DphRoot, 01792 BusyNode->pUserAllocation, 01793 Size, 01794 AccessSize); 01795 } 01796 01797 /* Finally allocation is done, perform validation again if required */ 01798 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased) 01799 { 01800 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 01801 } 01802 01803 /* Release the lock */ 01804 RtlpDphPostProcessing(DphRoot); 01805 01806 DPRINT("Allocated user block pointer: %p\n", BusyNode->pUserAllocation); 01807 01808 /* Return pointer to user allocation */ 01809 return BusyNode->pUserAllocation; 01810 } 01811 01812 BOOLEAN NTAPI 01813 RtlpPageHeapFree(HANDLE HeapPtr, 01814 ULONG Flags, 01815 PVOID Ptr) 01816 { 01817 PDPH_HEAP_ROOT DphRoot; 01818 PDPH_HEAP_BLOCK Node; 01819 ULONG ValidationInfo; 01820 PDPH_BLOCK_INFORMATION Info; 01821 01822 /* Check for a NULL pointer freeing */ 01823 if (!Ptr) 01824 { 01825 if (RtlpDphBreakOptions & DPH_BREAK_ON_NULL_FREE) 01826 { 01827 DPRINT1("Page heap: freeing a null pointer \n"); 01828 DbgBreakPoint(); 01829 } 01830 return TRUE; 01831 } 01832 01833 /* Get a pointer to the heap root */ 01834 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 01835 if (!DphRoot) return FALSE; 01836 01837 /* Acquire the heap lock */ 01838 RtlpDphPreProcessing(DphRoot, Flags); 01839 01840 /* Perform internal validation if specified by flags */ 01841 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 01842 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 01843 01844 /* Add heap flags */ 01845 Flags |= DphRoot->HeapFlags; 01846 01847 /* Find busy memory */ 01848 Node = RtlpDphFindBusyMemory(DphRoot, Ptr); 01849 01850 if (!Node) 01851 { 01852 /* This block was not found in page heap, try a normal heap instead */ 01853 //RtlpDphNormalHeapFree(); 01854 ASSERT(FALSE); 01855 } 01856 01857 if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)) 01858 { 01859 /* Check and report corrupted block */ 01860 if (!RtlpDphIsPageHeapBlock(DphRoot, Ptr, &ValidationInfo, TRUE)) 01861 { 01862 RtlpDphReportCorruptedBlock(DphRoot, 1, Ptr, ValidationInfo); 01863 } 01864 01865 // FIXME: Should go inside RtlpDphSetProtectionAfterUse 01866 if (Node->nVirtualAccessSize != 0) 01867 { 01868 /* Set stamps */ 01869 Info = (PDPH_BLOCK_INFORMATION)Node->pUserAllocation - 1; 01870 Info->StartStamp = DPH_FILL_START_STAMP_2; 01871 Info->EndStamp = DPH_FILL_END_STAMP_2; 01872 01873 RtlpDphProtectVm(Node->pVirtualBlock, Node->nVirtualAccessSize, PAGE_NOACCESS); 01874 } 01875 } 01876 else 01877 { 01878 // FIXME: Should go inside RtlpDphSetProtectionAfterUse 01879 if (Node->nVirtualAccessSize != 0) 01880 RtlpDphProtectVm(Node->pVirtualBlock + PAGE_SIZE, Node->nVirtualAccessSize, PAGE_NOACCESS); 01881 } 01882 01883 /* Set new protection */ 01884 //RtlpDphSetProtectionAfterUse(DphRoot, Node); 01885 01886 /* Remove it from the list of busy nodes */ 01887 RtlpDphRemoveFromBusyList(DphRoot, Node); 01888 01889 /* And put it into the list of free nodes */ 01890 RtlpDphPlaceOnFreeList(DphRoot, Node); 01891 01892 //if (DphRoot->ExtraFlags & DPH_EXTRA_LOG_STACK_TRACES) 01893 // Node->StackTrace = RtlpDphLogStackTrace(3); 01894 //else 01895 Node->StackTrace = NULL; 01896 01897 /* Leave the heap lock */ 01898 RtlpDphPostProcessing(DphRoot); 01899 01900 /* Return success */ 01901 return TRUE; 01902 } 01903 01904 PVOID NTAPI 01905 RtlpPageHeapReAllocate(HANDLE HeapPtr, 01906 ULONG Flags, 01907 PVOID Ptr, 01908 SIZE_T Size) 01909 { 01910 PDPH_HEAP_ROOT DphRoot; 01911 PDPH_HEAP_BLOCK Node = NULL, AllocatedNode; 01912 BOOLEAN Biased = FALSE, UseNormalHeap = FALSE, OldBlockPageHeap = TRUE; 01913 ULONG ValidationInfo; 01914 SIZE_T DataSize; 01915 PVOID NewAlloc = NULL; 01916 01917 /* Check requested size */ 01918 if (Size > 0x7FF00000) 01919 { 01920 DPRINT1("extreme size request\n"); 01921 01922 /* Generate an exception if needed */ 01923 if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY); 01924 01925 return NULL; 01926 } 01927 01928 /* Unbias the pointer if necessary */ 01929 if (IS_BIASED_POINTER(HeapPtr)) 01930 { 01931 HeapPtr = (PVOID)POINTER_REMOVE_BIAS(HeapPtr); 01932 Biased = TRUE; 01933 } 01934 01935 /* Get a pointer to the heap root */ 01936 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 01937 if (!DphRoot) return NULL; 01938 01939 /* Acquire the heap lock */ 01940 RtlpDphPreProcessing(DphRoot, Flags); 01941 01942 /* Perform internal validation if specified by flags */ 01943 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 01944 { 01945 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 01946 } 01947 01948 /* Add heap flags */ 01949 Flags |= DphRoot->HeapFlags; 01950 01951 /* Exit with NULL right away if inplace is specified */ 01952 if (Flags & HEAP_REALLOC_IN_PLACE_ONLY) 01953 { 01954 /* Release the lock */ 01955 RtlpDphPostProcessing(DphRoot); 01956 01957 /* Generate an exception if needed */ 01958 if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY); 01959 01960 return NULL; 01961 } 01962 01963 /* Try to get node of the allocated block */ 01964 AllocatedNode = RtlpDphFindBusyMemory(DphRoot, Ptr); 01965 01966 if (!AllocatedNode) 01967 { 01968 /* This block was not found in page heap, try a normal heap instead */ 01969 //RtlpDphNormalHeapFree(); 01970 ASSERT(FALSE); 01971 OldBlockPageHeap = FALSE; 01972 } 01973 01974 /* Check the block */ 01975 if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)) 01976 { 01977 if (!RtlpDphIsPageHeapBlock(DphRoot, AllocatedNode->pUserAllocation, &ValidationInfo, TRUE)) 01978 { 01979 RtlpDphReportCorruptedBlock(DphRoot, 3, AllocatedNode->pUserAllocation, ValidationInfo); 01980 } 01981 } 01982 01983 /* Remove old one from the busy list */ 01984 RtlpDphRemoveFromBusyList(DphRoot, AllocatedNode); 01985 01986 if (!Biased && !RtlpDphShouldAllocateInPageHeap(DphRoot, Size)) 01987 { 01988 // FIXME: Use normal heap 01989 ASSERT(FALSE); 01990 UseNormalHeap = TRUE; 01991 } 01992 else 01993 { 01994 /* Now do a trick: bias the pointer and call our allocate routine */ 01995 NewAlloc = RtlpPageHeapAllocate((PVOID)POINTER_ADD_BIAS(HeapPtr), Flags, Size); 01996 } 01997 01998 if (!NewAlloc) 01999 { 02000 /* New allocation failed, put the block back (if it was found in page heap) */ 02001 RtlpDphPlaceOnBusyList(DphRoot, AllocatedNode); 02002 02003 /* Release the lock */ 02004 RtlpDphPostProcessing(DphRoot); 02005 02006 /* Perform validation again if required */ 02007 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 02008 { 02009 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 02010 } 02011 02012 /* Generate an exception if needed */ 02013 if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY); 02014 02015 return NULL; 02016 } 02017 02018 /* Copy contents of the old block */ 02019 if (AllocatedNode->nUserRequestedSize > Size) 02020 DataSize = Size; 02021 else 02022 DataSize = AllocatedNode->nUserRequestedSize; 02023 02024 if (DataSize != 0) RtlCopyMemory(NewAlloc, Ptr, DataSize); 02025 02026 /* Copy user flags and values */ 02027 if (!UseNormalHeap) 02028 { 02029 /* Get the node of the new block */ 02030 Node = RtlpDphFindBusyMemory(DphRoot, NewAlloc); 02031 ASSERT(Node != NULL); 02032 02033 /* Set its values/flags */ 02034 Node->UserValue = AllocatedNode->UserValue; 02035 if (Flags & HEAP_SETTABLE_USER_FLAGS) 02036 Node->UserFlags = Flags & HEAP_SETTABLE_USER_FLAGS; 02037 else 02038 Node->UserFlags = AllocatedNode->UserFlags; 02039 } 02040 02041 if (!OldBlockPageHeap) 02042 { 02043 /* Weird scenario, investigate */ 02044 ASSERT(FALSE); 02045 } 02046 02047 /* Mark the old block as no access */ 02048 if (AllocatedNode->nVirtualAccessSize != 0) 02049 { 02050 RtlpDphProtectVm(AllocatedNode->pVirtualBlock, AllocatedNode->nVirtualAccessSize, PAGE_NOACCESS); 02051 } 02052 02053 /* And place it on the free list */ 02054 RtlpDphPlaceOnFreeList(DphRoot, AllocatedNode); 02055 02056 // FIXME: Capture stack traces if needed 02057 AllocatedNode->StackTrace = NULL; 02058 02059 /* Finally allocation is done, perform validation again if required */ 02060 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased) 02061 { 02062 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 02063 } 02064 02065 /* Release the lock */ 02066 RtlpDphPostProcessing(DphRoot); 02067 02068 DPRINT("Allocated new user block pointer: %p\n", NewAlloc); 02069 02070 /* Return pointer to user allocation */ 02071 return NewAlloc; 02072 } 02073 02074 BOOLEAN NTAPI 02075 RtlpPageHeapGetUserInfo(PVOID HeapHandle, 02076 ULONG Flags, 02077 PVOID BaseAddress, 02078 PVOID *UserValue, 02079 PULONG UserFlags) 02080 { 02081 PDPH_HEAP_ROOT DphRoot; 02082 PDPH_HEAP_BLOCK Node; 02083 02084 /* Get a pointer to the heap root */ 02085 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 02086 if (!DphRoot) return FALSE; 02087 02088 /* Add heap flags */ 02089 Flags |= DphRoot->HeapFlags; 02090 02091 /* Acquire the heap lock */ 02092 RtlpDphPreProcessing(DphRoot, Flags); 02093 02094 /* Find busy memory */ 02095 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 02096 02097 if (!Node) 02098 { 02099 /* This block was not found in page heap, try a normal heap instead */ 02100 //RtlpDphNormalHeapGetUserInfo(); 02101 ASSERT(FALSE); 02102 return FALSE; 02103 } 02104 02105 /* Get user values and flags and store them in user provided pointers */ 02106 if (UserValue) *UserValue = Node->UserValue; 02107 if (UserFlags) *UserFlags = Node->UserFlags; 02108 02109 /* Leave the heap lock */ 02110 RtlpDphPostProcessing(DphRoot); 02111 02112 /* Return success */ 02113 return TRUE; 02114 } 02115 02116 BOOLEAN NTAPI 02117 RtlpPageHeapSetUserValue(PVOID HeapHandle, 02118 ULONG Flags, 02119 PVOID BaseAddress, 02120 PVOID UserValue) 02121 { 02122 PDPH_HEAP_ROOT DphRoot; 02123 PDPH_HEAP_BLOCK Node; 02124 02125 /* Get a pointer to the heap root */ 02126 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 02127 if (!DphRoot) return FALSE; 02128 02129 /* Add heap flags */ 02130 Flags |= DphRoot->HeapFlags; 02131 02132 /* Acquire the heap lock */ 02133 RtlpDphPreProcessing(DphRoot, Flags); 02134 02135 /* Find busy memory */ 02136 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 02137 02138 if (!Node) 02139 { 02140 /* This block was not found in page heap, try a normal heap instead */ 02141 //RtlpDphNormalHeapSetUserValue(); 02142 ASSERT(FALSE); 02143 return FALSE; 02144 } 02145 02146 /* Get user values and flags and store them in user provided pointers */ 02147 Node->UserValue = UserValue; 02148 02149 /* Leave the heap lock */ 02150 RtlpDphPostProcessing(DphRoot); 02151 02152 /* Return success */ 02153 return TRUE; 02154 } 02155 02156 BOOLEAN 02157 NTAPI 02158 RtlpPageHeapSetUserFlags(PVOID HeapHandle, 02159 ULONG Flags, 02160 PVOID BaseAddress, 02161 ULONG UserFlagsReset, 02162 ULONG UserFlagsSet) 02163 { 02164 PDPH_HEAP_ROOT DphRoot; 02165 PDPH_HEAP_BLOCK Node; 02166 02167 /* Get a pointer to the heap root */ 02168 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 02169 if (!DphRoot) return FALSE; 02170 02171 /* Add heap flags */ 02172 Flags |= DphRoot->HeapFlags; 02173 02174 /* Acquire the heap lock */ 02175 RtlpDphPreProcessing(DphRoot, Flags); 02176 02177 /* Find busy memory */ 02178 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 02179 02180 if (!Node) 02181 { 02182 /* This block was not found in page heap, try a normal heap instead */ 02183 //RtlpDphNormalHeapSetUserFlags(); 02184 ASSERT(FALSE); 02185 return FALSE; 02186 } 02187 02188 /* Get user values and flags and store them in user provided pointers */ 02189 Node->UserFlags &= ~(UserFlagsReset); 02190 Node->UserFlags |= UserFlagsSet; 02191 02192 /* Leave the heap lock */ 02193 RtlpDphPostProcessing(DphRoot); 02194 02195 /* Return success */ 02196 return TRUE; 02197 } 02198 02199 SIZE_T NTAPI 02200 RtlpPageHeapSize(HANDLE HeapHandle, 02201 ULONG Flags, 02202 PVOID BaseAddress) 02203 { 02204 PDPH_HEAP_ROOT DphRoot; 02205 PDPH_HEAP_BLOCK Node; 02206 SIZE_T Size; 02207 02208 /* Get a pointer to the heap root */ 02209 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 02210 if (!DphRoot) return -1; 02211 02212 /* Add heap flags */ 02213 Flags |= DphRoot->HeapFlags; 02214 02215 /* Acquire the heap lock */ 02216 RtlpDphPreProcessing(DphRoot, Flags); 02217 02218 /* Find busy memory */ 02219 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 02220 02221 if (!Node) 02222 { 02223 /* This block was not found in page heap, try a normal heap instead */ 02224 //RtlpDphNormalHeapSize(); 02225 ASSERT(FALSE); 02226 return -1; 02227 } 02228 02229 /* Get heap block size */ 02230 Size = Node->nUserRequestedSize; 02231 02232 /* Leave the heap lock */ 02233 RtlpDphPostProcessing(DphRoot); 02234 02235 /* Return user requested size */ 02236 return Size; 02237 } 02238 02239 BOOLEAN 02240 NTAPI 02241 RtlpDebugPageHeapValidate(PVOID HeapHandle, 02242 ULONG Flags, 02243 PVOID BaseAddress) 02244 { 02245 PDPH_HEAP_ROOT DphRoot; 02246 PDPH_HEAP_BLOCK Node = NULL; 02247 BOOLEAN Valid = FALSE; 02248 02249 /* Get a pointer to the heap root */ 02250 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 02251 if (!DphRoot) return -1; 02252 02253 /* Add heap flags */ 02254 Flags |= DphRoot->HeapFlags; 02255 02256 /* Acquire the heap lock */ 02257 RtlpDphPreProcessing(DphRoot, Flags); 02258 02259 /* Find busy memory */ 02260 if (BaseAddress) 02261 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 02262 02263 if (!Node) 02264 { 02265 /* This block was not found in page heap, or the request is to validate all normal heap */ 02266 Valid = RtlpDphNormalHeapValidate(DphRoot, Flags, BaseAddress); 02267 } 02268 02269 /* Leave the heap lock */ 02270 RtlpDphPostProcessing(DphRoot); 02271 02272 /* Return result of a normal heap validation */ 02273 if (BaseAddress && !Node) 02274 return Valid; 02275 02276 /* Otherwise return our own result */ 02277 if (!BaseAddress || Node) Valid = TRUE; 02278 02279 return Valid; 02280 } 02281 02282 BOOLEAN 02283 NTAPI 02284 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot, 02285 ULONG Flags, 02286 PVOID BaseAddress) 02287 { 02288 PDPH_BLOCK_INFORMATION BlockInfo = (PDPH_BLOCK_INFORMATION)BaseAddress - 1; 02289 if (!BaseAddress) 02290 { 02291 /* Validate all normal heap */ 02292 return RtlValidateHeap(DphRoot->NormalHeap, Flags, NULL); 02293 } 02294 02295 // FIXME: Check is this a normal heap block 02296 /*if (!RtlpDphIsNormalHeapBlock(DphRoot, BaseAddress, &ValidationInfo)) 02297 { 02298 }*/ 02299 02300 return RtlValidateHeap(DphRoot->NormalHeap, Flags, BlockInfo); 02301 } 02302 02303 /* EOF */ Generated on Sun May 27 2012 04:36:22 for ReactOS by
1.7.6.1
|