Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2772 lines
96 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. heap.c
  5. Abstract:
  6. This module implements a heap allocator.
  7. Author:
  8. Steve Wood (stevewo) 20-Sep-1989 (Adapted from URTL\alloc.c)
  9. Revision History:
  10. --*/
  11. #include "ntrtlp.h"
  12. #include "heap.h"
  13. #include "heappriv.h"
  14. #if defined(NTOS_KERNEL_RUNTIME)
  15. #if defined(ALLOC_PRAGMA)
  16. PHEAP_UNCOMMMTTED_RANGE
  17. RtlpCreateUnCommittedRange(
  18. IN PHEAP_SEGMENT Segment
  19. );
  20. VOID
  21. RtlpDestroyUnCommittedRange(
  22. IN PHEAP_SEGMENT Segment,
  23. IN PHEAP_UNCOMMMTTED_RANGE UnCommittedRange
  24. );
  25. VOID
  26. RtlpInsertUnCommittedPages(
  27. IN PHEAP_SEGMENT Segment,
  28. IN ULONG Address,
  29. IN ULONG Size
  30. );
  31. NTSTATUS
  32. RtlpDestroyHeapSegment(
  33. IN PHEAP_SEGMENT Segment
  34. );
  35. PHEAP_FREE_ENTRY
  36. RtlpExtendHeap(
  37. IN PHEAP Heap,
  38. IN ULONG AllocationSize
  39. );
  40. #pragma alloc_text(PAGE, RtlpCreateUnCommittedRange)
  41. #pragma alloc_text(PAGE, RtlpDestroyUnCommittedRange)
  42. #pragma alloc_text(PAGE, RtlpInsertUnCommittedPages)
  43. #pragma alloc_text(PAGE, RtlpFindAndCommitPages)
  44. #pragma alloc_text(PAGE, RtlpInitializeHeapSegment)
  45. #pragma alloc_text(PAGE, RtlpDestroyHeapSegment)
  46. #pragma alloc_text(PAGE, RtlCreateHeap)
  47. #pragma alloc_text(PAGE, RtlDestroyHeap)
  48. #pragma alloc_text(PAGE, RtlpExtendHeap)
  49. #pragma alloc_text(PAGE, RtlpCoalesceFreeBlocks)
  50. #pragma alloc_text(PAGE, RtlpDeCommitFreeBlock)
  51. #pragma alloc_text(PAGE, RtlpInsertFreeBlock)
  52. #pragma alloc_text(PAGE, RtlAllocateHeap)
  53. #pragma alloc_text(PAGE, RtlFreeHeap)
  54. #pragma alloc_text(PAGE, RtlpGetSizeOfBigBlock)
  55. #pragma alloc_text(PAGE, RtlpCheckBusyBlockTail)
  56. #pragma alloc_text(PAGE, RtlZeroHeap)
  57. #endif
  58. #else
  59. PVOID
  60. RtlDebugCreateHeap(
  61. IN ULONG Flags,
  62. IN PVOID HeapBase OPTIONAL,
  63. IN ULONG ReserveSize OPTIONAL,
  64. IN ULONG CommitSize OPTIONAL,
  65. IN PVOID Lock OPTIONAL,
  66. IN PRTL_HEAP_PARAMETERS Parameters OPTIONAL
  67. );
  68. BOOLEAN
  69. RtlDebugDestroyHeap(
  70. IN PVOID HeapHandle
  71. );
  72. PVOID
  73. RtlDebugAllocateHeap(
  74. IN PVOID HeapHandle,
  75. IN ULONG Flags,
  76. IN ULONG Size
  77. );
  78. BOOLEAN
  79. RtlDebugFreeHeap(
  80. IN PVOID HeapHandle,
  81. IN ULONG Flags,
  82. IN PVOID BaseAddress
  83. );
  84. NTSTATUS
  85. RtlDebugZeroHeap(
  86. IN PVOID HeapHandle,
  87. IN ULONG Flags
  88. );
  89. PVOID
  90. RtlAllocateHeapSlowly(
  91. IN PVOID HeapHandle,
  92. IN ULONG Flags,
  93. IN ULONG Size
  94. );
  95. BOOLEAN
  96. RtlFreeHeapSlowly(
  97. IN PVOID HeapHandle,
  98. IN ULONG Flags,
  99. IN PVOID BaseAddress
  100. );
  101. #endif // NTOS_KERNEL_RUNTIME
  102. //
  103. // If any of these flags are set, the fast allocator punts
  104. // to the slow do-everything allocator.
  105. //
  106. #define HEAP_SLOW_FLAGS (HEAP_DEBUG_FLAGS | \
  107. HEAP_SETTABLE_USER_FLAGS | \
  108. HEAP_NEED_EXTRA_FLAGS | \
  109. HEAP_CREATE_ALIGN_16 | \
  110. HEAP_FREE_CHECKING_ENABLED | \
  111. HEAP_TAIL_CHECKING_ENABLED)
  112. UCHAR CheckHeapFillPattern[ CHECK_HEAP_TAIL_SIZE ] = {
  113. CHECK_HEAP_TAIL_FILL,
  114. CHECK_HEAP_TAIL_FILL,
  115. CHECK_HEAP_TAIL_FILL,
  116. CHECK_HEAP_TAIL_FILL,
  117. CHECK_HEAP_TAIL_FILL,
  118. CHECK_HEAP_TAIL_FILL,
  119. CHECK_HEAP_TAIL_FILL,
  120. CHECK_HEAP_TAIL_FILL
  121. };
  122. PHEAP_UNCOMMMTTED_RANGE
  123. RtlpCreateUnCommittedRange(
  124. IN PHEAP_SEGMENT Segment
  125. )
  126. {
  127. NTSTATUS Status;
  128. PVOID FirstEntry, LastEntry;
  129. PHEAP_UNCOMMMTTED_RANGE UnCommittedRange, *pp;
  130. ULONG ReserveSize, CommitSize;
  131. PHEAP_UCR_SEGMENT UCRSegment;
  132. RTL_PAGED_CODE();
  133. pp = &Segment->Heap->UnusedUnCommittedRanges;
  134. if (*pp == NULL) {
  135. UCRSegment = Segment->Heap->UCRSegments;
  136. if (UCRSegment == NULL ||
  137. UCRSegment->CommittedSize == UCRSegment->ReservedSize
  138. ) {
  139. ReserveSize = 0x10000;
  140. UCRSegment = NULL;
  141. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  142. &UCRSegment,
  143. 0,
  144. &ReserveSize,
  145. MEM_RESERVE,
  146. PAGE_READWRITE
  147. );
  148. if (!NT_SUCCESS( Status )) {
  149. return NULL;
  150. }
  151. CommitSize = 0x1000;
  152. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  153. &UCRSegment,
  154. 0,
  155. &CommitSize,
  156. MEM_COMMIT,
  157. PAGE_READWRITE
  158. );
  159. if (!NT_SUCCESS( Status )) {
  160. ZwFreeVirtualMemory( NtCurrentProcess(),
  161. &UCRSegment,
  162. &ReserveSize,
  163. MEM_RELEASE
  164. );
  165. return NULL;
  166. }
  167. UCRSegment->Next = Segment->Heap->UCRSegments;
  168. Segment->Heap->UCRSegments = UCRSegment;
  169. UCRSegment->ReservedSize = ReserveSize;
  170. UCRSegment->CommittedSize = CommitSize;
  171. FirstEntry = (PCHAR)(UCRSegment + 1);
  172. }
  173. else {
  174. CommitSize = 0x1000;
  175. FirstEntry = (PCHAR)UCRSegment + UCRSegment->CommittedSize;
  176. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  177. &FirstEntry,
  178. 0,
  179. &CommitSize,
  180. MEM_COMMIT,
  181. PAGE_READWRITE
  182. );
  183. if (!NT_SUCCESS( Status )) {
  184. return NULL;
  185. }
  186. UCRSegment->CommittedSize += CommitSize;
  187. }
  188. LastEntry = (PCHAR)UCRSegment + UCRSegment->CommittedSize;
  189. UnCommittedRange = (PHEAP_UNCOMMMTTED_RANGE)FirstEntry;
  190. pp = &Segment->Heap->UnusedUnCommittedRanges;
  191. while ((PCHAR)UnCommittedRange < (PCHAR)LastEntry) {
  192. *pp = UnCommittedRange;
  193. pp = &UnCommittedRange->Next;
  194. UnCommittedRange += 1;
  195. }
  196. *pp = NULL;
  197. pp = &Segment->Heap->UnusedUnCommittedRanges;
  198. }
  199. UnCommittedRange = *pp;
  200. *pp = UnCommittedRange->Next;
  201. return UnCommittedRange;
  202. }
  203. VOID
  204. RtlpDestroyUnCommittedRange(
  205. IN PHEAP_SEGMENT Segment,
  206. IN PHEAP_UNCOMMMTTED_RANGE UnCommittedRange
  207. )
  208. {
  209. RTL_PAGED_CODE();
  210. UnCommittedRange->Next = Segment->Heap->UnusedUnCommittedRanges;
  211. Segment->Heap->UnusedUnCommittedRanges = UnCommittedRange;
  212. UnCommittedRange->Address = 0;
  213. UnCommittedRange->Size = 0;
  214. return;
  215. }
  216. VOID
  217. RtlpInsertUnCommittedPages(
  218. IN PHEAP_SEGMENT Segment,
  219. IN ULONG Address,
  220. IN ULONG Size
  221. )
  222. {
  223. PHEAP_UNCOMMMTTED_RANGE UnCommittedRange, *pp;
  224. RTL_PAGED_CODE();
  225. pp = &Segment->UnCommittedRanges;
  226. while (UnCommittedRange = *pp) {
  227. if (UnCommittedRange->Address > Address) {
  228. if (Address + Size == UnCommittedRange->Address) {
  229. UnCommittedRange->Address = Address;
  230. UnCommittedRange->Size += Size;
  231. if (UnCommittedRange->Size > Segment->LargestUnCommittedRange) {
  232. Segment->LargestUnCommittedRange = UnCommittedRange->Size;
  233. }
  234. return;
  235. }
  236. break;
  237. }
  238. else
  239. if ((UnCommittedRange->Address + UnCommittedRange->Size) == Address) {
  240. Address = UnCommittedRange->Address;
  241. Size += UnCommittedRange->Size;
  242. *pp = UnCommittedRange->Next;
  243. RtlpDestroyUnCommittedRange( Segment, UnCommittedRange );
  244. Segment->NumberOfUnCommittedRanges -= 1;
  245. if (Size > Segment->LargestUnCommittedRange) {
  246. Segment->LargestUnCommittedRange = Size;
  247. }
  248. }
  249. else {
  250. pp = &UnCommittedRange->Next;
  251. }
  252. }
  253. UnCommittedRange = RtlpCreateUnCommittedRange( Segment );
  254. if (UnCommittedRange == NULL) {
  255. HeapDebugPrint(( "Abandoning uncommitted range (%x for %x)\n", Address, Size ));
  256. HeapDebugBreak( NULL );
  257. return;
  258. }
  259. UnCommittedRange->Address = Address;
  260. UnCommittedRange->Size = Size;
  261. UnCommittedRange->Next = *pp;
  262. *pp = UnCommittedRange;
  263. Segment->NumberOfUnCommittedRanges += 1;
  264. if (Size >= Segment->LargestUnCommittedRange) {
  265. Segment->LargestUnCommittedRange = Size;
  266. }
  267. return;
  268. }
  269. PHEAP_FREE_ENTRY
  270. RtlpFindAndCommitPages(
  271. IN PHEAP Heap,
  272. IN PHEAP_SEGMENT Segment,
  273. IN OUT PULONG Size,
  274. IN PVOID AddressWanted OPTIONAL
  275. )
  276. {
  277. NTSTATUS Status;
  278. PHEAP_ENTRY FirstEntry, LastEntry, PreviousLastEntry;
  279. PHEAP_UNCOMMMTTED_RANGE PreviousUnCommittedRange, UnCommittedRange, *pp;
  280. ULONG Address;
  281. RTL_PAGED_CODE();
  282. PreviousUnCommittedRange = NULL;
  283. pp = &Segment->UnCommittedRanges;
  284. while (UnCommittedRange = *pp) {
  285. if (UnCommittedRange->Size >= *Size &&
  286. (!ARGUMENT_PRESENT( AddressWanted ) || UnCommittedRange->Address == (ULONG)AddressWanted )
  287. ) {
  288. Address = UnCommittedRange->Address;
  289. if (Heap->CommitRoutine != NULL) {
  290. Status = (Heap->CommitRoutine)( Heap,
  291. (PVOID *)&Address,
  292. Size
  293. );
  294. }
  295. else {
  296. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  297. (PVOID *)&Address,
  298. 0,
  299. Size,
  300. MEM_COMMIT,
  301. PAGE_READWRITE
  302. );
  303. }
  304. if (!NT_SUCCESS( Status )) {
  305. return NULL;
  306. }
  307. HeapInternalTrace( Segment->Heap, (Segment->Heap->TraceBuffer, HEAP_TRACE_COMMIT_MEMORY, 2, Address, *Size) );
  308. Segment->NumberOfUnCommittedPages -= *Size / PAGE_SIZE;
  309. if (Segment->LargestUnCommittedRange == UnCommittedRange->Size) {
  310. Segment->LargestUnCommittedRange = 0;
  311. }
  312. FirstEntry = (PHEAP_ENTRY)Address;
  313. if (PreviousUnCommittedRange == NULL) {
  314. LastEntry = Segment->FirstEntry;
  315. }
  316. else {
  317. LastEntry = (PHEAP_ENTRY)(PreviousUnCommittedRange->Address +
  318. PreviousUnCommittedRange->Size);
  319. }
  320. while (!(LastEntry->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  321. PreviousLastEntry = LastEntry;
  322. LastEntry += LastEntry->Size;
  323. if ((PCHAR)LastEntry >= (PCHAR)Segment->LastValidEntry || LastEntry->Size==0) {
  324. HeapDebugPrint(( "Heap missing last entry in committed range near %x\n",
  325. PreviousLastEntry
  326. ));
  327. HeapDebugBreak( PreviousLastEntry );
  328. return NULL;
  329. }
  330. }
  331. LastEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
  332. UnCommittedRange->Address += *Size;
  333. UnCommittedRange->Size -= *Size;
  334. HeapInternalTrace( Segment->Heap, (Segment->Heap->TraceBuffer, HEAP_TRACE_COMMIT_INSERT, 3, LastEntry, UnCommittedRange->Address, UnCommittedRange->Size) );
  335. if (UnCommittedRange->Size == 0) {
  336. if (UnCommittedRange->Address == (ULONG)Segment->LastValidEntry) {
  337. FirstEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
  338. }
  339. else {
  340. FirstEntry->Flags = 0;
  341. }
  342. *pp = UnCommittedRange->Next;
  343. RtlpDestroyUnCommittedRange( Segment, UnCommittedRange );
  344. Segment->NumberOfUnCommittedRanges -= 1;
  345. }
  346. else {
  347. FirstEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
  348. }
  349. FirstEntry->SegmentIndex = LastEntry->SegmentIndex;
  350. FirstEntry->Size = (USHORT)(*Size >> HEAP_GRANULARITY_SHIFT);
  351. FirstEntry->PreviousSize = LastEntry->Size;
  352. HeapInternalTrace( Segment->Heap, (Segment->Heap->TraceBuffer, HEAP_TRACE_COMMIT_NEW_ENTRY, 3, FirstEntry, *(PULONG)FirstEntry, *((PULONG)FirstEntry+1)) );
  353. if (!(FirstEntry->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  354. (FirstEntry + FirstEntry->Size)->PreviousSize = FirstEntry->Size;
  355. }
  356. if (Segment->LargestUnCommittedRange == 0) {
  357. UnCommittedRange = Segment->UnCommittedRanges;
  358. while (UnCommittedRange != NULL) {
  359. if (UnCommittedRange->Size >= Segment->LargestUnCommittedRange) {
  360. Segment->LargestUnCommittedRange = UnCommittedRange->Size;
  361. }
  362. UnCommittedRange = UnCommittedRange->Next;
  363. }
  364. }
  365. return (PHEAP_FREE_ENTRY)FirstEntry;
  366. }
  367. else {
  368. PreviousUnCommittedRange = UnCommittedRange;
  369. pp = &UnCommittedRange->Next;
  370. }
  371. }
  372. return NULL;
  373. }
  374. BOOLEAN
  375. RtlpInitializeHeapSegment(
  376. IN PHEAP Heap,
  377. IN PHEAP_SEGMENT Segment,
  378. IN UCHAR SegmentIndex,
  379. IN ULONG Flags,
  380. IN PVOID BaseAddress,
  381. IN PVOID UnCommittedAddress,
  382. IN PVOID CommitLimitAddress
  383. )
  384. {
  385. NTSTATUS Status;
  386. PHEAP_ENTRY FirstEntry;
  387. USHORT PreviousSize, Size;
  388. ULONG NumberOfPages;
  389. ULONG NumberOfCommittedPages;
  390. ULONG NumberOfUnCommittedPages;
  391. ULONG CommitSize;
  392. RTL_PAGED_CODE();
  393. NumberOfPages = ((ULONG)CommitLimitAddress - (ULONG)BaseAddress) / PAGE_SIZE;
  394. FirstEntry = (PHEAP_ENTRY)ROUND_UP_TO_POWER2( Segment + 1,
  395. HEAP_GRANULARITY
  396. );
  397. if ((PVOID)Heap == BaseAddress) {
  398. PreviousSize = Heap->Entry.Size;
  399. }
  400. else {
  401. PreviousSize = 0;
  402. }
  403. Size = (USHORT)(((ULONG)FirstEntry - (ULONG)Segment) >> HEAP_GRANULARITY_SHIFT);
  404. if ((PCHAR)(FirstEntry + 1) >= (PCHAR)UnCommittedAddress) {
  405. if ((PCHAR)(FirstEntry + 1) >= (PCHAR)CommitLimitAddress) {
  406. return FALSE;
  407. }
  408. CommitSize = (PCHAR)(FirstEntry + 1) - (PCHAR)UnCommittedAddress;
  409. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  410. (PVOID *)&UnCommittedAddress,
  411. 0,
  412. &CommitSize,
  413. MEM_COMMIT,
  414. PAGE_READWRITE
  415. );
  416. if (!NT_SUCCESS( Status )) {
  417. return FALSE;
  418. }
  419. UnCommittedAddress = (PVOID)((PCHAR)UnCommittedAddress + CommitSize);
  420. }
  421. NumberOfUnCommittedPages = ((ULONG)CommitLimitAddress - (ULONG)UnCommittedAddress) / PAGE_SIZE;
  422. NumberOfCommittedPages = NumberOfPages - NumberOfUnCommittedPages;
  423. Segment->Entry.PreviousSize = PreviousSize;
  424. Segment->Entry.Size = Size;
  425. Segment->Entry.Flags = HEAP_ENTRY_BUSY;
  426. Segment->Entry.SegmentIndex = SegmentIndex;
  427. #if i386 && !NTOS_KERNEL_RUNTIME
  428. if (NtGlobalFlag & FLG_USER_STACK_TRACE_DB) {
  429. Segment->AllocatorBackTraceIndex = (USHORT)RtlLogStackBackTrace();
  430. }
  431. #endif // i386 && !NTOS_KERNEL_RUNTIME
  432. Segment->Signature = HEAP_SEGMENT_SIGNATURE;
  433. Segment->Flags = Flags;
  434. Segment->Heap = Heap;
  435. Segment->BaseAddress = BaseAddress;
  436. Segment->FirstEntry = FirstEntry;
  437. Segment->LastValidEntry = (PHEAP_ENTRY)((PCHAR)BaseAddress + (NumberOfPages * PAGE_SIZE));
  438. Segment->NumberOfPages = NumberOfPages;
  439. Segment->NumberOfUnCommittedPages = NumberOfUnCommittedPages;
  440. if (NumberOfUnCommittedPages) {
  441. RtlpInsertUnCommittedPages( Segment,
  442. (ULONG)UnCommittedAddress,
  443. NumberOfUnCommittedPages * PAGE_SIZE
  444. );
  445. }
  446. Heap->Segments[ SegmentIndex ] = Segment;
  447. PreviousSize = Segment->Entry.Size;
  448. FirstEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
  449. FirstEntry->PreviousSize = PreviousSize;
  450. FirstEntry->SegmentIndex = SegmentIndex;
  451. RtlpInsertFreeBlock( Heap,
  452. (PHEAP_FREE_ENTRY)FirstEntry,
  453. (PHEAP_ENTRY)UnCommittedAddress - FirstEntry
  454. );
  455. return TRUE;
  456. }
  457. NTSTATUS
  458. RtlpDestroyHeapSegment(
  459. IN PHEAP_SEGMENT Segment
  460. )
  461. {
  462. PVOID BaseAddress;
  463. ULONG BytesToFree;
  464. RTL_PAGED_CODE();
  465. if (!(Segment->Flags & HEAP_SEGMENT_USER_ALLOCATED)) {
  466. BaseAddress = Segment->BaseAddress;
  467. BytesToFree = 0;
  468. return ZwFreeVirtualMemory( NtCurrentProcess(),
  469. (PVOID *)&BaseAddress,
  470. &BytesToFree,
  471. MEM_RELEASE
  472. );
  473. }
  474. else {
  475. return STATUS_SUCCESS;
  476. }
  477. }
  478. PVOID
  479. RtlCreateHeap(
  480. IN ULONG Flags,
  481. IN PVOID HeapBase OPTIONAL,
  482. IN ULONG ReserveSize OPTIONAL,
  483. IN ULONG CommitSize OPTIONAL,
  484. IN PVOID Lock OPTIONAL,
  485. IN PRTL_HEAP_PARAMETERS Parameters OPTIONAL
  486. )
  487. /*++
  488. Routine Description:
  489. This routine initializes a heap.
  490. Arguments:
  491. Flags - Specifies optional attributes of the heap.
  492. Valid Flags Values:
  493. HEAP_NO_SERIALIZE - if set, then allocations and deallocations on
  494. this heap are NOT synchronized by these routines.
  495. HEAP_GROWABLE - if set, then the heap is a "sparse" heap where
  496. memory is committed only as necessary instead of
  497. being preallocated.
  498. HeapBase - if not NULL, this specifies the base address for memory
  499. to use as the heap. If NULL, memory is allocated by these routines.
  500. ReserveSize - if not zero, this specifies the amount of virtual address
  501. space to reserve for the heap.
  502. CommitSize - if not zero, this specifies the amount of virtual address
  503. space to commit for the heap. Must be less than ReserveSize. If
  504. zero, then defaults to one page.
  505. Lock - if not NULL, this parameter points to the resource lock to
  506. use. Only valid if HEAP_NO_SERIALIZE is NOT set.
  507. Parameters - optional heap parameters.
  508. Return Value:
  509. PVOID - a pointer to be used in accessing the created heap.
  510. --*/
  511. {
  512. NTSTATUS Status;
  513. PHEAP Heap = NULL;
  514. PHEAP_SEGMENT Segment = NULL;
  515. PLIST_ENTRY FreeListHead;
  516. ULONG SizeOfHeapHeader;
  517. ULONG SegmentFlags;
  518. PVOID CommittedBase;
  519. PVOID UnCommittedBase;
  520. MEMORY_BASIC_INFORMATION MemoryInformation;
  521. ULONG n;
  522. ULONG InitialCountOfUnusedUnCommittedRanges;
  523. ULONG MaximumHeapBlockSize;
  524. PVOID NextHeapHeaderAddress;
  525. PHEAP_UNCOMMMTTED_RANGE UnCommittedRange, *pp;
  526. RTL_HEAP_PARAMETERS TempParameters;
  527. #ifndef NTOS_KERNEL_RUNTIME
  528. PPEB Peb;
  529. #else
  530. extern ULONG MmHeapSegmentReserve;
  531. extern ULONG MmHeapSegmentCommit;
  532. extern ULONG MmHeapDeCommitTotalFreeThreshold;
  533. extern ULONG MmHeapDeCommitFreeBlockThreshold;
  534. #endif // NTOS_KERNEL_RUNTIME
  535. RTL_PAGED_CODE();
  536. #ifdef DEBUG_PAGE_HEAP
  537. if ( RtlpDebugPageHeap && ( HeapBase == NULL ) && ( Lock == NULL )) {
  538. return RtlpDebugPageHeapCreate( Flags, HeapBase, ReserveSize, CommitSize, Lock, Parameters );
  539. }
  540. else {
  541. Flags &= ~( HEAP_PROTECTION_ENABLED | HEAP_BREAK_WHEN_OUT_OF_VM | HEAP_NO_ALIGNMENT );
  542. }
  543. #endif
  544. if (!(Flags & HEAP_SKIP_VALIDATION_CHECKS)) {
  545. if (Flags & ~HEAP_CREATE_VALID_MASK) {
  546. HeapDebugPrint(( "Invalid flags (%08x) specified to RtlCreateHeap\n", Flags ));
  547. HeapDebugBreak( NULL );
  548. Flags &= HEAP_CREATE_VALID_MASK;
  549. }
  550. }
  551. MaximumHeapBlockSize = HEAP_MAXIMUM_BLOCK_SIZE << HEAP_GRANULARITY_SHIFT;
  552. Status = STATUS_SUCCESS;
  553. RtlZeroMemory( &TempParameters, sizeof( TempParameters ) );
  554. if (ARGUMENT_PRESENT( Parameters )) {
  555. try {
  556. if (Parameters->Length == sizeof( *Parameters )) {
  557. RtlMoveMemory( &TempParameters, Parameters, sizeof( *Parameters ) );
  558. }
  559. }
  560. except( EXCEPTION_EXECUTE_HANDLER ) {
  561. Status = GetExceptionCode();
  562. }
  563. if (!NT_SUCCESS( Status )) {
  564. return NULL;
  565. }
  566. }
  567. Parameters = &TempParameters;
  568. if (NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK) {
  569. Flags |= HEAP_TAIL_CHECKING_ENABLED;
  570. }
  571. if (NtGlobalFlag & FLG_HEAP_ENABLE_FREE_CHECK) {
  572. Flags |= HEAP_FREE_CHECKING_ENABLED;
  573. }
  574. if (NtGlobalFlag & FLG_HEAP_DISABLE_COALESCING) {
  575. Flags |= HEAP_DISABLE_COALESCE_ON_FREE;
  576. }
  577. #ifndef NTOS_KERNEL_RUNTIME
  578. Peb = NtCurrentPeb();
  579. if (NtGlobalFlag & FLG_HEAP_VALIDATE_PARAMETERS) {
  580. Flags |= HEAP_VALIDATE_PARAMETERS_ENABLED;
  581. }
  582. if (NtGlobalFlag & FLG_HEAP_VALIDATE_ALL) {
  583. Flags |= HEAP_VALIDATE_ALL_ENABLED;
  584. }
  585. if (NtGlobalFlag & FLG_HEAP_ENABLE_CALL_TRACING) {
  586. Flags |= HEAP_CREATE_ENABLE_TRACING;
  587. }
  588. if (Parameters->SegmentReserve == 0) {
  589. Parameters->SegmentReserve = Peb->HeapSegmentReserve;
  590. }
  591. if (Parameters->SegmentCommit == 0) {
  592. Parameters->SegmentCommit = Peb->HeapSegmentCommit;
  593. }
  594. if (Parameters->DeCommitFreeBlockThreshold == 0) {
  595. Parameters->DeCommitFreeBlockThreshold = Peb->HeapDeCommitFreeBlockThreshold;
  596. }
  597. if (Parameters->DeCommitTotalFreeThreshold == 0) {
  598. Parameters->DeCommitTotalFreeThreshold = Peb->HeapDeCommitTotalFreeThreshold;
  599. }
  600. #else
  601. if (Parameters->SegmentReserve == 0) {
  602. Parameters->SegmentReserve = MmHeapSegmentReserve;
  603. }
  604. if (Parameters->SegmentCommit == 0) {
  605. Parameters->SegmentCommit = MmHeapSegmentCommit;
  606. }
  607. if (Parameters->DeCommitFreeBlockThreshold == 0) {
  608. Parameters->DeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
  609. }
  610. if (Parameters->DeCommitTotalFreeThreshold == 0) {
  611. Parameters->DeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
  612. }
  613. #endif // NTOS_KERNEL_RUNTIME
  614. if (Parameters->MaximumAllocationSize == 0) {
  615. Parameters->MaximumAllocationSize = ((ULONG)MM_HIGHEST_USER_ADDRESS -
  616. (ULONG)MM_LOWEST_USER_ADDRESS -
  617. PAGE_SIZE
  618. );
  619. }
  620. if (Parameters->VirtualMemoryThreshold == 0 ||
  621. Parameters->VirtualMemoryThreshold > MaximumHeapBlockSize
  622. ) {
  623. Parameters->VirtualMemoryThreshold = MaximumHeapBlockSize;
  624. }
  625. if (!ARGUMENT_PRESENT( CommitSize )) {
  626. CommitSize = PAGE_SIZE;
  627. if (!ARGUMENT_PRESENT( ReserveSize )) {
  628. ReserveSize = 64 * CommitSize;
  629. }
  630. }
  631. else
  632. if (!ARGUMENT_PRESENT( ReserveSize )) {
  633. ReserveSize = ROUND_UP_TO_POWER2( CommitSize, 64 * 1024 );
  634. }
  635. #ifndef NTOS_KERNEL_RUNTIME
  636. if (DEBUG_HEAP( Flags )) {
  637. return RtlDebugCreateHeap( Flags,
  638. HeapBase,
  639. ReserveSize,
  640. CommitSize,
  641. Lock,
  642. Parameters
  643. );
  644. }
  645. #endif // NTOS_KERNEL_RUNTIME
  646. SizeOfHeapHeader = sizeof( HEAP );
  647. if (!(Flags & HEAP_NO_SERIALIZE)) {
  648. if (ARGUMENT_PRESENT( Lock )) {
  649. Flags |= HEAP_LOCK_USER_ALLOCATED;
  650. }
  651. else {
  652. SizeOfHeapHeader += sizeof( HEAP_LOCK );
  653. Lock = (PHEAP_LOCK)-1;
  654. }
  655. }
  656. else
  657. if (ARGUMENT_PRESENT( Lock )) {
  658. return NULL;
  659. }
  660. //
  661. // See if caller allocate the space for the heap.
  662. //
  663. if (ARGUMENT_PRESENT( HeapBase )) {
  664. if (Parameters->CommitRoutine != NULL) {
  665. if (Parameters->InitialCommit == 0 ||
  666. Parameters->InitialReserve == 0 ||
  667. Parameters->InitialCommit > Parameters->InitialReserve ||
  668. Flags & HEAP_GROWABLE
  669. ) {
  670. return NULL;
  671. }
  672. CommittedBase = HeapBase;
  673. UnCommittedBase = (PCHAR)CommittedBase + Parameters->InitialCommit;
  674. ReserveSize = Parameters->InitialReserve;
  675. RtlZeroMemory( CommittedBase, PAGE_SIZE );
  676. }
  677. else {
  678. Status = ZwQueryVirtualMemory( NtCurrentProcess(),
  679. HeapBase,
  680. MemoryBasicInformation,
  681. &MemoryInformation,
  682. sizeof( MemoryInformation ),
  683. NULL
  684. );
  685. if (!NT_SUCCESS( Status )) {
  686. return NULL;
  687. }
  688. if (MemoryInformation.BaseAddress != HeapBase) {
  689. return NULL;
  690. }
  691. if (MemoryInformation.State == MEM_FREE) {
  692. return NULL;
  693. }
  694. CommittedBase = MemoryInformation.BaseAddress;
  695. if (MemoryInformation.State == MEM_COMMIT) {
  696. RtlZeroMemory( CommittedBase, PAGE_SIZE );
  697. CommitSize = MemoryInformation.RegionSize;
  698. UnCommittedBase = (PCHAR)CommittedBase + CommitSize;
  699. Status = ZwQueryVirtualMemory( NtCurrentProcess(),
  700. UnCommittedBase,
  701. MemoryBasicInformation,
  702. &MemoryInformation,
  703. sizeof( MemoryInformation ),
  704. NULL
  705. );
  706. ReserveSize = CommitSize;
  707. if (NT_SUCCESS( Status ) &&
  708. MemoryInformation.State == MEM_RESERVE
  709. ) {
  710. ReserveSize += MemoryInformation.RegionSize;
  711. }
  712. }
  713. else {
  714. CommitSize = PAGE_SIZE;
  715. UnCommittedBase = CommittedBase;
  716. }
  717. }
  718. SegmentFlags = HEAP_SEGMENT_USER_ALLOCATED;
  719. Heap = (PHEAP)HeapBase;
  720. }
  721. else {
  722. if (Parameters->CommitRoutine != NULL) {
  723. return NULL;
  724. }
  725. //
  726. // Reserve the amount of virtual address space requested.
  727. //
  728. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  729. (PVOID *)&Heap,
  730. 0,
  731. &ReserveSize,
  732. MEM_RESERVE,
  733. PAGE_READWRITE
  734. );
  735. if (!NT_SUCCESS( Status )) {
  736. return NULL;
  737. }
  738. SegmentFlags = 0;
  739. if (!ARGUMENT_PRESENT( CommitSize )) {
  740. CommitSize = PAGE_SIZE;
  741. }
  742. CommittedBase = Heap;
  743. UnCommittedBase = Heap;
  744. }
  745. if (CommittedBase == UnCommittedBase) {
  746. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  747. (PVOID *)&CommittedBase,
  748. 0,
  749. &CommitSize,
  750. MEM_COMMIT,
  751. PAGE_READWRITE
  752. );
  753. if (!NT_SUCCESS( Status )) {
  754. if (!ARGUMENT_PRESENT(HeapBase)) {
  755. //
  756. // Return the reserved virtual address space.
  757. //
  758. ZwFreeVirtualMemory( NtCurrentProcess(),
  759. (PVOID *)&Heap,
  760. &ReserveSize,
  761. MEM_RELEASE );
  762. }
  763. return NULL;
  764. }
  765. UnCommittedBase = (PVOID)((PCHAR)UnCommittedBase + CommitSize);
  766. }
  767. NextHeapHeaderAddress = Heap + 1;
  768. UnCommittedRange = (PHEAP_UNCOMMMTTED_RANGE)ROUND_UP_TO_POWER2( NextHeapHeaderAddress,
  769. sizeof( QUAD )
  770. );
  771. InitialCountOfUnusedUnCommittedRanges = 8;
  772. SizeOfHeapHeader += InitialCountOfUnusedUnCommittedRanges * sizeof( *UnCommittedRange );
  773. pp = &Heap->UnusedUnCommittedRanges;
  774. while (InitialCountOfUnusedUnCommittedRanges--) {
  775. *pp = UnCommittedRange;
  776. pp = &UnCommittedRange->Next;
  777. UnCommittedRange += 1;
  778. }
  779. NextHeapHeaderAddress = UnCommittedRange;
  780. *pp = NULL;
  781. if (IS_HEAP_TAGGING_ENABLED()) {
  782. Heap->PseudoTagEntries = (PHEAP_PSEUDO_TAG_ENTRY)ROUND_UP_TO_POWER2( NextHeapHeaderAddress,
  783. sizeof( QUAD )
  784. );
  785. SizeOfHeapHeader += HEAP_NUMBER_OF_PSEUDO_TAG * sizeof( HEAP_PSEUDO_TAG_ENTRY );
  786. NextHeapHeaderAddress = Heap->PseudoTagEntries + HEAP_NUMBER_OF_PSEUDO_TAG;
  787. }
  788. SizeOfHeapHeader = ROUND_UP_TO_POWER2( SizeOfHeapHeader,
  789. HEAP_GRANULARITY
  790. );
  791. Heap->Entry.Size = (USHORT)(SizeOfHeapHeader >> HEAP_GRANULARITY_SHIFT);
  792. Heap->Entry.Flags = HEAP_ENTRY_BUSY;
  793. Heap->Signature = HEAP_SIGNATURE;
  794. Heap->Flags = Flags;
  795. Heap->ForceFlags = (Flags & (HEAP_NO_SERIALIZE |
  796. HEAP_GENERATE_EXCEPTIONS |
  797. HEAP_ZERO_MEMORY |
  798. HEAP_REALLOC_IN_PLACE_ONLY |
  799. HEAP_VALIDATE_PARAMETERS_ENABLED |
  800. HEAP_VALIDATE_ALL_ENABLED |
  801. HEAP_CREATE_ENABLE_TRACING |
  802. HEAP_TAIL_CHECKING_ENABLED |
  803. HEAP_CREATE_ALIGN_16 |
  804. HEAP_FREE_CHECKING_ENABLED
  805. )
  806. );
  807. Heap->EventLogMask = (0x00010000) << ((Flags & HEAP_CLASS_MASK) >> 12);
  808. Heap->FreeListsInUseTerminate = 0xFFFF;
  809. Heap->HeaderValidateLength = (USHORT)((ULONG)NextHeapHeaderAddress - (ULONG)Heap);
  810. Heap->HeaderValidateCopy = NULL;
  811. FreeListHead = &Heap->FreeLists[ 0 ];
  812. n = HEAP_MAXIMUM_FREELISTS;
  813. while (n--) {
  814. InitializeListHead( FreeListHead );
  815. FreeListHead++;
  816. }
  817. InitializeListHead( &Heap->VirtualAllocdBlocks );
  818. //
  819. // Initialize the cricital section that controls access to
  820. // the free list.
  821. //
  822. if (Lock == (PHEAP_LOCK)-1) {
  823. Lock = (PHEAP_LOCK)NextHeapHeaderAddress;
  824. Status = RtlInitializeLockRoutine( Lock );
  825. if (!NT_SUCCESS( Status )) {
  826. return NULL;
  827. }
  828. NextHeapHeaderAddress = (PHEAP_LOCK)Lock + 1;
  829. }
  830. Heap->LockVariable = Lock;
  831. if (!RtlpInitializeHeapSegment( Heap,
  832. (PHEAP_SEGMENT)
  833. ((PCHAR)Heap + SizeOfHeapHeader),
  834. 0,
  835. SegmentFlags,
  836. CommittedBase,
  837. UnCommittedBase,
  838. (PCHAR)CommittedBase + ReserveSize
  839. )
  840. ) {
  841. return NULL;
  842. }
  843. Heap->ProcessHeapsListIndex = 0;
  844. Heap->SegmentReserve = Parameters->SegmentReserve;
  845. Heap->SegmentCommit = Parameters->SegmentCommit;
  846. Heap->DeCommitFreeBlockThreshold = Parameters->DeCommitFreeBlockThreshold >> HEAP_GRANULARITY_SHIFT;
  847. Heap->DeCommitTotalFreeThreshold = Parameters->DeCommitTotalFreeThreshold >> HEAP_GRANULARITY_SHIFT;
  848. Heap->MaximumAllocationSize = Parameters->MaximumAllocationSize;
  849. Heap->VirtualMemoryThreshold = ROUND_UP_TO_POWER2( Parameters->VirtualMemoryThreshold,
  850. HEAP_GRANULARITY
  851. ) >> HEAP_GRANULARITY_SHIFT;
  852. if (Flags & HEAP_CREATE_ALIGN_16) {
  853. Heap->AlignRound = 15 + sizeof( HEAP_ENTRY );
  854. Heap->AlignMask = (ULONG)~15;
  855. }
  856. else {
  857. Heap->AlignRound = 7 + sizeof( HEAP_ENTRY );
  858. Heap->AlignMask = (ULONG)~7;
  859. }
  860. if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED) {
  861. Heap->AlignRound += CHECK_HEAP_TAIL_SIZE;
  862. }
  863. Heap->CommitRoutine = Parameters->CommitRoutine;
  864. #if !defined(NTOS_KERNEL_RUNTIME)
  865. RtlpAddHeapToProcessList( Heap );
  866. #endif // !defined(NTOS_KERNEL_RUNTIME)
  867. #if ENABLE_HEAP_EVENT_LOGGING
  868. if (RtlAreLogging( Heap->EventLogMask )) {
  869. RtlLogEvent( RtlpCreateHeapEventId,
  870. Heap->EventLogMask,
  871. Flags,
  872. Heap,
  873. ReserveSize,
  874. CommitSize
  875. );
  876. }
  877. #endif // ENABLE_HEAP_EVENT_LOGGING
  878. return (PVOID)Heap;
  879. } // RtlCreateHeap
  880. PVOID
  881. RtlDestroyHeap(
  882. IN PVOID HeapHandle
  883. )
  884. {
  885. PHEAP Heap = (PHEAP)HeapHandle;
  886. PHEAP_SEGMENT Segment;
  887. PHEAP_UCR_SEGMENT UCRSegments;
  888. PLIST_ENTRY Head, Next;
  889. PVOID BaseAddress;
  890. ULONG RegionSize;
  891. UCHAR SegmentIndex;
  892. //
  893. // Validate that HeapAddress points to a HEAP structure.
  894. //
  895. RTL_PAGED_CODE();
  896. IF_DEBUG_PAGE_HEAP_THEN_RETURN(
  897. HeapHandle,
  898. RtlpDebugPageHeapDestroy( HeapHandle )
  899. );
  900. if (Heap == NULL) {
  901. return NULL;
  902. }
  903. #ifndef NTOS_KERNEL_RUNTIME
  904. if (DEBUG_HEAP( Heap->Flags )) {
  905. if (!RtlDebugDestroyHeap( HeapHandle )) {
  906. return HeapHandle;
  907. }
  908. }
  909. if (HeapHandle == NtCurrentPeb()->ProcessHeap) {
  910. return HeapHandle;
  911. }
  912. #endif // NTOS_KERNEL_RUNTIME
  913. #if ENABLE_HEAP_EVENT_LOGGING
  914. if (RtlAreLogging( Heap->EventLogMask )) {
  915. RtlLogEvent( RtlpDestroyHeapEventId,
  916. Heap->EventLogMask,
  917. Heap
  918. );
  919. }
  920. #endif // ENABLE_HEAP_EVENT_LOGGING
  921. Head = &Heap->VirtualAllocdBlocks;
  922. Next = Head->Flink;
  923. while (Head != Next) {
  924. BaseAddress = CONTAINING_RECORD( Next, HEAP_VIRTUAL_ALLOC_ENTRY, Entry );
  925. Next = Next->Flink;
  926. RegionSize = 0;
  927. ZwFreeVirtualMemory( NtCurrentProcess(),
  928. (PVOID *)&BaseAddress,
  929. &RegionSize,
  930. MEM_RELEASE
  931. );
  932. }
  933. #if !defined(NTOS_KERNEL_RUNTIME)
  934. RtlpDestroyTags( Heap );
  935. RtlpRemoveHeapFromProcessList( Heap );
  936. #endif // !defined(NTOS_KERNEL_RUNTIME)
  937. //
  938. // If the heap is serialized, delete the critical section created
  939. // by RtlCreateHeap.
  940. //
  941. if (!(Heap->Flags & HEAP_NO_SERIALIZE)) {
  942. if (!(Heap->Flags & HEAP_LOCK_USER_ALLOCATED)) {
  943. (VOID)RtlDeleteLockRoutine( Heap->LockVariable );
  944. }
  945. Heap->LockVariable = NULL;
  946. }
  947. UCRSegments = Heap->UCRSegments;
  948. Heap->UCRSegments = NULL;
  949. while (UCRSegments) {
  950. BaseAddress = UCRSegments;
  951. UCRSegments = UCRSegments->Next;
  952. RegionSize = 0;
  953. ZwFreeVirtualMemory( NtCurrentProcess(),
  954. &BaseAddress,
  955. &RegionSize,
  956. MEM_RELEASE
  957. );
  958. }
  959. SegmentIndex = HEAP_MAXIMUM_SEGMENTS;
  960. while (SegmentIndex--) {
  961. Segment = Heap->Segments[ SegmentIndex ];
  962. if (Segment) {
  963. RtlpDestroyHeapSegment( Segment );
  964. }
  965. }
  966. return NULL;
  967. } // RtlDestroyHeap
  968. PHEAP_FREE_ENTRY
  969. RtlpExtendHeap(
  970. IN PHEAP Heap,
  971. IN ULONG AllocationSize
  972. )
  973. {
  974. NTSTATUS Status;
  975. PHEAP_SEGMENT Segment;
  976. PHEAP_FREE_ENTRY FreeBlock;
  977. UCHAR SegmentIndex, EmptySegmentIndex;
  978. ULONG NumberOfPages;
  979. ULONG CommitSize;
  980. ULONG ReserveSize;
  981. ULONG FreeSize;
  982. RTL_PAGED_CODE();
  983. NumberOfPages = ((AllocationSize + PAGE_SIZE - 1) / PAGE_SIZE);
  984. FreeSize = NumberOfPages * PAGE_SIZE;
  985. HeapInternalTrace( Heap, (Heap->TraceBuffer, HEAP_TRACE_EXTEND_HEAP, 3, AllocationSize, NumberOfPages, FreeSize) );
  986. EmptySegmentIndex = HEAP_MAXIMUM_SEGMENTS;
  987. for (SegmentIndex=0; SegmentIndex<HEAP_MAXIMUM_SEGMENTS; SegmentIndex++) {
  988. Segment = Heap->Segments[ SegmentIndex ];
  989. if (Segment &&
  990. NumberOfPages <= Segment->NumberOfUnCommittedPages &&
  991. FreeSize <= Segment->LargestUnCommittedRange
  992. ) {
  993. FreeBlock = RtlpFindAndCommitPages( Heap,
  994. Segment,
  995. &FreeSize,
  996. NULL
  997. );
  998. if (FreeBlock != NULL) {
  999. FreeSize = FreeSize >> HEAP_GRANULARITY_SHIFT;
  1000. FreeBlock = RtlpCoalesceFreeBlocks( Heap, FreeBlock, &FreeSize, FALSE );
  1001. RtlpInsertFreeBlock( Heap, FreeBlock, FreeSize );
  1002. return FreeBlock;
  1003. }
  1004. }
  1005. else
  1006. if (Segment == NULL && EmptySegmentIndex == HEAP_MAXIMUM_SEGMENTS) {
  1007. EmptySegmentIndex = SegmentIndex;
  1008. }
  1009. }
  1010. if (EmptySegmentIndex != HEAP_MAXIMUM_SEGMENTS &&
  1011. Heap->Flags & HEAP_GROWABLE
  1012. ) {
  1013. Segment = NULL;
  1014. if ((AllocationSize + PAGE_SIZE) > Heap->SegmentReserve) {
  1015. ReserveSize = AllocationSize + PAGE_SIZE;
  1016. }
  1017. else {
  1018. ReserveSize = Heap->SegmentReserve;
  1019. }
  1020. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  1021. (PVOID *)&Segment,
  1022. 0,
  1023. &ReserveSize,
  1024. MEM_RESERVE,
  1025. PAGE_READWRITE
  1026. );
  1027. if (NT_SUCCESS( Status )) {
  1028. Heap->SegmentReserve += ReserveSize;
  1029. if ((AllocationSize + PAGE_SIZE) > Heap->SegmentCommit) {
  1030. CommitSize = AllocationSize + PAGE_SIZE;
  1031. }
  1032. else {
  1033. CommitSize = Heap->SegmentCommit;
  1034. }
  1035. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  1036. (PVOID *)&Segment,
  1037. 0,
  1038. &CommitSize,
  1039. MEM_COMMIT,
  1040. PAGE_READWRITE
  1041. );
  1042. if (NT_SUCCESS( Status ) &&
  1043. !RtlpInitializeHeapSegment( Heap,
  1044. Segment,
  1045. EmptySegmentIndex,
  1046. 0,
  1047. Segment,
  1048. (PCHAR)Segment + CommitSize,
  1049. (PCHAR)Segment + ReserveSize
  1050. )
  1051. ) {
  1052. Status = STATUS_NO_MEMORY;
  1053. }
  1054. if (NT_SUCCESS(Status)) {
  1055. return (PHEAP_FREE_ENTRY)Segment->FirstEntry;
  1056. }
  1057. ZwFreeVirtualMemory( NtCurrentProcess(),
  1058. (PVOID *)&Segment,
  1059. &ReserveSize,
  1060. MEM_RELEASE
  1061. );
  1062. }
  1063. }
  1064. #if !defined(NTOS_KERNEL_RUNTIME)
  1065. if (Heap->Flags & HEAP_DISABLE_COALESCE_ON_FREE) {
  1066. FreeBlock = RtlpCoalesceHeap( Heap );
  1067. if ((FreeBlock != NULL) && (FreeBlock->Size >= AllocationSize)) {
  1068. return(FreeBlock);
  1069. }
  1070. }
  1071. #endif
  1072. return NULL;
  1073. }
  1074. PHEAP_FREE_ENTRY
  1075. RtlpCoalesceFreeBlocks(
  1076. IN PHEAP Heap,
  1077. IN PHEAP_FREE_ENTRY FreeBlock,
  1078. IN OUT PULONG FreeSize,
  1079. IN BOOLEAN RemoveFromFreeList
  1080. )
  1081. {
  1082. PHEAP_FREE_ENTRY FreeBlock1, NextFreeBlock;
  1083. RTL_PAGED_CODE();
  1084. FreeBlock1 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeBlock - FreeBlock->PreviousSize);
  1085. if (FreeBlock1 != FreeBlock &&
  1086. !(FreeBlock1->Flags & HEAP_ENTRY_BUSY) &&
  1087. (*FreeSize + FreeBlock1->Size) <= HEAP_MAXIMUM_BLOCK_SIZE
  1088. ) {
  1089. HEAPASSERT(FreeBlock->PreviousSize == FreeBlock1->Size);
  1090. HeapInternalTrace( Heap, (Heap->TraceBuffer, HEAP_TRACE_COALESCE_FREE_BLOCKS,
  1091. 7,
  1092. FreeBlock1, *(PULONG)FreeBlock1, *((PULONG)FreeBlock1+1),
  1093. FreeBlock, *(PULONG)FreeBlock, *((PULONG)FreeBlock+1),
  1094. *FreeSize + FreeBlock1->Size
  1095. )
  1096. );
  1097. if (RemoveFromFreeList) {
  1098. RtlpRemoveFreeBlock( Heap, FreeBlock );
  1099. Heap->TotalFreeSize -= FreeBlock->Size;
  1100. RemoveFromFreeList = FALSE;
  1101. }
  1102. RtlpRemoveFreeBlock( Heap, FreeBlock1 );
  1103. FreeBlock1->Flags = FreeBlock->Flags & HEAP_ENTRY_LAST_ENTRY;
  1104. FreeBlock = FreeBlock1;
  1105. *FreeSize += FreeBlock1->Size;
  1106. Heap->TotalFreeSize -= FreeBlock1->Size;
  1107. FreeBlock->Size = (USHORT)*FreeSize;
  1108. if (!(FreeBlock->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  1109. ((PHEAP_ENTRY)FreeBlock + *FreeSize)->PreviousSize = (USHORT)*FreeSize;
  1110. }
  1111. }
  1112. if (!(FreeBlock->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  1113. NextFreeBlock = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeBlock + *FreeSize);
  1114. if (!(NextFreeBlock->Flags & HEAP_ENTRY_BUSY) &&
  1115. (*FreeSize + NextFreeBlock->Size) <= HEAP_MAXIMUM_BLOCK_SIZE
  1116. ) {
  1117. HEAPASSERT(*FreeSize == NextFreeBlock->PreviousSize);
  1118. HeapInternalTrace( Heap, (Heap->TraceBuffer, HEAP_TRACE_COALESCE_FREE_BLOCKS,
  1119. 7,
  1120. FreeBlock, *(PULONG)FreeBlock, *((PULONG)FreeBlock+1),
  1121. NextFreeBlock, *(PULONG)NextFreeBlock, *((PULONG)NextFreeBlock+1),
  1122. *FreeSize + NextFreeBlock->Size
  1123. )
  1124. );
  1125. if (RemoveFromFreeList) {
  1126. RtlpRemoveFreeBlock( Heap, FreeBlock );
  1127. Heap->TotalFreeSize -= FreeBlock->Size;
  1128. RemoveFromFreeList = FALSE;
  1129. }
  1130. FreeBlock->Flags = NextFreeBlock->Flags & HEAP_ENTRY_LAST_ENTRY;
  1131. RtlpRemoveFreeBlock( Heap, NextFreeBlock );
  1132. *FreeSize += NextFreeBlock->Size;
  1133. Heap->TotalFreeSize -= NextFreeBlock->Size;
  1134. FreeBlock->Size = (USHORT)*FreeSize;
  1135. if (!(FreeBlock->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  1136. ((PHEAP_ENTRY)FreeBlock + *FreeSize)->PreviousSize = (USHORT)*FreeSize;
  1137. }
  1138. }
  1139. }
  1140. return FreeBlock;
  1141. }
  1142. VOID
  1143. RtlpDeCommitFreeBlock(
  1144. IN PHEAP Heap,
  1145. IN PHEAP_FREE_ENTRY FreeBlock,
  1146. IN ULONG FreeSize
  1147. )
  1148. {
  1149. NTSTATUS Status;
  1150. ULONG DeCommitAddress, DeCommitSize;
  1151. USHORT LeadingFreeSize, TrailingFreeSize;
  1152. PHEAP_SEGMENT Segment;
  1153. PHEAP_FREE_ENTRY LeadingFreeBlock, TrailingFreeBlock;
  1154. PHEAP_ENTRY LeadingBusyBlock, TrailingBusyBlock;
  1155. RTL_PAGED_CODE();
  1156. if (Heap->CommitRoutine != NULL) {
  1157. RtlpInsertFreeBlock( Heap, FreeBlock, FreeSize );
  1158. return;
  1159. }
  1160. Segment = Heap->Segments[ FreeBlock->SegmentIndex ];
  1161. LeadingBusyBlock = NULL;
  1162. LeadingFreeBlock = FreeBlock;
  1163. DeCommitAddress = ROUND_UP_TO_POWER2( LeadingFreeBlock, PAGE_SIZE );
  1164. LeadingFreeSize = (USHORT)((PHEAP_ENTRY)DeCommitAddress - (PHEAP_ENTRY)LeadingFreeBlock);
  1165. if (LeadingFreeSize == 1) {
  1166. DeCommitAddress += PAGE_SIZE;
  1167. LeadingFreeSize += PAGE_SIZE >> HEAP_GRANULARITY_SHIFT;
  1168. }
  1169. else
  1170. if (LeadingFreeBlock->PreviousSize != 0) {
  1171. if (DeCommitAddress == (ULONG)LeadingFreeBlock) {
  1172. LeadingBusyBlock = (PHEAP_ENTRY)LeadingFreeBlock - LeadingFreeBlock->PreviousSize;
  1173. }
  1174. }
  1175. TrailingBusyBlock = NULL;
  1176. TrailingFreeBlock = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeBlock + FreeSize);
  1177. DeCommitSize = ROUND_DOWN_TO_POWER2( (ULONG)TrailingFreeBlock, PAGE_SIZE );
  1178. TrailingFreeSize = (PHEAP_ENTRY)TrailingFreeBlock - (PHEAP_ENTRY)DeCommitSize;
  1179. if (TrailingFreeSize == (sizeof( HEAP_ENTRY ) >> HEAP_GRANULARITY_SHIFT)) {
  1180. DeCommitSize -= PAGE_SIZE;
  1181. TrailingFreeSize += PAGE_SIZE >> HEAP_GRANULARITY_SHIFT;
  1182. }
  1183. else
  1184. if (TrailingFreeSize == 0 && !(FreeBlock->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  1185. TrailingBusyBlock = (PHEAP_ENTRY)TrailingFreeBlock;
  1186. }
  1187. TrailingFreeBlock = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)TrailingFreeBlock - TrailingFreeSize);
  1188. if (DeCommitSize > DeCommitAddress) {
  1189. DeCommitSize -= DeCommitAddress;
  1190. }
  1191. else {
  1192. DeCommitSize = 0;
  1193. }
  1194. if (DeCommitSize != 0) {
  1195. Status = ZwFreeVirtualMemory( NtCurrentProcess(),
  1196. (PVOID *)&DeCommitAddress,
  1197. &DeCommitSize,
  1198. MEM_DECOMMIT
  1199. );
  1200. if (NT_SUCCESS( Status )) {
  1201. RtlpInsertUnCommittedPages( Segment,
  1202. DeCommitAddress,
  1203. DeCommitSize
  1204. );
  1205. Segment->NumberOfUnCommittedPages += DeCommitSize / PAGE_SIZE;
  1206. if (LeadingFreeSize != 0) {
  1207. LeadingFreeBlock->Flags = HEAP_ENTRY_LAST_ENTRY;
  1208. LeadingFreeBlock->Size = LeadingFreeSize;
  1209. Heap->TotalFreeSize += LeadingFreeSize;
  1210. RtlpInsertFreeBlockDirect( Heap, LeadingFreeBlock, LeadingFreeSize );
  1211. }
  1212. else
  1213. if (LeadingBusyBlock != NULL) {
  1214. LeadingBusyBlock->Flags |= HEAP_ENTRY_LAST_ENTRY;
  1215. }
  1216. if (TrailingFreeSize != 0) {
  1217. TrailingFreeBlock->PreviousSize = 0;
  1218. TrailingFreeBlock->SegmentIndex = Segment->Entry.SegmentIndex;
  1219. TrailingFreeBlock->Flags = 0;
  1220. TrailingFreeBlock->Size = TrailingFreeSize;
  1221. ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)TrailingFreeBlock + TrailingFreeSize))->PreviousSize = (USHORT)TrailingFreeSize;
  1222. RtlpInsertFreeBlockDirect( Heap, TrailingFreeBlock, TrailingFreeSize );
  1223. Heap->TotalFreeSize += TrailingFreeSize;
  1224. }
  1225. else
  1226. if (TrailingBusyBlock != NULL) {
  1227. TrailingBusyBlock->PreviousSize = 0;
  1228. }
  1229. }
  1230. else {
  1231. RtlpInsertFreeBlock( Heap, LeadingFreeBlock, FreeSize );
  1232. }
  1233. }
  1234. else {
  1235. RtlpInsertFreeBlock( Heap, LeadingFreeBlock, FreeSize );
  1236. }
  1237. return;
  1238. }
  1239. VOID
  1240. RtlpInsertFreeBlock(
  1241. IN PHEAP Heap,
  1242. IN PHEAP_FREE_ENTRY FreeBlock,
  1243. IN ULONG FreeSize
  1244. )
  1245. {
  1246. USHORT PreviousSize, Size;
  1247. UCHAR Flags;
  1248. UCHAR SegmentIndex;
  1249. PHEAP_SEGMENT Segment;
  1250. RTL_PAGED_CODE();
  1251. PreviousSize = FreeBlock->PreviousSize;
  1252. SegmentIndex = FreeBlock->SegmentIndex;
  1253. Segment = Heap->Segments[ SegmentIndex ];
  1254. Flags = FreeBlock->Flags;
  1255. Heap->TotalFreeSize += FreeSize;
  1256. while (FreeSize != 0) {
  1257. if (FreeSize > (ULONG)HEAP_MAXIMUM_BLOCK_SIZE) {
  1258. Size = HEAP_MAXIMUM_BLOCK_SIZE;
  1259. if (FreeSize == (ULONG)HEAP_MAXIMUM_BLOCK_SIZE + 1) {
  1260. Size -= 16;
  1261. }
  1262. FreeBlock->Flags = 0;
  1263. }
  1264. else {
  1265. Size = (USHORT)FreeSize;
  1266. FreeBlock->Flags = Flags;
  1267. }
  1268. FreeBlock->PreviousSize = PreviousSize;
  1269. FreeBlock->SegmentIndex = SegmentIndex;
  1270. FreeBlock->Size = Size;
  1271. RtlpInsertFreeBlockDirect( Heap, FreeBlock, Size );
  1272. PreviousSize = Size;
  1273. FreeSize -= Size;
  1274. FreeBlock = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeBlock + Size);
  1275. if ((PHEAP_ENTRY)FreeBlock >= Segment->LastValidEntry) {
  1276. return;
  1277. }
  1278. }
  1279. if (!(Flags & HEAP_ENTRY_LAST_ENTRY)) {
  1280. FreeBlock->PreviousSize = PreviousSize;
  1281. }
  1282. return;
  1283. }
  1284. #define RtlFindFirstSetRightMember(Set) \
  1285. (((Set) & 0xFFFF) ? \
  1286. (((Set) & 0xFF) ? \
  1287. RtlpBitsClearLow[(Set) & 0xFF] : \
  1288. RtlpBitsClearLow[((Set) >> 8) & 0xFF] + 8) : \
  1289. ((((Set) >> 16) & 0xFF) ? \
  1290. RtlpBitsClearLow[ ((Set) >> 16) & 0xFF] + 16 : \
  1291. RtlpBitsClearLow[ (Set) >> 24] + 24) \
  1292. )
  1293. PVOID
  1294. RtlAllocateHeap(
  1295. IN PVOID HeapHandle,
  1296. IN ULONG Flags,
  1297. IN ULONG Size
  1298. )
  1299. {
  1300. PHEAP Heap = (PHEAP)HeapHandle;
  1301. PULONG FreeListsInUse;
  1302. ULONG FreeListsInUseUlong;
  1303. ULONG AllocationSize;
  1304. ULONG FreeSize, AllocationIndex;
  1305. PLIST_ENTRY FreeListHead, Next;
  1306. PHEAP_ENTRY BusyBlock;
  1307. PHEAP_FREE_ENTRY FreeBlock, SplitBlock, SplitBlock2;
  1308. ULONG InUseIndex;
  1309. UCHAR FreeFlags;
  1310. NTSTATUS Status;
  1311. EXCEPTION_RECORD ExceptionRecord;
  1312. PVOID ReturnValue;
  1313. RTL_PAGED_CODE();
  1314. Flags |= Heap->ForceFlags;
  1315. //
  1316. // Check for special features that force us to call the slow, do-everything
  1317. // version.
  1318. //
  1319. if (( ! ( Flags & HEAP_SLOW_FLAGS )) && ( Size < 0x80000000 )) {
  1320. //
  1321. // Round the requested size up to the allocation granularity. Note
  1322. // that if the request is for 0 bytes, we still allocate memory, because
  1323. // we add in an extra 1 byte to protect ourselves from idiots.
  1324. //
  1325. AllocationSize = ((Size ? Size : 1) + 7 + sizeof( HEAP_ENTRY )) & (ULONG)~7;
  1326. AllocationIndex = AllocationSize >> HEAP_GRANULARITY_SHIFT;
  1327. if (!(Flags & HEAP_NO_SERIALIZE)) {
  1328. //
  1329. // Lock the free list.
  1330. //
  1331. RtlAcquireLockRoutine( Heap->LockVariable );
  1332. }
  1333. if (AllocationIndex < HEAP_MAXIMUM_FREELISTS) {
  1334. FreeListHead = &Heap->FreeLists[ AllocationIndex ];
  1335. if ( !IsListEmpty( FreeListHead )) {
  1336. FreeBlock = CONTAINING_RECORD( FreeListHead->Blink,
  1337. HEAP_FREE_ENTRY,
  1338. FreeList );
  1339. FreeFlags = FreeBlock->Flags;
  1340. RtlpFastRemoveDedicatedFreeBlock( Heap, FreeBlock );
  1341. Heap->TotalFreeSize -= AllocationIndex;
  1342. BusyBlock = (PHEAP_ENTRY)FreeBlock;
  1343. BusyBlock->Flags = HEAP_ENTRY_BUSY | (FreeFlags & HEAP_ENTRY_LAST_ENTRY);
  1344. BusyBlock->UnusedBytes = (UCHAR)(AllocationSize - Size);
  1345. BusyBlock->SmallTagIndex = 0;
  1346. } else {
  1347. //
  1348. // Scan the free list in use vector to find the smallest
  1349. // available free block large enough for our allocations.
  1350. //
  1351. //
  1352. // Compute the index of the ULONG where the scan should begin
  1353. //
  1354. InUseIndex = AllocationIndex >> 5;
  1355. FreeListsInUse = &Heap->u.FreeListsInUseUlong[InUseIndex];
  1356. //
  1357. // Mask off the bits in the first ULONG that represent allocations
  1358. // smaller than we need.
  1359. //
  1360. FreeListsInUseUlong = *FreeListsInUse++ & ~((1 << (AllocationIndex & 0x1f)) - 1);
  1361. //
  1362. // Begin unrolled loop to scan bit vector.
  1363. //
  1364. switch (InUseIndex) {
  1365. case 0:
  1366. if (FreeListsInUseUlong) {
  1367. FreeListHead = &Heap->FreeLists[0];
  1368. break;
  1369. }
  1370. FreeListsInUseUlong = *FreeListsInUse++;
  1371. // deliberate fallthrough to next ULONG
  1372. case 1:
  1373. if (FreeListsInUseUlong) {
  1374. FreeListHead = &Heap->FreeLists[32];
  1375. break;
  1376. }
  1377. FreeListsInUseUlong = *FreeListsInUse++;
  1378. // deliberate fallthrough to next ULONG
  1379. case 2:
  1380. if (FreeListsInUseUlong) {
  1381. FreeListHead = &Heap->FreeLists[64];
  1382. break;
  1383. }
  1384. FreeListsInUseUlong = *FreeListsInUse++;
  1385. // deliberate fallthrough to next ULONG
  1386. case 3:
  1387. if (FreeListsInUseUlong) {
  1388. FreeListHead = &Heap->FreeLists[96];
  1389. break;
  1390. }
  1391. // deliberate fallthrough to non dedicated list
  1392. default:
  1393. //
  1394. // No suitable entry on the free list was found.
  1395. //
  1396. goto LookInNonDedicatedList;
  1397. }
  1398. //
  1399. // A free list has been found with a large enough allocation. FreeListHead
  1400. // contains the base of the vector it was found in. FreeListsInUseUlong
  1401. // contains the vector.
  1402. //
  1403. FreeListHead += RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1404. FreeBlock = CONTAINING_RECORD( FreeListHead->Blink,
  1405. HEAP_FREE_ENTRY,
  1406. FreeList );
  1407. RtlpFastRemoveDedicatedFreeBlock( Heap, FreeBlock );
  1408. SplitFreeBlock:
  1409. FreeFlags = FreeBlock->Flags;
  1410. Heap->TotalFreeSize -= FreeBlock->Size;
  1411. BusyBlock = (PHEAP_ENTRY)FreeBlock;
  1412. BusyBlock->Flags = HEAP_ENTRY_BUSY;
  1413. FreeSize = BusyBlock->Size - AllocationIndex;
  1414. BusyBlock->Size = (USHORT)AllocationIndex;
  1415. BusyBlock->UnusedBytes = (UCHAR)(AllocationSize - Size);
  1416. BusyBlock->SmallTagIndex = 0;
  1417. if (FreeSize != 0) {
  1418. if (FreeSize == 1) {
  1419. BusyBlock->Size += 1;
  1420. BusyBlock->UnusedBytes += sizeof( HEAP_ENTRY );
  1421. } else {
  1422. SplitBlock = (PHEAP_FREE_ENTRY)(BusyBlock + AllocationIndex);
  1423. SplitBlock->Flags = FreeFlags;
  1424. SplitBlock->PreviousSize = (USHORT)AllocationIndex;
  1425. SplitBlock->SegmentIndex = BusyBlock->SegmentIndex;
  1426. SplitBlock->Size = (USHORT)FreeSize;
  1427. if (FreeFlags & HEAP_ENTRY_LAST_ENTRY) {
  1428. RtlpFastInsertFreeBlockDirect( Heap, SplitBlock, (USHORT)FreeSize);
  1429. Heap->TotalFreeSize += FreeSize;
  1430. } else {
  1431. SplitBlock2 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize);
  1432. if (SplitBlock2->Flags & HEAP_ENTRY_BUSY) {
  1433. SplitBlock2->PreviousSize = (USHORT)FreeSize;
  1434. RtlpFastInsertFreeBlockDirect( Heap, SplitBlock, (USHORT)FreeSize );
  1435. Heap->TotalFreeSize += FreeSize;
  1436. } else {
  1437. SplitBlock->Flags = SplitBlock2->Flags;
  1438. RtlpFastRemoveFreeBlock( Heap, SplitBlock2 );
  1439. Heap->TotalFreeSize -= SplitBlock2->Size;
  1440. FreeSize += SplitBlock2->Size;
  1441. if (FreeSize <= HEAP_MAXIMUM_BLOCK_SIZE) {
  1442. SplitBlock->Size = (USHORT)FreeSize;
  1443. if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  1444. ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
  1445. }
  1446. RtlpFastInsertFreeBlockDirect( Heap, SplitBlock, (USHORT)FreeSize );
  1447. Heap->TotalFreeSize += FreeSize;
  1448. } else {
  1449. RtlpInsertFreeBlock( Heap, SplitBlock, FreeSize );
  1450. }
  1451. }
  1452. }
  1453. FreeFlags = 0;
  1454. }
  1455. }
  1456. if (FreeFlags & HEAP_ENTRY_LAST_ENTRY) {
  1457. BusyBlock->Flags |= HEAP_ENTRY_LAST_ENTRY;
  1458. }
  1459. }
  1460. if (!(Flags & HEAP_NO_SERIALIZE)) {
  1461. //
  1462. // Unlock the free list.
  1463. //
  1464. RtlReleaseLockRoutine( Heap->LockVariable );
  1465. }
  1466. //
  1467. // Return the address of the user portion of the allocated block.
  1468. // This is the byte following the header.
  1469. //
  1470. ReturnValue = BusyBlock + 1;
  1471. if (Flags & HEAP_ZERO_MEMORY) {
  1472. RtlZeroMemory( ReturnValue, Size );
  1473. }
  1474. return(ReturnValue);
  1475. } else if (AllocationIndex <= Heap->VirtualMemoryThreshold) {
  1476. LookInNonDedicatedList:
  1477. FreeListHead = &Heap->FreeLists[0];
  1478. Next = FreeListHead->Flink;
  1479. while (FreeListHead != Next) {
  1480. FreeBlock = CONTAINING_RECORD( Next, HEAP_FREE_ENTRY, FreeList );
  1481. if (FreeBlock->Size >= AllocationIndex) {
  1482. RtlpFastRemoveNonDedicatedFreeBlock( Heap, FreeBlock );
  1483. goto SplitFreeBlock;
  1484. }
  1485. Next = Next->Flink;
  1486. }
  1487. FreeBlock = RtlpExtendHeap( Heap, AllocationSize );
  1488. if (FreeBlock != NULL) {
  1489. RtlpFastRemoveNonDedicatedFreeBlock( Heap, FreeBlock );
  1490. goto SplitFreeBlock;
  1491. }
  1492. Status = STATUS_NO_MEMORY;
  1493. } else if (Heap->Flags & HEAP_GROWABLE) {
  1494. PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
  1495. VirtualAllocBlock = NULL;
  1496. AllocationSize += FIELD_OFFSET( HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
  1497. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  1498. (PVOID *)&VirtualAllocBlock,
  1499. 0,
  1500. &AllocationSize,
  1501. MEM_COMMIT,
  1502. PAGE_READWRITE );
  1503. if (NT_SUCCESS(Status)) {
  1504. //
  1505. // Just committed, already zero.
  1506. //
  1507. VirtualAllocBlock->BusyBlock.Size = (USHORT)(AllocationSize - Size);
  1508. VirtualAllocBlock->BusyBlock.Flags = HEAP_ENTRY_VIRTUAL_ALLOC | HEAP_ENTRY_EXTRA_PRESENT | HEAP_ENTRY_BUSY;
  1509. VirtualAllocBlock->CommitSize = AllocationSize;
  1510. VirtualAllocBlock->ReserveSize = AllocationSize;
  1511. InsertTailList( &Heap->VirtualAllocdBlocks, (PLIST_ENTRY)VirtualAllocBlock );
  1512. if (!(Flags & HEAP_NO_SERIALIZE)) {
  1513. //
  1514. // Unlock the free list.
  1515. //
  1516. RtlReleaseLockRoutine( Heap->LockVariable );
  1517. }
  1518. //
  1519. // Return the address of the user portion of the allocated block.
  1520. // This is the byte following the header.
  1521. //
  1522. return (PHEAP_ENTRY)(VirtualAllocBlock + 1);
  1523. }
  1524. } else {
  1525. Status = STATUS_BUFFER_TOO_SMALL;
  1526. }
  1527. //
  1528. // This is the error return.
  1529. //
  1530. if (!(Flags & HEAP_NO_SERIALIZE)) {
  1531. //
  1532. // Unlock the free list.
  1533. //
  1534. RtlReleaseLockRoutine( Heap->LockVariable );
  1535. }
  1536. if (Flags & HEAP_GENERATE_EXCEPTIONS) {
  1537. //
  1538. // Construct an exception record.
  1539. //
  1540. ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
  1541. ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL;
  1542. ExceptionRecord.NumberParameters = 1;
  1543. ExceptionRecord.ExceptionFlags = 0;
  1544. ExceptionRecord.ExceptionInformation[ 0 ] = AllocationSize;
  1545. RtlRaiseException( &ExceptionRecord );
  1546. }
  1547. SET_LAST_STATUS(Status);
  1548. return(NULL);
  1549. } else {
  1550. return(RtlAllocateHeapSlowly(HeapHandle, Flags, Size));
  1551. }
  1552. }
  1553. PVOID
  1554. RtlAllocateHeapSlowly(
  1555. IN PVOID HeapHandle,
  1556. IN ULONG Flags,
  1557. IN ULONG Size
  1558. )
  1559. {
  1560. PHEAP Heap = (PHEAP)HeapHandle;
  1561. BOOLEAN LockAcquired;
  1562. PVOID ReturnValue=NULL;
  1563. PULONG FreeListsInUse;
  1564. ULONG FreeListsInUseUlong;
  1565. ULONG AllocationSize;
  1566. ULONG FreeSize, AllocationIndex;
  1567. UCHAR EntryFlags, FreeFlags;
  1568. PLIST_ENTRY FreeListHead, Next;
  1569. PHEAP_ENTRY BusyBlock;
  1570. PHEAP_FREE_ENTRY FreeBlock, SplitBlock, SplitBlock2;
  1571. PHEAP_ENTRY_EXTRA ExtraStuff;
  1572. NTSTATUS Status;
  1573. EXCEPTION_RECORD ExceptionRecord;
  1574. ULONG ZeroSize = 0;
  1575. RTL_PAGED_CODE();
  1576. //
  1577. // Note that Flags has already been OR'd with Heap->ForceFlags.
  1578. //
  1579. #ifndef NTOS_KERNEL_RUNTIME
  1580. if (DEBUG_HEAP( Flags )) {
  1581. return RtlDebugAllocateHeap( HeapHandle, Flags, Size );
  1582. }
  1583. #endif // NTOS_KERNEL_RUNTIME
  1584. if (Size > 0x7fffffff) {
  1585. SET_LAST_STATUS( STATUS_NO_MEMORY );
  1586. return NULL;
  1587. }
  1588. AllocationSize = ((Size ? Size : 1) + Heap->AlignRound) & Heap->AlignMask;
  1589. EntryFlags = (UCHAR)(HEAP_ENTRY_BUSY | ((Flags & HEAP_SETTABLE_USER_FLAGS) >> 4));
  1590. if (Flags & HEAP_NEED_EXTRA_FLAGS || Heap->PseudoTagEntries != NULL) {
  1591. EntryFlags |= HEAP_ENTRY_EXTRA_PRESENT;
  1592. AllocationSize += sizeof( HEAP_ENTRY_EXTRA );
  1593. }
  1594. AllocationIndex = AllocationSize >> HEAP_GRANULARITY_SHIFT;
  1595. //
  1596. // Lock the free list.
  1597. //
  1598. if (!(Flags & HEAP_NO_SERIALIZE)) {
  1599. RtlAcquireLockRoutine( Heap->LockVariable );
  1600. LockAcquired = TRUE;
  1601. }
  1602. else {
  1603. LockAcquired = FALSE;
  1604. }
  1605. try {
  1606. if (AllocationIndex < HEAP_MAXIMUM_FREELISTS) {
  1607. FreeListHead = &Heap->FreeLists[ AllocationIndex ];
  1608. if ( !IsListEmpty( FreeListHead )) {
  1609. FreeBlock = CONTAINING_RECORD( FreeListHead->Flink,
  1610. HEAP_FREE_ENTRY,
  1611. FreeList
  1612. );
  1613. FreeFlags = FreeBlock->Flags;
  1614. RtlpRemoveFreeBlock( Heap, FreeBlock );
  1615. Heap->TotalFreeSize -= AllocationIndex;
  1616. BusyBlock = (PHEAP_ENTRY)FreeBlock;
  1617. BusyBlock->Flags = EntryFlags | (FreeFlags & HEAP_ENTRY_LAST_ENTRY);
  1618. BusyBlock->UnusedBytes = (UCHAR)(AllocationSize - Size);
  1619. }
  1620. else {
  1621. if (AllocationIndex < (HEAP_MAXIMUM_FREELISTS * 1) / 4) {
  1622. FreeListsInUse = &Heap->u.FreeListsInUseUlong[ 0 ];
  1623. FreeListsInUseUlong = *FreeListsInUse++ >> (AllocationIndex & 0x1F);
  1624. if (FreeListsInUseUlong) {
  1625. FreeListHead += RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1626. }
  1627. else {
  1628. FreeListsInUseUlong = *FreeListsInUse++;
  1629. if (FreeListsInUseUlong) {
  1630. FreeListHead += ((HEAP_MAXIMUM_FREELISTS * 1) / 4) -
  1631. (AllocationIndex & 0x1F) +
  1632. RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1633. }
  1634. else {
  1635. FreeListsInUseUlong = *FreeListsInUse++;
  1636. if (FreeListsInUseUlong) {
  1637. FreeListHead += ((HEAP_MAXIMUM_FREELISTS * 2) / 4) -
  1638. (AllocationIndex & 0x1F) +
  1639. RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1640. }
  1641. else {
  1642. FreeListsInUseUlong = *FreeListsInUse++;
  1643. if (FreeListsInUseUlong) {
  1644. FreeListHead += ((HEAP_MAXIMUM_FREELISTS * 3) / 4) -
  1645. (AllocationIndex & 0x1F) +
  1646. RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1647. }
  1648. else {
  1649. goto LookInNonDedicatedList;
  1650. }
  1651. }
  1652. }
  1653. }
  1654. }
  1655. else
  1656. if (AllocationIndex < (HEAP_MAXIMUM_FREELISTS * 2) / 4) {
  1657. FreeListsInUse = &Heap->u.FreeListsInUseUlong[ 1 ];
  1658. FreeListsInUseUlong = *FreeListsInUse++ >> (AllocationIndex & 0x1F);
  1659. if (FreeListsInUseUlong) {
  1660. FreeListHead += RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1661. }
  1662. else {
  1663. FreeListsInUseUlong = *FreeListsInUse++;
  1664. if (FreeListsInUseUlong) {
  1665. FreeListHead += ((HEAP_MAXIMUM_FREELISTS * 1) / 4) -
  1666. (AllocationIndex & 0x1F) +
  1667. RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1668. }
  1669. else {
  1670. FreeListsInUseUlong = *FreeListsInUse++;
  1671. if (FreeListsInUseUlong) {
  1672. FreeListHead += ((HEAP_MAXIMUM_FREELISTS * 2) / 4) -
  1673. (AllocationIndex & 0x1F) +
  1674. RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1675. }
  1676. else {
  1677. goto LookInNonDedicatedList;
  1678. }
  1679. }
  1680. }
  1681. }
  1682. else
  1683. if (AllocationIndex < (HEAP_MAXIMUM_FREELISTS * 3) / 4) {
  1684. FreeListsInUse = &Heap->u.FreeListsInUseUlong[ 2 ];
  1685. FreeListsInUseUlong = *FreeListsInUse++ >> (AllocationIndex & 0x1F);
  1686. if (FreeListsInUseUlong) {
  1687. FreeListHead += RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1688. }
  1689. else {
  1690. FreeListsInUseUlong = *FreeListsInUse++;
  1691. if (FreeListsInUseUlong) {
  1692. FreeListHead += ((HEAP_MAXIMUM_FREELISTS * 1) / 4) -
  1693. (AllocationIndex & 0x1F) +
  1694. RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1695. }
  1696. else {
  1697. goto LookInNonDedicatedList;
  1698. }
  1699. }
  1700. }
  1701. else {
  1702. FreeListsInUse = &Heap->u.FreeListsInUseUlong[ 3 ];
  1703. FreeListsInUseUlong = *FreeListsInUse++ >> (AllocationIndex & 0x1F);
  1704. if (FreeListsInUseUlong) {
  1705. FreeListHead += RtlFindFirstSetRightMember( FreeListsInUseUlong );
  1706. }
  1707. else {
  1708. goto LookInNonDedicatedList;
  1709. }
  1710. }
  1711. FreeBlock = CONTAINING_RECORD( FreeListHead->Flink,
  1712. HEAP_FREE_ENTRY,
  1713. FreeList
  1714. );
  1715. SplitFreeBlock:
  1716. FreeFlags = FreeBlock->Flags;
  1717. RtlpRemoveFreeBlock( Heap, FreeBlock );
  1718. Heap->TotalFreeSize -= FreeBlock->Size;
  1719. BusyBlock = (PHEAP_ENTRY)FreeBlock;
  1720. BusyBlock->Flags = EntryFlags;
  1721. FreeSize = BusyBlock->Size - AllocationIndex;
  1722. BusyBlock->Size = (USHORT)AllocationIndex;
  1723. BusyBlock->UnusedBytes = (UCHAR)(AllocationSize - Size);
  1724. if (FreeSize != 0) {
  1725. if (FreeSize == 1) {
  1726. BusyBlock->Size += 1;
  1727. BusyBlock->UnusedBytes += sizeof( HEAP_ENTRY );
  1728. }
  1729. else {
  1730. SplitBlock = (PHEAP_FREE_ENTRY)(BusyBlock + AllocationIndex);
  1731. SplitBlock->Flags = FreeFlags;
  1732. SplitBlock->PreviousSize = (USHORT)AllocationIndex;
  1733. SplitBlock->SegmentIndex = BusyBlock->SegmentIndex;
  1734. SplitBlock->Size = (USHORT)FreeSize;
  1735. if (FreeFlags & HEAP_ENTRY_LAST_ENTRY) {
  1736. RtlpInsertFreeBlockDirect( Heap, SplitBlock, (USHORT)FreeSize );
  1737. Heap->TotalFreeSize += FreeSize;
  1738. }
  1739. else {
  1740. SplitBlock2 = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize);
  1741. if (SplitBlock2->Flags & HEAP_ENTRY_BUSY) {
  1742. SplitBlock2->PreviousSize = (USHORT)FreeSize;
  1743. RtlpInsertFreeBlockDirect( Heap, SplitBlock, (USHORT)FreeSize );
  1744. Heap->TotalFreeSize += FreeSize;
  1745. }
  1746. else {
  1747. SplitBlock->Flags = SplitBlock2->Flags;
  1748. RtlpRemoveFreeBlock( Heap, SplitBlock2 );
  1749. Heap->TotalFreeSize -= SplitBlock2->Size;
  1750. FreeSize += SplitBlock2->Size;
  1751. if (FreeSize <= HEAP_MAXIMUM_BLOCK_SIZE) {
  1752. SplitBlock->Size = (USHORT)FreeSize;
  1753. if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  1754. ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
  1755. }
  1756. RtlpInsertFreeBlockDirect( Heap, SplitBlock, (USHORT)FreeSize );
  1757. Heap->TotalFreeSize += FreeSize;
  1758. }
  1759. else {
  1760. RtlpInsertFreeBlock( Heap, SplitBlock, FreeSize );
  1761. }
  1762. }
  1763. }
  1764. FreeFlags = 0;
  1765. }
  1766. }
  1767. if (FreeFlags & HEAP_ENTRY_LAST_ENTRY) {
  1768. BusyBlock->Flags |= HEAP_ENTRY_LAST_ENTRY;
  1769. }
  1770. }
  1771. ReturnValue = BusyBlock + 1;
  1772. if (Flags & HEAP_ZERO_MEMORY) {
  1773. ZeroSize = Size;
  1774. }
  1775. else
  1776. if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED) {
  1777. RtlFillMemoryUlong( (PCHAR)(BusyBlock + 1), Size & ~0x3, ALLOC_HEAP_FILL );
  1778. }
  1779. if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED) {
  1780. RtlFillMemory( (PCHAR)ReturnValue + Size,
  1781. CHECK_HEAP_TAIL_SIZE,
  1782. CHECK_HEAP_TAIL_FILL
  1783. );
  1784. BusyBlock->Flags |= HEAP_ENTRY_FILL_PATTERN;
  1785. }
  1786. BusyBlock->SmallTagIndex = 0;
  1787. if (BusyBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  1788. ExtraStuff = RtlpGetExtraStuffPointer( BusyBlock );
  1789. ExtraStuff->ZeroInit = 0;
  1790. #ifndef NTOS_KERNEL_RUNTIME
  1791. if (IS_HEAP_TAGGING_ENABLED()) {
  1792. ExtraStuff->TagIndex = RtlpUpdateTagEntry( Heap,
  1793. (USHORT)((Flags & HEAP_TAG_MASK) >> HEAP_TAG_SHIFT),
  1794. 0,
  1795. BusyBlock->Size,
  1796. AllocationAction
  1797. );
  1798. }
  1799. }
  1800. else
  1801. if (IS_HEAP_TAGGING_ENABLED()) {
  1802. BusyBlock->SmallTagIndex = (UCHAR)RtlpUpdateTagEntry( Heap,
  1803. (USHORT)((Flags & HEAP_SMALL_TAG_MASK) >> HEAP_TAG_SHIFT),
  1804. 0,
  1805. BusyBlock->Size,
  1806. AllocationAction
  1807. );
  1808. #endif // NTOS_KERNEL_RUNTIME
  1809. }
  1810. #if ENABLE_HEAP_EVENT_LOGGING
  1811. if (RtlAreLogging( Heap->EventLogMask )) {
  1812. RtlLogEvent( RtlpAllocHeapEventId,
  1813. Heap->EventLogMask,
  1814. Heap,
  1815. Flags,
  1816. Size,
  1817. ReturnValue
  1818. );
  1819. }
  1820. #endif // ENABLE_HEAP_EVENT_LOGGING
  1821. //
  1822. // Return the address of the user portion of the allocated block.
  1823. // This is the byte following the header.
  1824. //
  1825. leave;
  1826. }
  1827. else
  1828. if (AllocationIndex <= Heap->VirtualMemoryThreshold) {
  1829. LookInNonDedicatedList:
  1830. FreeListHead = &Heap->FreeLists[ 0 ];
  1831. Next = FreeListHead->Flink;
  1832. while (FreeListHead != Next) {
  1833. FreeBlock = CONTAINING_RECORD( Next, HEAP_FREE_ENTRY, FreeList );
  1834. if (FreeBlock->Size >= AllocationIndex) {
  1835. goto SplitFreeBlock;
  1836. }
  1837. else {
  1838. Next = Next->Flink;
  1839. }
  1840. }
  1841. FreeBlock = RtlpExtendHeap( Heap, AllocationSize );
  1842. if (FreeBlock != NULL) {
  1843. goto SplitFreeBlock;
  1844. }
  1845. Status = STATUS_NO_MEMORY;
  1846. }
  1847. else
  1848. if (Heap->Flags & HEAP_GROWABLE) {
  1849. PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
  1850. VirtualAllocBlock = NULL;
  1851. AllocationSize += FIELD_OFFSET( HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
  1852. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  1853. (PVOID *)&VirtualAllocBlock,
  1854. 0,
  1855. &AllocationSize,
  1856. MEM_COMMIT,
  1857. PAGE_READWRITE
  1858. );
  1859. if (NT_SUCCESS( Status )) {
  1860. //
  1861. // Just committed, already zero.
  1862. //
  1863. VirtualAllocBlock->BusyBlock.Size = (USHORT)(AllocationSize - Size);
  1864. VirtualAllocBlock->BusyBlock.Flags = EntryFlags | HEAP_ENTRY_VIRTUAL_ALLOC | HEAP_ENTRY_EXTRA_PRESENT;
  1865. VirtualAllocBlock->CommitSize = AllocationSize;
  1866. VirtualAllocBlock->ReserveSize = AllocationSize;
  1867. #ifndef NTOS_KERNEL_RUNTIME
  1868. if (IS_HEAP_TAGGING_ENABLED()) {
  1869. VirtualAllocBlock->ExtraStuff.TagIndex =
  1870. RtlpUpdateTagEntry( Heap,
  1871. (USHORT)((Flags & HEAP_SMALL_TAG_MASK) >> HEAP_TAG_SHIFT),
  1872. 0,
  1873. VirtualAllocBlock->CommitSize >> HEAP_GRANULARITY_SHIFT,
  1874. VirtualAllocationAction
  1875. );
  1876. }
  1877. #endif // NTOS_KERNEL_RUNTIME
  1878. InsertTailList( &Heap->VirtualAllocdBlocks, (PLIST_ENTRY)VirtualAllocBlock );
  1879. //
  1880. // Return the address of the user portion of the allocated block.
  1881. // This is the byte following the header.
  1882. //
  1883. ReturnValue = (PHEAP_ENTRY)(VirtualAllocBlock + 1);
  1884. #if ENABLE_HEAP_EVENT_LOGGING
  1885. if (RtlAreLogging( Heap->EventLogMask )) {
  1886. RtlLogEvent( RtlpAllocHeapEventId,
  1887. Heap->EventLogMask,
  1888. Heap,
  1889. Flags,
  1890. Size,
  1891. ReturnValue
  1892. );
  1893. }
  1894. #endif // ENABLE_HEAP_EVENT_LOGGING
  1895. leave;
  1896. }
  1897. }
  1898. else {
  1899. Status = STATUS_BUFFER_TOO_SMALL;
  1900. }
  1901. SET_LAST_STATUS( Status );
  1902. #if ENABLE_HEAP_EVENT_LOGGING
  1903. if (RtlAreLogging( Heap->EventLogMask )) {
  1904. RtlLogEvent( RtlpAllocHeapEventId,
  1905. Heap->EventLogMask,
  1906. Heap,
  1907. Flags,
  1908. Size,
  1909. NULL
  1910. );
  1911. }
  1912. #endif // ENABLE_HEAP_EVENT_LOGGING
  1913. //
  1914. // Release the free list lock if held
  1915. //
  1916. if (LockAcquired) {
  1917. LockAcquired = FALSE;
  1918. RtlReleaseLockRoutine( Heap->LockVariable );
  1919. }
  1920. if (Flags & HEAP_GENERATE_EXCEPTIONS) {
  1921. //
  1922. // Construct an exception record.
  1923. //
  1924. ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
  1925. ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL;
  1926. ExceptionRecord.NumberParameters = 1;
  1927. ExceptionRecord.ExceptionFlags = 0;
  1928. ExceptionRecord.ExceptionInformation[ 0 ] = AllocationSize;
  1929. RtlRaiseException( &ExceptionRecord );
  1930. }
  1931. }
  1932. except( GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_CONTINUE_SEARCH :
  1933. EXCEPTION_EXECUTE_HANDLER
  1934. ) {
  1935. SET_LAST_STATUS( GetExceptionCode() );
  1936. }
  1937. //
  1938. // Release the free list lock if held
  1939. //
  1940. if (LockAcquired) {
  1941. RtlReleaseLockRoutine( Heap->LockVariable );
  1942. }
  1943. if ( ZeroSize ) {
  1944. RtlZeroMemory( ReturnValue, ZeroSize );
  1945. }
  1946. return ReturnValue;
  1947. }
  1948. BOOLEAN
  1949. RtlFreeHeap(
  1950. IN PVOID HeapHandle,
  1951. IN ULONG Flags,
  1952. IN PVOID BaseAddress
  1953. )
  1954. {
  1955. NTSTATUS Status;
  1956. PHEAP Heap = (PHEAP)HeapHandle;
  1957. PHEAP_ENTRY BusyBlock;
  1958. PHEAP_ENTRY_EXTRA ExtraStuff;
  1959. ULONG FreeSize;
  1960. RTL_PAGED_CODE();
  1961. if ( BaseAddress != NULL ) {
  1962. Flags |= Heap->ForceFlags;
  1963. if ( ! ( Flags & HEAP_SLOW_FLAGS )) {
  1964. BusyBlock = (PHEAP_ENTRY)BaseAddress - 1;
  1965. //
  1966. // Protect ourselves from idiots by refusing to free blocks
  1967. // that do not have the busy bit set.
  1968. //
  1969. // Also refuse to free blocks that are not eight-byte aligned.
  1970. // The specific idiot in this case is Office95, which likes
  1971. // to free a random pointer when you start Word95 from a desktop
  1972. // shortcut.
  1973. //
  1974. // As further insurance against idiots, check the segment index
  1975. // to make sure it is less than HEAP_MAXIMUM_SEGMENTS (16). This
  1976. // should fix all the dorks who have ASCII or Unicode where the
  1977. // heap header is supposed to be.
  1978. //
  1979. if ((BusyBlock->Flags & HEAP_ENTRY_BUSY) &&
  1980. (((ULONG)BaseAddress & 0x7) == 0) &&
  1981. (BusyBlock->SegmentIndex < HEAP_MAXIMUM_SEGMENTS)) {
  1982. //
  1983. // Lock the heap
  1984. //
  1985. if (!(Flags & HEAP_NO_SERIALIZE)) {
  1986. RtlAcquireLockRoutine( Heap->LockVariable );
  1987. }
  1988. if (!(BusyBlock->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)) {
  1989. FreeSize = BusyBlock->Size;
  1990. #ifdef NTOS_KERNEL_RUNTIME
  1991. BusyBlock = (PHEAP_ENTRY)RtlpCoalesceFreeBlocks( Heap,
  1992. (PHEAP_FREE_ENTRY)BusyBlock,
  1993. &FreeSize,
  1994. FALSE );
  1995. #else
  1996. if (!(Heap->Flags & HEAP_DISABLE_COALESCE_ON_FREE)) {
  1997. BusyBlock = (PHEAP_ENTRY)RtlpCoalesceFreeBlocks( Heap,
  1998. (PHEAP_FREE_ENTRY)BusyBlock,
  1999. &FreeSize,
  2000. FALSE );
  2001. }
  2002. #endif
  2003. //
  2004. // Check for a small allocation that can go on a freelist
  2005. // first, these should never trigger a decommit.
  2006. //
  2007. HEAPASSERT(HEAP_MAXIMUM_FREELISTS < Heap->DeCommitFreeBlockThreshold);
  2008. if (FreeSize < HEAP_MAXIMUM_FREELISTS) {
  2009. RtlpFastInsertDedicatedFreeBlockDirect( Heap,
  2010. (PHEAP_FREE_ENTRY)BusyBlock,
  2011. (USHORT)FreeSize );
  2012. Heap->TotalFreeSize += FreeSize;
  2013. if (!(BusyBlock->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  2014. HEAPASSERT((BusyBlock + FreeSize)->PreviousSize == (USHORT)FreeSize);
  2015. }
  2016. } else if ((FreeSize < Heap->DeCommitFreeBlockThreshold) ||
  2017. ((Heap->TotalFreeSize + FreeSize) < Heap->DeCommitTotalFreeThreshold)) {
  2018. if (FreeSize <= (ULONG)HEAP_MAXIMUM_BLOCK_SIZE) {
  2019. RtlpFastInsertNonDedicatedFreeBlockDirect( Heap,
  2020. (PHEAP_FREE_ENTRY)BusyBlock,
  2021. (USHORT)FreeSize );
  2022. if (!(BusyBlock->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  2023. HEAPASSERT((BusyBlock + FreeSize)->PreviousSize == (USHORT)FreeSize);
  2024. }
  2025. Heap->TotalFreeSize += FreeSize;
  2026. } else {
  2027. RtlpInsertFreeBlock( Heap, (PHEAP_FREE_ENTRY)BusyBlock, FreeSize );
  2028. }
  2029. } else {
  2030. RtlpDeCommitFreeBlock( Heap, (PHEAP_FREE_ENTRY)BusyBlock, FreeSize );
  2031. }
  2032. //
  2033. // Unlock the heap
  2034. //
  2035. if (!(Flags & HEAP_NO_SERIALIZE)) {
  2036. RtlReleaseLockRoutine( Heap->LockVariable );
  2037. }
  2038. } else {
  2039. PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
  2040. VirtualAllocBlock = CONTAINING_RECORD( BusyBlock, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
  2041. RemoveEntryList( &VirtualAllocBlock->Entry );
  2042. //
  2043. // Release lock here as there is no reason to hold it across
  2044. // the system call.
  2045. //
  2046. if (!(Flags & HEAP_NO_SERIALIZE)) {
  2047. RtlReleaseLockRoutine( Heap->LockVariable );
  2048. }
  2049. FreeSize = 0;
  2050. Status = ZwFreeVirtualMemory( NtCurrentProcess(),
  2051. (PVOID *)&VirtualAllocBlock,
  2052. &FreeSize,
  2053. MEM_RELEASE
  2054. );
  2055. if (!NT_SUCCESS( Status )) {
  2056. SET_LAST_STATUS( Status );
  2057. return(FALSE);
  2058. }
  2059. }
  2060. return(TRUE);
  2061. } else {
  2062. //
  2063. // Not a busy block, fail the call.
  2064. //
  2065. SET_LAST_STATUS( STATUS_INVALID_PARAMETER );
  2066. return(FALSE);
  2067. }
  2068. } else {
  2069. //
  2070. // Call the do-everything allocator.
  2071. //
  2072. return(RtlFreeHeapSlowly(HeapHandle, Flags, BaseAddress));
  2073. }
  2074. } else {
  2075. //
  2076. // BaseAddress is NULL, just return success
  2077. //
  2078. return(TRUE);
  2079. }
  2080. } // RtlFreeHeap
  2081. BOOLEAN
  2082. RtlFreeHeapSlowly(
  2083. IN PVOID HeapHandle,
  2084. IN ULONG Flags,
  2085. IN PVOID BaseAddress
  2086. )
  2087. {
  2088. NTSTATUS Status;
  2089. PHEAP Heap = (PHEAP)HeapHandle;
  2090. PHEAP_ENTRY BusyBlock;
  2091. PHEAP_ENTRY_EXTRA ExtraStuff;
  2092. ULONG FreeSize;
  2093. BOOLEAN Result, LockAcquired;
  2094. #ifndef NTOS_KERNEL_RUNTIME
  2095. USHORT TagIndex;
  2096. #endif // NTOS_KERNEL_RUNTIME
  2097. RTL_PAGED_CODE();
  2098. //
  2099. // Note that Flags has already been OR'd with Heap->ForceFlags.
  2100. //
  2101. #ifndef NTOS_KERNEL_RUNTIME
  2102. if (DEBUG_HEAP( Flags )) {
  2103. return RtlDebugFreeHeap( HeapHandle, Flags, BaseAddress );
  2104. }
  2105. #endif // NTOS_KERNEL_RUNTIME
  2106. Result = FALSE;
  2107. //
  2108. // Lock the heap
  2109. //
  2110. if (!(Flags & HEAP_NO_SERIALIZE)) {
  2111. RtlAcquireLockRoutine( Heap->LockVariable );
  2112. LockAcquired = TRUE;
  2113. }
  2114. else {
  2115. LockAcquired = FALSE;
  2116. }
  2117. try {
  2118. BusyBlock = (PHEAP_ENTRY)BaseAddress - 1;
  2119. if ((BusyBlock->Flags & HEAP_ENTRY_BUSY) &&
  2120. (((ULONG)BaseAddress & 0x7) == 0) &&
  2121. (BusyBlock->SegmentIndex < HEAP_MAXIMUM_SEGMENTS)) {
  2122. if (BusyBlock->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) {
  2123. PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
  2124. VirtualAllocBlock = CONTAINING_RECORD( BusyBlock, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
  2125. RemoveEntryList( &VirtualAllocBlock->Entry );
  2126. #ifndef NTOS_KERNEL_RUNTIME
  2127. if (IS_HEAP_TAGGING_ENABLED()) {
  2128. RtlpUpdateTagEntry( Heap,
  2129. VirtualAllocBlock->ExtraStuff.TagIndex,
  2130. VirtualAllocBlock->CommitSize >> HEAP_GRANULARITY_SHIFT,
  2131. 0,
  2132. VirtualFreeAction
  2133. );
  2134. }
  2135. #endif // NTOS_KERNEL_RUNTIME
  2136. FreeSize = 0;
  2137. Status = ZwFreeVirtualMemory( NtCurrentProcess(),
  2138. (PVOID *)&VirtualAllocBlock,
  2139. &FreeSize,
  2140. MEM_RELEASE
  2141. );
  2142. if (NT_SUCCESS( Status )) {
  2143. Result = TRUE;
  2144. }
  2145. else {
  2146. SET_LAST_STATUS( Status );
  2147. }
  2148. }
  2149. else {
  2150. #ifndef NTOS_KERNEL_RUNTIME
  2151. if (IS_HEAP_TAGGING_ENABLED()) {
  2152. if (BusyBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  2153. ExtraStuff = (PHEAP_ENTRY_EXTRA)(BusyBlock + BusyBlock->Size - 1);
  2154. TagIndex = RtlpUpdateTagEntry( Heap,
  2155. ExtraStuff->TagIndex,
  2156. BusyBlock->Size,
  2157. 0,
  2158. FreeAction
  2159. );
  2160. }
  2161. else {
  2162. TagIndex = RtlpUpdateTagEntry( Heap,
  2163. BusyBlock->SmallTagIndex,
  2164. BusyBlock->Size,
  2165. 0,
  2166. FreeAction
  2167. );
  2168. }
  2169. }
  2170. else {
  2171. TagIndex = 0;
  2172. }
  2173. #endif // NTOS_KERNEL_RUNTIME
  2174. FreeSize = BusyBlock->Size;
  2175. #ifndef NTOS_KERNEL_RUNTIME
  2176. if (!(Heap->Flags & HEAP_DISABLE_COALESCE_ON_FREE)) {
  2177. #endif // NTOS_KERNEL_RUNTIME
  2178. BusyBlock = (PHEAP_ENTRY)RtlpCoalesceFreeBlocks( Heap, (PHEAP_FREE_ENTRY)BusyBlock, &FreeSize, FALSE );
  2179. #ifndef NTOS_KERNEL_RUNTIME
  2180. }
  2181. #endif // NTOS_KERNEL_RUNTIME
  2182. if (FreeSize < Heap->DeCommitFreeBlockThreshold ||
  2183. (Heap->TotalFreeSize + FreeSize) < Heap->DeCommitTotalFreeThreshold
  2184. ) {
  2185. if (FreeSize <= (ULONG)HEAP_MAXIMUM_BLOCK_SIZE) {
  2186. RtlpInsertFreeBlockDirect( Heap, (PHEAP_FREE_ENTRY)BusyBlock, (USHORT)FreeSize );
  2187. if (!(BusyBlock->Flags & HEAP_ENTRY_LAST_ENTRY)) {
  2188. HEAPASSERT((BusyBlock + FreeSize)->PreviousSize == (USHORT)FreeSize);
  2189. }
  2190. Heap->TotalFreeSize += FreeSize;
  2191. }
  2192. else {
  2193. RtlpInsertFreeBlock( Heap, (PHEAP_FREE_ENTRY)BusyBlock, FreeSize );
  2194. }
  2195. #ifndef NTOS_KERNEL_RUNTIME
  2196. if (TagIndex != 0) {
  2197. PHEAP_FREE_ENTRY_EXTRA FreeExtra;
  2198. BusyBlock->Flags |= HEAP_ENTRY_EXTRA_PRESENT;
  2199. FreeExtra = (PHEAP_FREE_ENTRY_EXTRA)(BusyBlock + BusyBlock->Size) - 1;
  2200. FreeExtra->TagIndex = TagIndex;
  2201. FreeExtra->FreeBackTraceIndex = 0;
  2202. #if i386
  2203. if (NtGlobalFlag & FLG_USER_STACK_TRACE_DB) {
  2204. FreeExtra->FreeBackTraceIndex = (USHORT)RtlLogStackBackTrace();
  2205. }
  2206. #endif // i386
  2207. }
  2208. #endif // NTOS_KERNEL_RUNTIME
  2209. }
  2210. else {
  2211. RtlpDeCommitFreeBlock( Heap, (PHEAP_FREE_ENTRY)BusyBlock, FreeSize );
  2212. }
  2213. Result = TRUE;
  2214. }
  2215. }
  2216. else {
  2217. //
  2218. // Not a busy block, fail the call.
  2219. //
  2220. SET_LAST_STATUS( STATUS_INVALID_PARAMETER );
  2221. }
  2222. #if ENABLE_HEAP_EVENT_LOGGING
  2223. if (RtlAreLogging( Heap->EventLogMask )) {
  2224. RtlLogEvent( RtlpFreeHeapEventId,
  2225. Heap->EventLogMask,
  2226. Heap,
  2227. Flags,
  2228. BaseAddress,
  2229. Result
  2230. );
  2231. }
  2232. #endif // ENABLE_HEAP_EVENT_LOGGING
  2233. }
  2234. except( EXCEPTION_EXECUTE_HANDLER ) {
  2235. SET_LAST_STATUS( GetExceptionCode() );
  2236. Result = FALSE;
  2237. }
  2238. //
  2239. // Unlock the heap
  2240. //
  2241. if (LockAcquired) {
  2242. RtlReleaseLockRoutine( Heap->LockVariable );
  2243. }
  2244. return Result;
  2245. } // RtlFreeHeap
  2246. PHEAP_ENTRY_EXTRA
  2247. RtlpGetExtraStuffPointer(
  2248. PHEAP_ENTRY BusyBlock
  2249. )
  2250. {
  2251. ULONG AllocationIndex;
  2252. if (BusyBlock->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) {
  2253. PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
  2254. VirtualAllocBlock = CONTAINING_RECORD( BusyBlock, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
  2255. return &VirtualAllocBlock->ExtraStuff;
  2256. }
  2257. else {
  2258. AllocationIndex = BusyBlock->Size;
  2259. return (PHEAP_ENTRY_EXTRA)(BusyBlock + AllocationIndex - 1);
  2260. }
  2261. }
  2262. ULONG
  2263. RtlpGetSizeOfBigBlock(
  2264. IN PHEAP_ENTRY BusyBlock
  2265. )
  2266. {
  2267. PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
  2268. RTL_PAGED_CODE();
  2269. VirtualAllocBlock = CONTAINING_RECORD( BusyBlock, HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock );
  2270. return VirtualAllocBlock->CommitSize - BusyBlock->Size;
  2271. }
  2272. BOOLEAN
  2273. RtlpCheckBusyBlockTail(
  2274. IN PHEAP_ENTRY BusyBlock
  2275. )
  2276. {
  2277. PCHAR Tail;
  2278. ULONG Size, cbEqual;
  2279. RTL_PAGED_CODE();
  2280. if (BusyBlock->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) {
  2281. Size = RtlpGetSizeOfBigBlock( BusyBlock );
  2282. }
  2283. else {
  2284. Size = (BusyBlock->Size << HEAP_GRANULARITY_SHIFT) - BusyBlock->UnusedBytes;
  2285. }
  2286. Tail = (PCHAR)(BusyBlock + 1) + Size;
  2287. cbEqual = RtlCompareMemory( Tail,
  2288. CheckHeapFillPattern,
  2289. CHECK_HEAP_TAIL_SIZE
  2290. );
  2291. if (cbEqual != CHECK_HEAP_TAIL_SIZE) {
  2292. HeapDebugPrint(( "Heap block at %lx modified at %lx past requested size of %lx\n",
  2293. BusyBlock,
  2294. Tail + cbEqual,
  2295. Size
  2296. ));
  2297. HeapDebugBreak( BusyBlock );
  2298. return FALSE;
  2299. }
  2300. else {
  2301. return TRUE;
  2302. }
  2303. }
  2304. NTSTATUS
  2305. RtlZeroHeap(
  2306. IN PVOID HeapHandle,
  2307. IN ULONG Flags
  2308. )
  2309. {
  2310. PHEAP Heap = (PHEAP)HeapHandle;
  2311. NTSTATUS Status;
  2312. BOOLEAN LockAcquired;
  2313. PHEAP_SEGMENT Segment;
  2314. ULONG SegmentIndex;
  2315. PHEAP_ENTRY CurrentBlock;
  2316. PHEAP_FREE_ENTRY FreeBlock;
  2317. ULONG Size;
  2318. PHEAP_UNCOMMMTTED_RANGE UnCommittedRange;
  2319. RTL_PAGED_CODE();
  2320. Flags |= Heap->ForceFlags;
  2321. #ifndef NTOS_KERNEL_RUNTIME
  2322. if (DEBUG_HEAP( Flags )) {
  2323. return RtlDebugZeroHeap( HeapHandle, Flags );
  2324. }
  2325. #endif // NTOS_KERNEL_RUNTIME
  2326. Status = STATUS_SUCCESS;
  2327. //
  2328. // Lock the heap
  2329. //
  2330. if (!(Flags & HEAP_NO_SERIALIZE)) {
  2331. RtlAcquireLockRoutine( Heap->LockVariable );
  2332. LockAcquired = TRUE;
  2333. }
  2334. else {
  2335. LockAcquired = FALSE;
  2336. }
  2337. try { try {
  2338. for (SegmentIndex=0; SegmentIndex<HEAP_MAXIMUM_SEGMENTS; SegmentIndex++) {
  2339. Segment = Heap->Segments[ SegmentIndex ];
  2340. if (!Segment) {
  2341. continue;
  2342. }
  2343. UnCommittedRange = Segment->UnCommittedRanges;
  2344. CurrentBlock = Segment->FirstEntry;
  2345. while (CurrentBlock < Segment->LastValidEntry) {
  2346. Size = CurrentBlock->Size << HEAP_GRANULARITY_SHIFT;
  2347. if (!(CurrentBlock->Flags & HEAP_ENTRY_BUSY)) {
  2348. FreeBlock = (PHEAP_FREE_ENTRY)CurrentBlock;
  2349. if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED &&
  2350. CurrentBlock->Flags & HEAP_ENTRY_FILL_PATTERN
  2351. ) {
  2352. RtlFillMemoryUlong( FreeBlock + 1,
  2353. Size - sizeof( *FreeBlock ),
  2354. FREE_HEAP_FILL
  2355. );
  2356. }
  2357. else {
  2358. RtlFillMemoryUlong( FreeBlock + 1,
  2359. Size - sizeof( *FreeBlock ),
  2360. 0
  2361. );
  2362. }
  2363. }
  2364. if (CurrentBlock->Flags & HEAP_ENTRY_LAST_ENTRY) {
  2365. CurrentBlock += CurrentBlock->Size;
  2366. if (UnCommittedRange == NULL) {
  2367. CurrentBlock = Segment->LastValidEntry;
  2368. }
  2369. else {
  2370. CurrentBlock = (PHEAP_ENTRY)
  2371. ((PCHAR)UnCommittedRange->Address + UnCommittedRange->Size);
  2372. UnCommittedRange = UnCommittedRange->Next;
  2373. }
  2374. }
  2375. else {
  2376. CurrentBlock += CurrentBlock->Size;
  2377. }
  2378. }
  2379. }
  2380. }
  2381. except( EXCEPTION_EXECUTE_HANDLER ) {
  2382. Status = GetExceptionCode();
  2383. }
  2384. } finally {
  2385. //
  2386. // Unlock the heap
  2387. //
  2388. if (LockAcquired) {
  2389. RtlReleaseLockRoutine( Heap->LockVariable );
  2390. }
  2391. }
  2392. return Status;
  2393. }