1 /* 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 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <rtl.h> 12 #include <heap.h> 13 14 #define NDEBUG 15 #include <debug.h> 16 17 /* FUNCTIONS ******************************************************************/ 18 19 HANDLE NTAPI 20 RtlDebugCreateHeap(ULONG Flags, 21 PVOID Addr, 22 SIZE_T ReserveSize, 23 SIZE_T CommitSize, 24 PVOID Lock, 25 PRTL_HEAP_PARAMETERS Parameters) 26 { 27 MEMORY_BASIC_INFORMATION MemoryInfo; 28 NTSTATUS Status; 29 PHEAP Heap; 30 31 /* Validate parameters */ 32 if (ReserveSize <= HEAP_ENTRY_SIZE) 33 { 34 DPRINT1("HEAP: Incorrect ReserveSize %x\n", ReserveSize); 35 return NULL; 36 } 37 38 if (ReserveSize < CommitSize) 39 { 40 DPRINT1("HEAP: Incorrect CommitSize %x\n", CommitSize); 41 return NULL; 42 } 43 44 if (Flags & HEAP_NO_SERIALIZE && Lock) 45 { 46 DPRINT1("HEAP: Can't specify Lock routine and have HEAP_NO_SERIALIZE flag set\n"); 47 return NULL; 48 } 49 50 /* If the address is specified, check it's virtual memory */ 51 if (Addr) 52 { 53 Status = ZwQueryVirtualMemory(NtCurrentProcess(), 54 Addr, 55 MemoryBasicInformation, 56 &MemoryInfo, 57 sizeof(MemoryInfo), 58 NULL); 59 60 if (!NT_SUCCESS(Status)) 61 { 62 DPRINT1("HEAP: Specified heap base address %p is invalid, Status 0x%08X\n", Addr, Status); 63 return NULL; 64 } 65 66 if (MemoryInfo.BaseAddress != Addr) 67 { 68 DPRINT1("HEAP: Specified heap base address %p is not really a base one %p\n", Addr, MemoryInfo.BaseAddress); 69 return NULL; 70 } 71 72 if (MemoryInfo.State == MEM_FREE) 73 { 74 DPRINT1("HEAP: Specified heap base address %p is free\n", Addr); 75 return NULL; 76 } 77 } 78 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; 83 84 Heap = RtlCreateHeap(Flags, Addr, ReserveSize, CommitSize, Lock, Parameters); 85 if (!Heap) return NULL; 86 87 // FIXME: Capture stack backtrace 88 89 RtlpValidateHeapHeaders(Heap, TRUE); 90 91 return Heap; 92 } 93 94 BOOLEAN NTAPI 95 RtlDebugDestroyHeap(HANDLE HeapPtr) 96 { 97 SIZE_T Size = 0; 98 PHEAP Heap = (PHEAP)HeapPtr; 99 100 if (Heap == RtlGetCurrentPeb()->ProcessHeap) 101 { 102 DPRINT1("HEAP: It's forbidden delete process heap!"); 103 return FALSE; 104 } 105 106 if (Heap->Signature != HEAP_SIGNATURE) 107 { 108 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature); 109 return FALSE; 110 } 111 112 if (!RtlpValidateHeap(Heap, FALSE)) return FALSE; 113 114 /* Make heap invalid by zeroing its signature */ 115 Heap->Signature = 0; 116 117 /* Free validate headers copy if it was existing */ 118 if (Heap->HeaderValidateCopy) 119 { 120 ZwFreeVirtualMemory(NtCurrentProcess(), 121 &Heap->HeaderValidateCopy, 122 &Size, 123 MEM_RELEASE); 124 } 125 126 return TRUE; 127 } 128 129 PVOID NTAPI 130 RtlDebugAllocateHeap(PVOID HeapPtr, 131 ULONG Flags, 132 SIZE_T Size) 133 { 134 PHEAP Heap = (PHEAP)HeapPtr; 135 SIZE_T AllocSize = 1; 136 BOOLEAN HeapLocked = FALSE; 137 PVOID Result; 138 139 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) 140 return RtlpPageHeapAllocate(HeapPtr, Flags, Size); 141 142 if (Heap->Signature != HEAP_SIGNATURE) 143 { 144 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature); 145 return NULL; 146 } 147 148 /* Add settable user value flag */ 149 Flags |= Heap->ForceFlags | HEAP_SETTABLE_USER_VALUE | HEAP_SKIP_VALIDATION_CHECKS; 150 151 /* Calculate size */ 152 if (Size) AllocSize = Size; 153 AllocSize = ((AllocSize + Heap->AlignRound) & Heap->AlignMask) + sizeof(HEAP_ENTRY_EXTRA); 154 155 /* Check if size didn't exceed max one */ 156 if (AllocSize < Size || 157 AllocSize > Heap->MaximumAllocationSize) 158 { 159 DPRINT1("HEAP: Too big allocation size %x (max allowed %x)\n", Size, Heap->MaximumAllocationSize); 160 return NULL; 161 } 162 163 /* Lock the heap ourselves */ 164 if (!(Flags & HEAP_NO_SERIALIZE)) 165 { 166 RtlEnterHeapLock(Heap->LockVariable, TRUE); 167 HeapLocked = TRUE; 168 169 /* Add no serialize flag so that the main routine won't try to acquire the lock again */ 170 Flags |= HEAP_NO_SERIALIZE; 171 } 172 173 /* Validate the heap if necessary */ 174 RtlpValidateHeap(Heap, FALSE); 175 176 /* Call main routine to do the stuff */ 177 Result = RtlAllocateHeap(HeapPtr, Flags, Size); 178 179 /* Validate heap headers */ 180 RtlpValidateHeapHeaders(Heap, TRUE); 181 182 if (Result) 183 { 184 if (Heap->Flags & HEAP_VALIDATE_ALL_ENABLED) 185 RtlpValidateHeap(Heap, FALSE); 186 } 187 188 /* Release the lock */ 189 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable); 190 191 return Result; 192 } 193 194 PVOID NTAPI 195 RtlDebugReAllocateHeap(HANDLE HeapPtr, 196 ULONG Flags, 197 PVOID Ptr, 198 SIZE_T Size) 199 { 200 PHEAP Heap = (PHEAP)HeapPtr; 201 SIZE_T AllocSize = 1; 202 BOOLEAN HeapLocked = FALSE; 203 PVOID Result = NULL; 204 PHEAP_ENTRY HeapEntry; 205 206 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) 207 return RtlpPageHeapReAllocate(HeapPtr, Flags, Ptr, Size); 208 209 if (Heap->Signature != HEAP_SIGNATURE) 210 { 211 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature); 212 return NULL; 213 } 214 215 /* Add settable user value flag */ 216 Flags |= Heap->ForceFlags | HEAP_SETTABLE_USER_VALUE | HEAP_SKIP_VALIDATION_CHECKS; 217 218 /* Calculate size */ 219 if (Size) AllocSize = Size; 220 AllocSize = ((AllocSize + Heap->AlignRound) & Heap->AlignMask) + sizeof(HEAP_ENTRY_EXTRA); 221 222 /* Check if size didn't exceed max one */ 223 if (AllocSize < Size || 224 AllocSize > Heap->MaximumAllocationSize) 225 { 226 DPRINT1("HEAP: Too big allocation size %x (max allowed %x)\n", Size, Heap->MaximumAllocationSize); 227 return NULL; 228 } 229 230 /* Lock the heap ourselves */ 231 if (!(Flags & HEAP_NO_SERIALIZE)) 232 { 233 RtlEnterHeapLock(Heap->LockVariable, TRUE); 234 HeapLocked = TRUE; 235 236 /* Add no serialize flag so that the main routine won't try to acquire the lock again */ 237 Flags |= HEAP_NO_SERIALIZE; 238 } 239 240 /* Validate the heap if necessary */ 241 RtlpValidateHeap(Heap, FALSE); 242 243 /* Get the existing heap entry */ 244 HeapEntry = (PHEAP_ENTRY)Ptr - 1; 245 246 /* Validate it */ 247 if (RtlpValidateHeapEntry(Heap, HeapEntry)) 248 { 249 /* Call main routine to do the stuff */ 250 Result = RtlReAllocateHeap(HeapPtr, Flags, Ptr, Size); 251 252 if (Result) 253 { 254 /* Validate heap headers and then heap itself */ 255 RtlpValidateHeapHeaders(Heap, TRUE); 256 RtlpValidateHeap(Heap, FALSE); 257 } 258 } 259 260 /* Release the lock */ 261 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable); 262 263 return Result; 264 } 265 266 BOOLEAN NTAPI 267 RtlDebugFreeHeap(HANDLE HeapPtr, 268 ULONG Flags, 269 PVOID Ptr) 270 { 271 PHEAP Heap = (PHEAP)HeapPtr; 272 BOOLEAN HeapLocked = FALSE; 273 PHEAP_ENTRY HeapEntry; 274 BOOLEAN Result = FALSE; 275 276 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) 277 return RtlpPageHeapFree(HeapPtr, Flags, Ptr); 278 279 if (Heap->Signature != HEAP_SIGNATURE) 280 { 281 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature); 282 return FALSE; 283 } 284 285 /* Add skip validation flag */ 286 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS; 287 288 /* Lock the heap ourselves */ 289 if (!(Flags & HEAP_NO_SERIALIZE)) 290 { 291 RtlEnterHeapLock(Heap->LockVariable, TRUE); 292 HeapLocked = TRUE; 293 294 /* Add no serialize flag so that the main routine won't try to acquire the lock again */ 295 Flags |= HEAP_NO_SERIALIZE; 296 } 297 298 /* Validate the heap if necessary */ 299 RtlpValidateHeap(Heap, FALSE); 300 301 /* Get the existing heap entry */ 302 HeapEntry = (PHEAP_ENTRY)Ptr - 1; 303 304 /* Validate it */ 305 if (RtlpValidateHeapEntry(Heap, HeapEntry)) 306 { 307 /* If it succeeded - call the main routine */ 308 Result = RtlFreeHeap(HeapPtr, Flags, Ptr); 309 310 /* Validate heap headers and then heap itself */ 311 RtlpValidateHeapHeaders(Heap, TRUE); 312 RtlpValidateHeap(Heap, FALSE); 313 } 314 315 /* Release the lock */ 316 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable); 317 318 return Result; 319 } 320 321 BOOLEAN NTAPI 322 RtlDebugGetUserInfoHeap(PVOID HeapHandle, 323 ULONG Flags, 324 PVOID BaseAddress, 325 PVOID *UserValue, 326 PULONG UserFlags) 327 { 328 PHEAP Heap = (PHEAP)HeapHandle; 329 BOOLEAN HeapLocked = FALSE; 330 PHEAP_ENTRY HeapEntry; 331 BOOLEAN Result = FALSE; 332 333 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) 334 return RtlpPageHeapGetUserInfo(HeapHandle, Flags, BaseAddress, UserValue, UserFlags); 335 336 if (Heap->Signature != HEAP_SIGNATURE) 337 { 338 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature); 339 return FALSE; 340 } 341 342 /* Add skip validation flag */ 343 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS; 344 345 /* Lock the heap ourselves */ 346 if (!(Flags & HEAP_NO_SERIALIZE)) 347 { 348 RtlEnterHeapLock(Heap->LockVariable, TRUE); 349 HeapLocked = TRUE; 350 351 /* Add no serialize flag so that the main routine won't try to acquire the lock again */ 352 Flags |= HEAP_NO_SERIALIZE; 353 } 354 355 /* Validate the heap if necessary */ 356 RtlpValidateHeap(Heap, FALSE); 357 358 /* Get the existing heap entry */ 359 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1; 360 361 /* Validate it */ 362 if (RtlpValidateHeapEntry(Heap, HeapEntry)) 363 { 364 /* If it succeeded - call the main routine */ 365 Result = RtlGetUserInfoHeap(HeapHandle, Flags, BaseAddress, UserValue, UserFlags); 366 } 367 368 /* Release the lock */ 369 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable); 370 371 return Result; 372 } 373 374 BOOLEAN NTAPI 375 RtlDebugSetUserValueHeap(PVOID HeapHandle, 376 ULONG Flags, 377 PVOID BaseAddress, 378 PVOID UserValue) 379 { 380 PHEAP Heap = (PHEAP)HeapHandle; 381 BOOLEAN HeapLocked = FALSE; 382 PHEAP_ENTRY HeapEntry; 383 BOOLEAN Result = FALSE; 384 385 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) 386 return RtlpPageHeapSetUserValue(HeapHandle, Flags, BaseAddress, UserValue); 387 388 if (Heap->Signature != HEAP_SIGNATURE) 389 { 390 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature); 391 return FALSE; 392 } 393 394 /* Add skip validation flag */ 395 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS; 396 397 /* Lock the heap ourselves */ 398 if (!(Flags & HEAP_NO_SERIALIZE)) 399 { 400 RtlEnterHeapLock(Heap->LockVariable, TRUE); 401 HeapLocked = TRUE; 402 403 /* Add no serialize flag so that the main routine won't try to acquire the lock again */ 404 Flags |= HEAP_NO_SERIALIZE; 405 } 406 407 /* Validate the heap if necessary */ 408 RtlpValidateHeap(Heap, FALSE); 409 410 /* Get the existing heap entry */ 411 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1; 412 413 /* Validate it */ 414 if (RtlpValidateHeapEntry(Heap, HeapEntry)) 415 { 416 /* If it succeeded - call the main routine */ 417 Result = RtlSetUserValueHeap(HeapHandle, Flags, BaseAddress, UserValue); 418 419 /* Validate the heap */ 420 RtlpValidateHeap(Heap, FALSE); 421 } 422 423 /* Release the lock */ 424 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable); 425 426 return Result; 427 } 428 429 BOOLEAN 430 NTAPI 431 RtlDebugSetUserFlagsHeap(PVOID HeapHandle, 432 ULONG Flags, 433 PVOID BaseAddress, 434 ULONG UserFlagsReset, 435 ULONG UserFlagsSet) 436 { 437 PHEAP Heap = (PHEAP)HeapHandle; 438 BOOLEAN HeapLocked = FALSE; 439 PHEAP_ENTRY HeapEntry; 440 BOOLEAN Result = FALSE; 441 442 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) 443 return RtlpPageHeapSetUserFlags(HeapHandle, Flags, BaseAddress, UserFlagsReset, UserFlagsSet); 444 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) 448 { 449 return FALSE; 450 } 451 452 if (Heap->Signature != HEAP_SIGNATURE) 453 { 454 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature); 455 return FALSE; 456 } 457 458 /* Add skip validation flag */ 459 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS; 460 461 /* Lock the heap ourselves */ 462 if (!(Flags & HEAP_NO_SERIALIZE)) 463 { 464 RtlEnterHeapLock(Heap->LockVariable, TRUE); 465 HeapLocked = TRUE; 466 467 /* Add no serialize flag so that the main routine won't try to acquire the lock again */ 468 Flags |= HEAP_NO_SERIALIZE; 469 } 470 471 /* Validate the heap if necessary */ 472 RtlpValidateHeap(Heap, FALSE); 473 474 /* Get the existing heap entry */ 475 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1; 476 477 /* Validate it */ 478 if (RtlpValidateHeapEntry(Heap, HeapEntry)) 479 { 480 /* If it succeeded - call the main routine */ 481 Result = RtlSetUserFlagsHeap(HeapHandle, Flags, BaseAddress, UserFlagsReset, UserFlagsSet); 482 483 /* Validate the heap */ 484 RtlpValidateHeap(Heap, FALSE); 485 } 486 487 /* Release the lock */ 488 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable); 489 490 return Result; 491 } 492 493 SIZE_T NTAPI 494 RtlDebugSizeHeap(HANDLE HeapPtr, 495 ULONG Flags, 496 PVOID Ptr) 497 { 498 PHEAP Heap = (PHEAP)HeapPtr; 499 BOOLEAN HeapLocked = FALSE; 500 PHEAP_ENTRY HeapEntry; 501 SIZE_T Result = ~(SIZE_T)0; 502 503 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) 504 return RtlpPageHeapSize(HeapPtr, Flags, Ptr); 505 506 /* Check heap signature */ 507 if (Heap->Signature != HEAP_SIGNATURE) 508 { 509 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature); 510 return FALSE; 511 } 512 513 /* Add skip validation flag */ 514 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS; 515 516 /* Lock the heap ourselves */ 517 if (!(Flags & HEAP_NO_SERIALIZE)) 518 { 519 RtlEnterHeapLock(Heap->LockVariable, TRUE); 520 HeapLocked = TRUE; 521 522 /* Add no serialize flag so that the main routine won't try to acquire the lock again */ 523 Flags |= HEAP_NO_SERIALIZE; 524 } 525 526 /* Validate the heap if necessary */ 527 RtlpValidateHeap(Heap, FALSE); 528 529 /* Get the existing heap entry */ 530 HeapEntry = (PHEAP_ENTRY)Ptr - 1; 531 532 /* Validate it */ 533 if (RtlpValidateHeapEntry(Heap, HeapEntry)) 534 { 535 /* If it succeeded - call the main routine */ 536 Result = RtlSizeHeap(HeapPtr, Flags, Ptr); 537 } 538 539 /* Release the lock */ 540 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable); 541 542 return Result; 543 } 544 545 /* EOF */