2 * PROJECT: ReactOS Runtime Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/rtl/heapdbg.c
5 * PURPOSE: Heap manager debug heap
6 * PROGRAMMERS: Copyright 2010 Aleksey Bragin
9 /* INCLUDES ******************************************************************/
17 /* FUNCTIONS ******************************************************************/
20 RtlDebugCreateHeap(ULONG Flags
,
25 PRTL_HEAP_PARAMETERS Parameters
)
27 MEMORY_BASIC_INFORMATION MemoryInfo
;
31 /* Validate parameters */
32 if (ReserveSize
<= HEAP_ENTRY_SIZE
)
34 DPRINT1("HEAP: Incorrect ReserveSize %x\n", ReserveSize
);
38 if (ReserveSize
< CommitSize
)
40 DPRINT1("HEAP: Incorrect CommitSize %x\n", CommitSize
);
44 if (Flags
& HEAP_NO_SERIALIZE
&& Lock
)
46 DPRINT1("HEAP: Can't specify Lock routine and have HEAP_NO_SERIALIZE flag set\n");
50 /* If the address is specified, check it's virtual memory */
53 Status
= ZwQueryVirtualMemory(NtCurrentProcess(),
55 MemoryBasicInformation
,
60 if (!NT_SUCCESS(Status
))
62 DPRINT1("HEAP: Specified heap base address %p is invalid, Status 0x%08X\n", Addr
, Status
);
66 if (MemoryInfo
.BaseAddress
!= Addr
)
68 DPRINT1("HEAP: Specified heap base address %p is not really a base one %p\n", Addr
, MemoryInfo
.BaseAddress
);
72 if (MemoryInfo
.State
== MEM_FREE
)
74 DPRINT1("HEAP: Specified heap base address %p is free\n", Addr
);
79 /* All validation performed, now call the real routine with skip validation check flag */
80 Flags
|= HEAP_SKIP_VALIDATION_CHECKS
|
81 HEAP_TAIL_CHECKING_ENABLED
|
82 HEAP_FREE_CHECKING_ENABLED
;
84 Heap
= RtlCreateHeap(Flags
, Addr
, ReserveSize
, CommitSize
, Lock
, Parameters
);
85 if (!Heap
) return NULL
;
87 // FIXME: Capture stack backtrace
89 RtlpValidateHeapHeaders(Heap
, TRUE
);
95 RtlDebugDestroyHeap(HANDLE HeapPtr
)
98 PHEAP Heap
= (PHEAP
)HeapPtr
;
100 if (Heap
== RtlGetCurrentPeb()->ProcessHeap
)
102 DPRINT1("HEAP: It's forbidden delete process heap!");
106 if (Heap
->Signature
!= HEAP_SIGNATURE
)
108 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap
, Heap
->Signature
);
112 if (!RtlpValidateHeap(Heap
, FALSE
)) return FALSE
;
114 /* Make heap invalid by zeroing its signature */
117 /* Free validate headers copy if it was existing */
118 if (Heap
->HeaderValidateCopy
)
120 ZwFreeVirtualMemory(NtCurrentProcess(),
121 &Heap
->HeaderValidateCopy
,
130 RtlDebugAllocateHeap(PVOID HeapPtr
,
134 PHEAP Heap
= (PHEAP
)HeapPtr
;
135 SIZE_T AllocSize
= 1;
136 BOOLEAN HeapLocked
= FALSE
;
139 if (Heap
->ForceFlags
& HEAP_FLAG_PAGE_ALLOCS
)
140 return RtlpPageHeapAllocate(HeapPtr
, Flags
, Size
);
142 if (Heap
->Signature
!= HEAP_SIGNATURE
)
144 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap
, Heap
->Signature
);
148 /* Add settable user value flag */
149 Flags
|= Heap
->ForceFlags
| HEAP_SETTABLE_USER_VALUE
| HEAP_SKIP_VALIDATION_CHECKS
;
152 if (Size
) AllocSize
= Size
;
153 AllocSize
= ((AllocSize
+ Heap
->AlignRound
) & Heap
->AlignMask
) + sizeof(HEAP_ENTRY_EXTRA
);
155 /* Check if size didn't exceed max one */
156 if (AllocSize
< Size
||
157 AllocSize
> Heap
->MaximumAllocationSize
)
159 DPRINT1("HEAP: Too big allocation size %x (max allowed %x)\n", Size
, Heap
->MaximumAllocationSize
);
163 /* Lock the heap ourselves */
164 if (!(Flags
& HEAP_NO_SERIALIZE
))
166 RtlEnterHeapLock(Heap
->LockVariable
, TRUE
);
169 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
170 Flags
|= HEAP_NO_SERIALIZE
;
173 /* Validate the heap if necessary */
174 RtlpValidateHeap(Heap
, FALSE
);
176 /* Call main routine to do the stuff */
177 Result
= RtlAllocateHeap(HeapPtr
, Flags
, Size
);
179 /* Validate heap headers */
180 RtlpValidateHeapHeaders(Heap
, TRUE
);
184 if (Heap
->Flags
& HEAP_VALIDATE_ALL_ENABLED
)
185 RtlpValidateHeap(Heap
, FALSE
);
188 /* Release the lock */
189 if (HeapLocked
) RtlLeaveHeapLock(Heap
->LockVariable
);
195 RtlDebugReAllocateHeap(HANDLE HeapPtr
,
200 PHEAP Heap
= (PHEAP
)HeapPtr
;
201 SIZE_T AllocSize
= 1;
202 BOOLEAN HeapLocked
= FALSE
;
204 PHEAP_ENTRY HeapEntry
;
206 if (Heap
->ForceFlags
& HEAP_FLAG_PAGE_ALLOCS
)
207 return RtlpPageHeapReAllocate(HeapPtr
, Flags
, Ptr
, Size
);
209 if (Heap
->Signature
!= HEAP_SIGNATURE
)
211 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap
, Heap
->Signature
);
215 /* Add settable user value flag */
216 Flags
|= Heap
->ForceFlags
| HEAP_SETTABLE_USER_VALUE
| HEAP_SKIP_VALIDATION_CHECKS
;
219 if (Size
) AllocSize
= Size
;
220 AllocSize
= ((AllocSize
+ Heap
->AlignRound
) & Heap
->AlignMask
) + sizeof(HEAP_ENTRY_EXTRA
);
222 /* Check if size didn't exceed max one */
223 if (AllocSize
< Size
||
224 AllocSize
> Heap
->MaximumAllocationSize
)
226 DPRINT1("HEAP: Too big allocation size %x (max allowed %x)\n", Size
, Heap
->MaximumAllocationSize
);
230 /* Lock the heap ourselves */
231 if (!(Flags
& HEAP_NO_SERIALIZE
))
233 RtlEnterHeapLock(Heap
->LockVariable
, TRUE
);
236 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
237 Flags
|= HEAP_NO_SERIALIZE
;
240 /* Validate the heap if necessary */
241 RtlpValidateHeap(Heap
, FALSE
);
243 /* Get the existing heap entry */
244 HeapEntry
= (PHEAP_ENTRY
)Ptr
- 1;
247 if (RtlpValidateHeapEntry(Heap
, HeapEntry
))
249 /* Call main routine to do the stuff */
250 Result
= RtlReAllocateHeap(HeapPtr
, Flags
, Ptr
, Size
);
254 /* Validate heap headers and then heap itself */
255 RtlpValidateHeapHeaders(Heap
, TRUE
);
256 RtlpValidateHeap(Heap
, FALSE
);
260 /* Release the lock */
261 if (HeapLocked
) RtlLeaveHeapLock(Heap
->LockVariable
);
267 RtlDebugFreeHeap(HANDLE HeapPtr
,
271 PHEAP Heap
= (PHEAP
)HeapPtr
;
272 BOOLEAN HeapLocked
= FALSE
;
273 PHEAP_ENTRY HeapEntry
;
274 BOOLEAN Result
= FALSE
;
276 if (Heap
->ForceFlags
& HEAP_FLAG_PAGE_ALLOCS
)
277 return RtlpPageHeapFree(HeapPtr
, Flags
, Ptr
);
279 if (Heap
->Signature
!= HEAP_SIGNATURE
)
281 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap
, Heap
->Signature
);
285 /* Add skip validation flag */
286 Flags
|= Heap
->ForceFlags
| HEAP_SKIP_VALIDATION_CHECKS
;
288 /* Lock the heap ourselves */
289 if (!(Flags
& HEAP_NO_SERIALIZE
))
291 RtlEnterHeapLock(Heap
->LockVariable
, TRUE
);
294 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
295 Flags
|= HEAP_NO_SERIALIZE
;
298 /* Validate the heap if necessary */
299 RtlpValidateHeap(Heap
, FALSE
);
301 /* Get the existing heap entry */
302 HeapEntry
= (PHEAP_ENTRY
)Ptr
- 1;
305 if (RtlpValidateHeapEntry(Heap
, HeapEntry
))
307 /* If it succeeded - call the main routine */
308 Result
= RtlFreeHeap(HeapPtr
, Flags
, Ptr
);
310 /* Validate heap headers and then heap itself */
311 RtlpValidateHeapHeaders(Heap
, TRUE
);
312 RtlpValidateHeap(Heap
, FALSE
);
315 /* Release the lock */
316 if (HeapLocked
) RtlLeaveHeapLock(Heap
->LockVariable
);
322 RtlDebugGetUserInfoHeap(PVOID HeapHandle
,
328 PHEAP Heap
= (PHEAP
)HeapHandle
;
329 BOOLEAN HeapLocked
= FALSE
;
330 PHEAP_ENTRY HeapEntry
;
331 BOOLEAN Result
= FALSE
;
333 if (Heap
->ForceFlags
& HEAP_FLAG_PAGE_ALLOCS
)
334 return RtlpPageHeapGetUserInfo(HeapHandle
, Flags
, BaseAddress
, UserValue
, UserFlags
);
336 if (Heap
->Signature
!= HEAP_SIGNATURE
)
338 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap
, Heap
->Signature
);
342 /* Add skip validation flag */
343 Flags
|= Heap
->ForceFlags
| HEAP_SKIP_VALIDATION_CHECKS
;
345 /* Lock the heap ourselves */
346 if (!(Flags
& HEAP_NO_SERIALIZE
))
348 RtlEnterHeapLock(Heap
->LockVariable
, TRUE
);
351 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
352 Flags
|= HEAP_NO_SERIALIZE
;
355 /* Validate the heap if necessary */
356 RtlpValidateHeap(Heap
, FALSE
);
358 /* Get the existing heap entry */
359 HeapEntry
= (PHEAP_ENTRY
)BaseAddress
- 1;
362 if (RtlpValidateHeapEntry(Heap
, HeapEntry
))
364 /* If it succeeded - call the main routine */
365 Result
= RtlGetUserInfoHeap(HeapHandle
, Flags
, BaseAddress
, UserValue
, UserFlags
);
368 /* Release the lock */
369 if (HeapLocked
) RtlLeaveHeapLock(Heap
->LockVariable
);
375 RtlDebugSetUserValueHeap(PVOID HeapHandle
,
380 PHEAP Heap
= (PHEAP
)HeapHandle
;
381 BOOLEAN HeapLocked
= FALSE
;
382 PHEAP_ENTRY HeapEntry
;
383 BOOLEAN Result
= FALSE
;
385 if (Heap
->ForceFlags
& HEAP_FLAG_PAGE_ALLOCS
)
386 return RtlpPageHeapSetUserValue(HeapHandle
, Flags
, BaseAddress
, UserValue
);
388 if (Heap
->Signature
!= HEAP_SIGNATURE
)
390 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap
, Heap
->Signature
);
394 /* Add skip validation flag */
395 Flags
|= Heap
->ForceFlags
| HEAP_SKIP_VALIDATION_CHECKS
;
397 /* Lock the heap ourselves */
398 if (!(Flags
& HEAP_NO_SERIALIZE
))
400 RtlEnterHeapLock(Heap
->LockVariable
, TRUE
);
403 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
404 Flags
|= HEAP_NO_SERIALIZE
;
407 /* Validate the heap if necessary */
408 RtlpValidateHeap(Heap
, FALSE
);
410 /* Get the existing heap entry */
411 HeapEntry
= (PHEAP_ENTRY
)BaseAddress
- 1;
414 if (RtlpValidateHeapEntry(Heap
, HeapEntry
))
416 /* If it succeeded - call the main routine */
417 Result
= RtlSetUserValueHeap(HeapHandle
, Flags
, BaseAddress
, UserValue
);
419 /* Validate the heap */
420 RtlpValidateHeap(Heap
, FALSE
);
423 /* Release the lock */
424 if (HeapLocked
) RtlLeaveHeapLock(Heap
->LockVariable
);
431 RtlDebugSetUserFlagsHeap(PVOID HeapHandle
,
434 ULONG UserFlagsReset
,
437 PHEAP Heap
= (PHEAP
)HeapHandle
;
438 BOOLEAN HeapLocked
= FALSE
;
439 PHEAP_ENTRY HeapEntry
;
440 BOOLEAN Result
= FALSE
;
442 if (Heap
->ForceFlags
& HEAP_FLAG_PAGE_ALLOCS
)
443 return RtlpPageHeapSetUserFlags(HeapHandle
, Flags
, BaseAddress
, UserFlagsReset
, UserFlagsSet
);
445 /* Check if this heap allows flags to be set at all */
446 if (UserFlagsSet
& ~HEAP_SETTABLE_USER_FLAGS
||
447 UserFlagsReset
& ~HEAP_SETTABLE_USER_FLAGS
)
452 if (Heap
->Signature
!= HEAP_SIGNATURE
)
454 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap
, Heap
->Signature
);
458 /* Add skip validation flag */
459 Flags
|= Heap
->ForceFlags
| HEAP_SKIP_VALIDATION_CHECKS
;
461 /* Lock the heap ourselves */
462 if (!(Flags
& HEAP_NO_SERIALIZE
))
464 RtlEnterHeapLock(Heap
->LockVariable
, TRUE
);
467 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
468 Flags
|= HEAP_NO_SERIALIZE
;
471 /* Validate the heap if necessary */
472 RtlpValidateHeap(Heap
, FALSE
);
474 /* Get the existing heap entry */
475 HeapEntry
= (PHEAP_ENTRY
)BaseAddress
- 1;
478 if (RtlpValidateHeapEntry(Heap
, HeapEntry
))
480 /* If it succeeded - call the main routine */
481 Result
= RtlSetUserFlagsHeap(HeapHandle
, Flags
, BaseAddress
, UserFlagsReset
, UserFlagsSet
);
483 /* Validate the heap */
484 RtlpValidateHeap(Heap
, FALSE
);
487 /* Release the lock */
488 if (HeapLocked
) RtlLeaveHeapLock(Heap
->LockVariable
);
494 RtlDebugSizeHeap(HANDLE HeapPtr
,
498 PHEAP Heap
= (PHEAP
)HeapPtr
;
499 BOOLEAN HeapLocked
= FALSE
;
500 PHEAP_ENTRY HeapEntry
;
501 SIZE_T Result
= ~(SIZE_T
)0;
503 if (Heap
->ForceFlags
& HEAP_FLAG_PAGE_ALLOCS
)
504 return RtlpPageHeapSize(HeapPtr
, Flags
, Ptr
);
506 /* Check heap signature */
507 if (Heap
->Signature
!= HEAP_SIGNATURE
)
509 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap
, Heap
->Signature
);
513 /* Add skip validation flag */
514 Flags
|= Heap
->ForceFlags
| HEAP_SKIP_VALIDATION_CHECKS
;
516 /* Lock the heap ourselves */
517 if (!(Flags
& HEAP_NO_SERIALIZE
))
519 RtlEnterHeapLock(Heap
->LockVariable
, TRUE
);
522 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
523 Flags
|= HEAP_NO_SERIALIZE
;
526 /* Validate the heap if necessary */
527 RtlpValidateHeap(Heap
, FALSE
);
529 /* Get the existing heap entry */
530 HeapEntry
= (PHEAP_ENTRY
)Ptr
- 1;
533 if (RtlpValidateHeapEntry(Heap
, HeapEntry
))
535 /* If it succeeded - call the main routine */
536 Result
= RtlSizeHeap(HeapPtr
, Flags
, Ptr
);
539 /* Release the lock */
540 if (HeapLocked
) RtlLeaveHeapLock(Heap
->LockVariable
);