Reactos
at master 1995 lines 65 kB view raw
1// 2// debug_heap.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// The implementation of the CRT Debug Heap. 7// 8#ifndef _DEBUG 9 #error This file is supported only in debug builds 10 #define _DEBUG // For design-time support, when editing/viewing CRT sources 11#endif 12 13#include <corecrt_internal.h> 14#include <malloc.h> 15#include <minmax.h> 16#include <new.h> 17#include <stdio.h> 18#include <stdlib.h> 19 20 21 22//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 23// 24// Constant Data 25// 26//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27#define _ALLOCATION_FILE_LINENUM "\nMemory allocated at %hs(%d).\n" 28 29#if _FREE_BLOCK != 0 || _NORMAL_BLOCK != 1 || _CRT_BLOCK != 2 || _IGNORE_BLOCK != 3 || _CLIENT_BLOCK != 4 30 #error Block numbers have changed! 31#endif 32 33static char const* const block_use_names[_MAX_BLOCKS] 34{ 35 "Free", 36 "Normal", 37 "CRT", 38 "Ignore", 39 "Client", 40}; 41 42// The following values are non-zero, constant, odd, large, and atypical. 43// * Non-zero values help find bugs that assume zero-filled data 44// * Constant values are good so that memory filling is deterministic (to help 45// make bugs reproducible). Of course, it is bad if the constant filling of 46// weird values masks a bug. 47// * Mathematically odd numbers are good for finding bugs assuming a cleared 48// lower bit (e.g. properly aligned pointers to types other than char are not 49// odd). 50// * Large byte values are less typical and are useful for finding bad addresses. 51// * Atypical values (i.e., not too often) are good because they typically cause 52// early detection in code. 53// * For the case of the no-man's land and free blocks, if you store to any of 54// these locations, the memory integrity checker will detect it. 55// 56// The align_land_fill was changed from 0xBD to 0xED to ensure that four bytes of 57// that value (0xEDEDEDED) would form an inaccessible address outside of the lower 58// 3GB of a 32-bit process address space. 59static unsigned char const no_mans_land_fill{0xFD}; // Fill unaligned no-man's land 60static unsigned char const align_land_fill {0xED}; // Fill aligned no-man's land 61static unsigned char const dead_land_fill {0xDD}; // Fill free objects with this 62static unsigned char const clean_land_fill {0xCD}; // Fill new objects with this 63 64// The size of the no-man's land used in unaligned and aligned allocations: 65static size_t const no_mans_land_size = 4; 66static size_t const align_gap_size = sizeof(void *); 67 68// For _IGNORE_BLOCK blocks, we use these request and line numbers as sentinels. 69static long const request_number_for_ignore_blocks{0}; 70static int const line_number_for_ignore_blocks {static_cast<int>(0xFEDCBABC)}; 71 72 73 74//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 75// 76// Types 77// 78//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 79// For diagnostic purpose, blocks are allocated in the debug heap with extra 80// information and stored in a doubly-linked list. This makes all blocks 81// registered with how big they are, when they were allocated, and what they are 82// used for. 83struct _CrtMemBlockHeader 84{ 85 _CrtMemBlockHeader* _block_header_next; 86 _CrtMemBlockHeader* _block_header_prev; 87 char const* _file_name; 88 int _line_number; 89 90 int _block_use; 91 size_t _data_size; 92 93 long _request_number; 94 unsigned char _gap[no_mans_land_size]; 95 96 // Followed by: 97 // unsigned char _data[_data_size]; 98 // unsigned char _another_gap[no_mans_land_size]; 99}; 100 101static_assert( 102 sizeof(_CrtMemBlockHeader) % MEMORY_ALLOCATION_ALIGNMENT == 0, 103 "Incorrect debug heap block alignment"); 104 105 106 107//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 108// 109// Global Mutable State (Synchronized by the AppCRT Heap Lock) 110// 111//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 112// These are pointers to the first and last nodes in the debug heap's doubly 113// linked list of allocation nodes. 114static _CrtMemBlockHeader* __acrt_first_block{nullptr}; 115static _CrtMemBlockHeader* __acrt_last_block {nullptr}; 116 117// These are the statistics for the current state of the debug heap, storing the 118// total number of bytes allocated over the life of the process, the total number 119// of bytes currently allocated (but not freed), and the maximum number of bytes 120// that were ever allocated at once. 121static size_t __acrt_total_allocations {0}; 122static size_t __acrt_current_allocations{0}; 123static size_t __acrt_max_allocations {0}; 124 125// These states control the frequency with which _CrtCheckMemory. The units are 126// "calls to allocation functions." 127static unsigned __acrt_check_frequency{0}; 128static unsigned __acrt_check_counter {0}; 129 130// This is the current request number, which is incremented each time a new 131// allocation request is made. 132static long __acrt_current_request_number{1}; 133 134 135 136// These three globals had external linkage in older versions of the CRT and may 137// be referenced by name in client code. The first stores the current debug 138// heap options (flags). The second stores the next allocation number on which 139// to break. The third stores the pointer to the dump client to be used when 140// dumping heap objects. 141#undef _crtDbgFlag 142#undef _crtBreakAlloc 143 144extern "C" { 145 int _crtDbgFlag{_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_DEFAULT_DF}; 146 long _crtBreakAlloc{-1}; 147 _CRT_DUMP_CLIENT _pfnDumpClient{nullptr}; 148} 149 150extern "C" int* __p__crtDbgFlag() 151{ 152 return &_crtDbgFlag; 153} 154 155extern "C" long* __p__crtBreakAlloc() 156{ 157 return &_crtBreakAlloc; 158} 159 160 161 162//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 163// 164// Internal Utilities 165// 166//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 167static unsigned char* __cdecl block_from_header(_CrtMemBlockHeader* const header) throw() 168{ 169 return reinterpret_cast<unsigned char*>(header + 1); 170} 171 172static _CrtMemBlockHeader* __cdecl header_from_block(void const* const block) throw() 173{ 174 return static_cast<_CrtMemBlockHeader*>(const_cast<void*>(block)) - 1; 175} 176 177static bool __cdecl is_block_type_valid(int const block_use) throw() 178{ 179 return _BLOCK_TYPE(block_use) == _CLIENT_BLOCK 180 || _BLOCK_TYPE(block_use) == _CRT_BLOCK 181 || block_use == _NORMAL_BLOCK 182 || block_use == _IGNORE_BLOCK; 183} 184 185// Tests the array of size bytes starting at first. Returns true if all of the 186// bytes in the array have the given value; returns false otherwise. 187static bool __cdecl check_bytes( 188 unsigned char const* const first, 189 unsigned char const value, 190 size_t const size 191 ) throw() 192{ 193 unsigned char const* const last{first + size}; 194 for (unsigned char const* it{first}; it != last; ++it) 195 { 196 if (*it != value) 197 return false; 198 } 199 200 return true; 201} 202 203// Tests whether the size bytes of memory starting at address p can be read from. 204// The functionality is similar to that of the Windows API IsBadReadPtr(), which 205// is now deprecated. 206static bool __cdecl is_bad_read_pointer(void const* const p, size_t const size) throw() 207{ 208 SYSTEM_INFO system_info{}; 209 GetSystemInfo(&system_info); 210 DWORD const page_size{system_info.dwPageSize}; 211 212 // If the structure has zero length, then do not probe the structure for 213 // read accessibility or alignment. 214 if (size == 0) 215 return false; 216 217 // A null pointer can never be read from: 218 if (!p) 219 return true; 220 221 char const* start_address{static_cast<char const*>(p)}; 222 char const* end_address {start_address + size - 1 }; 223 if (end_address < start_address) 224 return true; 225 226 __try 227 { 228 *(volatile char*)start_address; 229 230 long const mask{~(static_cast<long>(page_size) - 1)}; 231 232 start_address = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(start_address) & mask); 233 end_address = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(end_address) & mask); 234 while (start_address != end_address) 235 { 236 start_address = start_address + page_size; 237 *reinterpret_cast<const volatile char*>(start_address); 238 } 239 } 240 __except(EXCEPTION_EXECUTE_HANDLER) 241 { 242 return true; 243 } 244 __endtry 245 246 return false; 247} 248 249static bool __cdecl is_block_an_aligned_allocation(void const* const block) throw() 250{ 251 unsigned char const* const possible_alignment_gap{reinterpret_cast<unsigned char const*>( 252 reinterpret_cast<uintptr_t>(block) & (~sizeof(uintptr_t) - 1)) - align_gap_size}; 253 254 return check_bytes(possible_alignment_gap, align_land_fill, align_gap_size); 255} 256 257// The debug heap can be configured to validate the consistency of the heap at 258// regular intervals. If this behavior is configured, this function controls 259// that validation. 260static bool heap_validation_pending{false}; 261 262static void __cdecl validate_heap_if_required_nolock() throw() 263{ 264 if (__acrt_check_frequency == 0) 265 { 266 return; 267 } 268 269 if (__acrt_check_counter != __acrt_check_frequency - 1) 270 { 271 ++__acrt_check_counter; 272 return; 273 } 274 275 if (heap_validation_pending) 276 { 277 return; 278 } 279 280 heap_validation_pending = true; 281 __try 282 { 283 _ASSERTE(_CrtCheckMemory()); 284 } 285 __finally 286 { 287 heap_validation_pending = false; 288 } 289 __endtry 290 291 __acrt_check_counter = 0; 292} 293 294 295 296//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 297// 298// Internal Debug Heap APIs 299// 300//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 301 302// Attempts to allocate a block of size bytes from the debug heap. Returns null 303// on failure. 304static void* __cdecl heap_alloc_dbg_internal( 305 size_t const size, 306 int const block_use, 307 char const* const file_name, 308 int const line_number 309 ) throw() 310{ 311 void* block{nullptr}; 312 313 __acrt_lock(__acrt_heap_lock); 314 __try 315 { 316 validate_heap_if_required_nolock(); 317 318 long const request_number{__acrt_current_request_number}; 319 320 // Handle break-on-request and forced failure: 321 if (_crtBreakAlloc != -1 && request_number == _crtBreakAlloc) 322 { 323 _CrtDbgBreak(); 324 } 325 326 if (_pfnAllocHook && !_pfnAllocHook( 327 _HOOK_ALLOC, 328 nullptr, 329 size, 330 block_use, 331 request_number, 332 reinterpret_cast<unsigned char const*>(file_name), 333 line_number)) 334 { 335 if (file_name) 336 _RPTN(_CRT_WARN, "Client hook allocation failure at file %hs line %d.\n", file_name, line_number); 337 else 338 _RPT0(_CRT_WARN, "Client hook allocation failure.\n"); 339 340 __leave; 341 } 342 343#pragma warning(suppress:__WARNING_UNUSED_ASSIGNMENT) // 28931 344 bool const ignore_block{_BLOCK_TYPE(block_use) != _CRT_BLOCK && !(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF)}; 345 346 // Diagnostic memory allocation from this point on... 347 if (size > static_cast<size_t>(_HEAP_MAXREQ - no_mans_land_size - sizeof(_CrtMemBlockHeader))) 348 { 349 errno_t* const global_errno{_errno()}; 350 if (global_errno) 351 *global_errno = ENOMEM; 352 353 __leave; 354 } 355 356 if (!is_block_type_valid(block_use)) 357 { 358 _RPT0(_CRT_ERROR, "Error: memory allocation: bad memory block type.\n"); 359 } 360 361 size_t const block_size{sizeof(_CrtMemBlockHeader) + size + no_mans_land_size}; 362 363 _CrtMemBlockHeader* const header{static_cast<_CrtMemBlockHeader*>(HeapAlloc(__acrt_heap, 0, block_size))}; 364 if (!header) 365 { 366 errno_t* const global_errno{_errno()}; 367 if (global_errno) 368 *global_errno = ENOMEM; 369 370 __leave; 371 } 372 373 // Commit the allocation by linking the block into the global list: 374 ++__acrt_current_request_number; 375 376 if (ignore_block) 377 { 378 header->_block_header_next = nullptr; 379 header->_block_header_prev = nullptr; 380 header->_file_name = nullptr; 381 header->_line_number = line_number_for_ignore_blocks; 382 header->_data_size = size; 383 header->_block_use = _IGNORE_BLOCK; 384 header->_request_number = request_number_for_ignore_blocks; 385 } 386 else 387 { 388 // Keep track of total amount of memory allocated: 389 if (SIZE_MAX - __acrt_total_allocations > size) 390 { 391 __acrt_total_allocations += size; 392 } 393 else 394 { 395 __acrt_total_allocations = SIZE_MAX; 396 } 397 398 __acrt_current_allocations += size; 399 400 if (__acrt_current_allocations > __acrt_max_allocations) 401 __acrt_max_allocations = __acrt_current_allocations; 402 403 if (__acrt_first_block) 404 { 405 __acrt_first_block->_block_header_prev = header; 406 } 407 else 408 { 409 __acrt_last_block = header; 410 } 411 412 header->_block_header_next = __acrt_first_block; 413 header->_block_header_prev = nullptr; 414 header->_file_name = file_name; 415 header->_line_number = line_number; 416 header->_data_size = size; 417 header->_block_use = block_use; 418 header->_request_number = request_number; 419 420 __acrt_first_block = header; 421 } 422 423 // Fill the gap before and after the data block: 424 memset(header->_gap, no_mans_land_fill, no_mans_land_size); 425 memset(block_from_header(header) + size, no_mans_land_fill, no_mans_land_size); 426 427 // Fill the data block with a silly (but non-zero) value: 428 memset(block_from_header(header), clean_land_fill, size); 429 430 block = block_from_header(header); 431 } 432 __finally 433 { 434 __acrt_unlock(__acrt_heap_lock); 435 } 436 __endtry 437 438 return block; 439} 440 441 442 443// Allocates a block of size bytes from the debug heap, using the new handler if 444// it is configured for use with malloc. 445static void* __cdecl heap_alloc_dbg( 446 size_t const size, 447 int const block_use, 448 char const* const file_name, 449 int const line_number 450 ) throw() 451{ 452 bool const should_call_new_handler{_query_new_mode() != 0}; 453 for (;;) 454 { 455 void* const block{heap_alloc_dbg_internal(size, block_use, file_name, line_number)}; 456 if (block) 457 return block; 458 459 if (!should_call_new_handler || !_callnewh(size)) 460 { 461 errno_t* const global_errno{_errno()}; 462 if (global_errno) 463 *global_errno = ENOMEM; 464 465 return nullptr; 466 } 467 468 // The new handler was successful -- try to allocate again 469 } 470} 471 472 473 474//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 475// 476// Public Debug Heap Allocation APIs 477// 478//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 479 480// These are the allocation functions that allocate, manipulate, and free blocks 481// from the debug heap. They are equivalent to the main allocation functions, 482// which deal with blocks from the process heap. Most of the debug allocation 483// functions accept a block use, file name, and/or line number which are used to 484// track where allocations originated. 485// 486// Documentation comments for these functions describe only the material 487// differences between them and the corresponding main allocation functions. 488 489// This function must be marked noinline, otherwise malloc and 490// _malloc_dbg will have identical COMDATs, and the linker will fold 491// them when calling one from the CRT. This is necessary because malloc 492// needs to support users patching in custom implementations. 493extern "C" __declspec(noinline) void* __cdecl _malloc_dbg( 494 size_t const size, 495 int const block_use, 496 char const* const file_name, 497 int const line_number 498 ) 499{ 500 return heap_alloc_dbg(size, block_use, file_name, line_number); 501} 502 503 504// This function must be marked noinline, otherwise calloc and 505// _calloc_dbg will have identical COMDATs, and the linker will fold 506// them when calling one from the CRT. This is necessary because calloc 507// needs to support users patching in custom implementations. 508extern "C" __declspec(noinline) void* __cdecl _calloc_dbg( 509 size_t const count, 510 size_t const element_size, 511 int const block_use, 512 char const* const file_name, 513 int const line_number 514 ) 515{ 516 _VALIDATE_RETURN_NOEXC(count == 0 || (_HEAP_MAXREQ / count) >= element_size, ENOMEM, nullptr); 517 518 size_t const allocation_size{element_size * count}; 519 520 // Note that we zero exactly allocation_size bytes. The _calloc_base 521 // function for the main heap may zero more bytes if a larger block is 522 // allocated. 523 void* const block{heap_alloc_dbg(allocation_size, block_use, file_name, line_number)}; 524 if (block) 525 memset(block, 0, allocation_size); 526 527 return block; 528} 529 530 531 532// Common debug realloc implementation shared by _realloc_dbg, _recalloc_dbg, 533// and _expand_dbg. If reallocation_is_allowed is true, the expand behavior 534// is used; otherwise the realloc behavior is used. 535static void * __cdecl realloc_dbg_nolock( 536 void* const block, 537 size_t* const new_size, 538 int const block_use, 539 char const* const file_name, 540 int const line_number, 541 bool const reallocation_is_allowed 542 ) throw() 543{ 544 // realloc(nullptr, size) is equivalent to malloc(size): 545 if (!block) 546 { 547 return _malloc_dbg(*new_size, block_use, file_name, line_number); 548 } 549 550 // realloc(block, 0) is equivalent to free(block): 551 if (reallocation_is_allowed && *new_size == 0) 552 { 553 _free_dbg(block, block_use); 554 return nullptr; 555 } 556 557 validate_heap_if_required_nolock(); 558 559 // Handle break-on-request and forced failure: 560 long const request_number{__acrt_current_request_number}; 561 if (_crtBreakAlloc != -1 && request_number == _crtBreakAlloc) 562 { 563 _CrtDbgBreak(); 564 } 565 566 if (_pfnAllocHook && !_pfnAllocHook( 567 _HOOK_REALLOC, 568 block, 569 *new_size, 570 block_use, 571 request_number, 572 reinterpret_cast<unsigned char const*>(file_name), 573 line_number)) 574 { 575 if (file_name) 576 _RPTN(_CRT_WARN, "Client hook re-allocation failure at file %hs line %d.\n", file_name, line_number); 577 else 578 _RPT0(_CRT_WARN, "Client hook re-allocation failure.\n"); 579 580 return nullptr; 581 } 582 583 // Ensure the block type matches what is expected and isn't an aligned allocation: 584 if (block_use != _NORMAL_BLOCK && _BLOCK_TYPE(block_use) != _CLIENT_BLOCK && _BLOCK_TYPE(block_use) != _CRT_BLOCK) 585 { 586 if (file_name) 587 { 588 _RPTN(_CRT_ERROR, 589 "Error: memory allocation: bad memory block type.\n" _ALLOCATION_FILE_LINENUM, 590 file_name, line_number); 591 } 592 else 593 { 594 _RPT0(_CRT_ERROR, "Error: memory allocation: bad memory block type.\n"); 595 } 596 } 597 else if (is_block_an_aligned_allocation(block)) 598 { 599 // We don't know (yet) where (file, linenum) block was allocated 600 _RPTN(_CRT_ERROR, "The Block at 0x%p was allocated by aligned routines, use _aligned_realloc()", block); 601 errno = EINVAL; 602 603 return nullptr; 604 } 605 606 // If this assertion fails, a bad pointer has been passed in. It may be 607 // totally bogus, or it may have been allocated from another heap. The 608 // pointer must have been allocated from the debug heap. 609 _ASSERTE(_CrtIsValidHeapPointer(block)); 610 611 _CrtMemBlockHeader* const old_head{header_from_block(block)}; 612 613 bool const is_ignore_block{old_head->_block_use == _IGNORE_BLOCK}; 614 if (is_ignore_block) 615 { 616 _ASSERTE(old_head->_line_number == line_number_for_ignore_blocks && old_head->_request_number == request_number_for_ignore_blocks); 617 } 618 else if (__acrt_total_allocations < old_head->_data_size) 619 { 620 _RPTN(_CRT_ERROR, "Error: possible heap corruption at or near 0x%p", block); 621 errno = EINVAL; 622 return nullptr; 623 } 624 625 // Ensure the new requested size is not too large: 626 if (*new_size > static_cast<size_t>(_HEAP_MAXREQ - no_mans_land_size - sizeof(_CrtMemBlockHeader))) 627 { 628 errno = ENOMEM; 629 return nullptr; 630 } 631 632 // Note that all header values will remain valid and the minimum of the old 633 // size and the new size of data will remain valid. 634 size_t const new_internal_size{sizeof(_CrtMemBlockHeader) + *new_size + no_mans_land_size}; 635 636 _CrtMemBlockHeader* new_head{nullptr}; 637 if (reallocation_is_allowed) 638 { 639 new_head = static_cast<_CrtMemBlockHeader*>(_realloc_base(old_head, new_internal_size)); 640 if (!new_head) 641 return nullptr; 642 } 643 else 644 { 645 new_head = static_cast<_CrtMemBlockHeader*>(_expand_base(old_head, new_internal_size)); 646 if (!new_head) 647 return nullptr; 648 649 // On Win64, the heap does not try to resize the block if it is shrinking 650 // because of the use of the low-fragmentation heap. It just returns the 651 // original block. We make sure that our own header tracks that properly: 652 #ifdef _WIN64 653 *new_size = static_cast<size_t>(HeapSize(__acrt_heap, 0, new_head) 654 - sizeof(_CrtMemBlockHeader) 655 - no_mans_land_size); 656 #endif 657 } 658 659 _Analysis_assume_(new_head->_data_size == old_head->_data_size); 660 661 // Account for the current allocation and track the total amount of memory 662 // that is currently allocated: 663 ++__acrt_current_request_number; 664 if (!is_ignore_block) 665 { 666 if (__acrt_total_allocations < SIZE_MAX) 667 { 668 __acrt_total_allocations -= new_head->_data_size; 669 __acrt_total_allocations += SIZE_MAX - __acrt_total_allocations > *new_size 670 ? *new_size 671 : SIZE_MAX; 672 } 673 674 __acrt_current_allocations -= new_head->_data_size; 675 __acrt_current_allocations += *new_size; 676 677 if (__acrt_current_allocations > __acrt_max_allocations) 678 __acrt_max_allocations = __acrt_current_allocations; 679 } 680 681 unsigned char* const new_block{block_from_header(new_head)}; 682 683 // If the block grew, fill the "extension" with the land fill value: 684 if (*new_size > new_head->_data_size) 685 { 686 memset(new_block + new_head->_data_size, clean_land_fill, *new_size - new_head->_data_size); 687 } 688 689 // Fill in the gap after the client block: 690 memset(new_block + *new_size, no_mans_land_fill, no_mans_land_size); 691 692 if (!is_ignore_block) 693 { 694 new_head->_file_name = file_name; 695 new_head->_line_number = line_number; 696 new_head->_request_number = request_number; 697 } 698 699 new_head->_data_size = *new_size; 700 701 _ASSERTE(reallocation_is_allowed || (!reallocation_is_allowed && new_head == old_head)); 702 703 // If the block did not move or is ignored, we are done: 704 if (new_head == old_head || is_ignore_block) 705 return new_block; 706 707 // Swap out the old block from the linked list and link in the new block: 708 if (new_head->_block_header_next) 709 { 710 new_head->_block_header_next->_block_header_prev = new_head->_block_header_prev; 711 } 712 else 713 { 714 _ASSERTE(__acrt_last_block == old_head); 715 __acrt_last_block = new_head->_block_header_prev; 716 } 717 718 if (new_head->_block_header_prev) 719 { 720 new_head->_block_header_prev->_block_header_next = new_head->_block_header_next; 721 } 722 else 723 { 724 _ASSERTE(__acrt_first_block == old_head); 725 __acrt_first_block = new_head->_block_header_next; 726 } 727 728 if (__acrt_first_block) 729 { 730 __acrt_first_block->_block_header_prev = new_head; 731 } 732 else 733 { 734 __acrt_last_block = new_head; 735 } 736 737 new_head->_block_header_next = __acrt_first_block; 738 new_head->_block_header_prev = nullptr; 739 __acrt_first_block = new_head; 740 741 return new_block; 742} 743 744 745// This function must be marked noinline, otherwise realloc and 746// _realloc_dbg will have identical COMDATs, and the linker will fold 747// them when calling one from the CRT. This is necessary because realloc 748// needs to support users patching in custom implementations. 749extern "C" __declspec(noinline) void* __cdecl _realloc_dbg( 750 void* const block, 751 size_t const requested_size, 752 int const block_use, 753 char const* const file_name, 754 int const line_number 755 ) 756{ 757 void* new_block{nullptr}; 758 759 __acrt_lock(__acrt_heap_lock); 760 __try 761 { 762 size_t new_size{requested_size}; 763 new_block = realloc_dbg_nolock(block, &new_size, block_use, file_name, line_number, true); 764 } 765 __finally 766 { 767 __acrt_unlock(__acrt_heap_lock); 768 } 769 __endtry 770 771 return new_block; 772} 773 774 775// This function must be marked noinline, otherwise recalloc and 776// _recalloc_dbg will have identical COMDATs, and the linker will fold 777// them when calling one from the CRT. This is necessary because recalloc 778// needs to support users patching in custom implementations. 779extern "C" __declspec(noinline) void* __cdecl _recalloc_dbg( 780 void* const block, 781 size_t const count, 782 size_t const element_size, 783 int const block_use, 784 char const* const file_name, 785 int const line_number 786 ) 787{ 788 _VALIDATE_RETURN_NOEXC(count == 0 || (_HEAP_MAXREQ / count) >= element_size, ENOMEM, nullptr); 789 790 size_t const old_allocation_size{block ? _msize_dbg(block, block_use) : 0}; 791 size_t const new_allocation_size{element_size * count }; 792 793 void* const new_block{_realloc_dbg(block, new_allocation_size, block_use, file_name, line_number)}; 794 if (!new_block) 795 return nullptr; 796 797 // Zero the "expansion," if the block was expanded: 798 if (old_allocation_size < new_allocation_size) 799 { 800 memset( 801 static_cast<unsigned char*>(new_block) + old_allocation_size, 802 0, 803 new_allocation_size - old_allocation_size); 804 } 805 806 return new_block; 807} 808 809 810// This function must be marked noinline, otherwise _expand and 811// _expand_dbg will have identical COMDATs, and the linker will fold 812// them when calling one from the CRT. This is necessary because _expand 813// needs to support users patching in custom implementations. 814extern "C" __declspec(noinline) void* __cdecl _expand_dbg( 815 void* const block, 816 size_t const requested_size, 817 int const block_use, 818 char const* const file_name, 819 int const line_number 820 ) 821{ 822 _VALIDATE_RETURN(block != nullptr, EINVAL, nullptr); 823 824 if (requested_size > static_cast<size_t>(_HEAP_MAXREQ - no_mans_land_size - sizeof(_CrtMemBlockHeader))) 825 { 826 errno = ENOMEM; 827 return nullptr; 828 } 829 830 void* new_block{nullptr}; 831 832 __acrt_lock(__acrt_heap_lock); 833 __try 834 { 835 size_t new_size{requested_size}; 836 new_block = realloc_dbg_nolock(block, &new_size, block_use, file_name, line_number, false); 837 } 838 __finally 839 { 840 __acrt_unlock(__acrt_heap_lock); 841 } 842 __endtry 843 844 return new_block; 845} 846 847 848 849static void __cdecl free_dbg_nolock( 850 void* const block, 851 int const block_use 852 ) throw() 853{ 854 validate_heap_if_required_nolock(); 855 856 if (block == nullptr) 857 return; 858 859 #if _UCRT_HEAP_MISMATCH_DETECTION && (defined _M_IX86 || defined _M_AMD64) 860 861 if (!_CrtIsValidHeapPointer(block)) 862 { 863 HANDLE const msvcrt_heap_handle = __acrt_get_msvcrt_heap_handle(); 864 if (msvcrt_heap_handle) 865 { 866 if (HeapValidate(msvcrt_heap_handle, 0, block)) 867 { 868 _RPT1(_CRT_WARN, "CRTHEAP: ucrt: Attempt to free a pointer (0x%p) that belongs to MSVCRT's private heap, not the process heap.\n", block); 869 870 #if _UCRT_HEAP_MISMATCH_BREAK 871 _CrtDbgBreak(); 872 #endif // _UCRT_HEAP_MISMATCH_BREAK 873 874 #if _UCRT_HEAP_MISMATCH_RECOVERY 875 if (HeapFree(msvcrt_heap_handle, 0, block)) 876 { 877 _RPT1(_CRT_WARN, "CRTHEAP: ucrt: Successfully free'd 0x%p\n", block); 878 return; 879 } 880 else 881 { 882 _RPT1(_CRT_ERROR, "CRTHEAP: ucrt: Unable to free 0x%p\n", block); 883 _CrtDbgBreak(); // Force break. 884 } 885 #endif // _UCRT_HEAP_MISMATCH_RECOVERY 886 } 887 } 888 } 889 890 #endif // _UCRT_HEAP_MISMATCH_DETECTION && (defined _M_IX86 || defined _M_AMD64) 891 892 // Check to ensure that the block was not allocated by _aligned routines 893 if (block_use == _NORMAL_BLOCK && is_block_an_aligned_allocation(block)) 894 { 895 // We don't know (yet) where (file, linenum) block was allocated 896 _RPTN(_CRT_ERROR, "The Block at 0x%p was allocated by aligned routines, use _aligned_free()", block); 897 errno = EINVAL; 898 return; 899 } 900 901 // Forced failure handling 902 if (_pfnAllocHook && !_pfnAllocHook(_HOOK_FREE, block, 0, block_use, 0, nullptr, 0)) 903 { 904 _RPT0(_CRT_WARN, "Client hook free failure.\n"); 905 return; 906 } 907 908 // If this assertion fails, a bad pointer has been passed in. It may be 909 // totally bogus, or it may have been allocated from another heap. The 910 // pointer must have been allocated from the CRT heap. 911 _ASSERTE(_CrtIsValidHeapPointer(block)); 912 913 // Get a pointer to memory block header: 914 _CrtMemBlockHeader* const header = header_from_block(block); 915 _ASSERTE(is_block_type_valid(header->_block_use)); 916 917 // If we didn't already check entire heap, at least check this object by 918 // verifying that its no-man's land areas have not been trashed: 919 if (!(_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)) 920 { 921 if (!check_bytes(header->_gap, no_mans_land_fill, no_mans_land_size)) 922 { 923 if (header->_file_name) 924 { 925 _RPTN(_CRT_ERROR, "HEAP CORRUPTION DETECTED: before %hs block (#%d) at 0x%p.\n" 926 "CRT detected that the application wrote to memory before start of heap buffer.\n" 927 _ALLOCATION_FILE_LINENUM, 928 block_use_names[_BLOCK_TYPE(header->_block_use)], 929 header->_request_number, 930 block_from_header(header), 931 header->_file_name, 932 header->_line_number); 933 } 934 else 935 { 936 _RPTN(_CRT_ERROR, "HEAP CORRUPTION DETECTED: before %hs block (#%d) at 0x%p.\n" 937 "CRT detected that the application wrote to memory before start of heap buffer.\n", 938 block_use_names[_BLOCK_TYPE(header->_block_use)], 939 header->_request_number, 940 block_from_header(header)); 941 } 942 } 943 944 if (!check_bytes(block_from_header(header) + header->_data_size, no_mans_land_fill, no_mans_land_size)) 945 { 946 if (header->_file_name) 947 { 948 _RPTN(_CRT_ERROR, "HEAP CORRUPTION DETECTED: after %hs block (#%d) at 0x%p.\n" 949 "CRT detected that the application wrote to memory after end of heap buffer.\n" 950 _ALLOCATION_FILE_LINENUM, 951 block_use_names[_BLOCK_TYPE(header->_block_use)], 952 header->_request_number, 953 block_from_header(header), 954 header->_file_name, 955 header->_line_number); 956 } 957 else 958 { 959 _RPTN(_CRT_ERROR, "HEAP CORRUPTION DETECTED: after %hs block (#%d) at 0x%p.\n" 960 "CRT detected that the application wrote to memory after end of heap buffer.\n", 961 block_use_names[_BLOCK_TYPE(header->_block_use)], 962 header->_request_number, 963 block_from_header(header)); 964 } 965 } 966 } 967 968 // If this block was ignored when it was allocated, we can just free it: 969 if (header->_block_use == _IGNORE_BLOCK) 970 { 971 _ASSERTE(header->_line_number == line_number_for_ignore_blocks && header->_request_number == request_number_for_ignore_blocks); 972 memset(header, dead_land_fill, sizeof(_CrtMemBlockHeader) + header->_data_size + no_mans_land_size); 973 _free_base(header); 974 return; 975 } 976 977 // Ensure that we were called with the right block use. CRT blocks can be 978 // freed as NORMAL blocks. 979 _ASSERTE(header->_block_use == block_use || header->_block_use == _CRT_BLOCK && block_use == _NORMAL_BLOCK); 980 981 __acrt_current_allocations -= header->_data_size; 982 983 // Optionally reclaim memory: 984 if ((_crtDbgFlag & _CRTDBG_DELAY_FREE_MEM_DF) == 0) 985 { 986 // Unlink this allocation from the global linked list: 987 if (header->_block_header_next) 988 { 989 header->_block_header_next->_block_header_prev = header->_block_header_prev; 990 } 991 else 992 { 993 _ASSERTE(__acrt_last_block == header); 994 __acrt_last_block = header->_block_header_prev; 995 } 996 997 if (header->_block_header_prev) 998 { 999 header->_block_header_prev->_block_header_next = header->_block_header_next; 1000 } 1001 else 1002 { 1003 _ASSERTE(__acrt_first_block == header); 1004 __acrt_first_block = header->_block_header_next; 1005 } 1006 1007 memset(header, dead_land_fill, sizeof(_CrtMemBlockHeader) + header->_data_size + no_mans_land_size); 1008 _free_base(header); 1009 } 1010 else 1011 { 1012 header->_block_use = _FREE_BLOCK; 1013 1014 // Keep memory around as dead space: 1015 memset(block_from_header(header), dead_land_fill, header->_data_size); 1016 } 1017} 1018 1019 1020// This function must be marked noinline, otherwise free and 1021// _free_dbg will have identical COMDATs, and the linker will fold 1022// them when calling one from the CRT. This is necessary because free 1023// needs to support users patching in custom implementations. 1024extern "C" __declspec(noinline) void __cdecl _free_dbg(void* const block, int const block_use) 1025{ 1026 __acrt_lock(__acrt_heap_lock); 1027 __try 1028 { 1029 // If a block use was provided, use it; if the block use was not known, 1030 // use the block use stored in the header. (For example, the block use 1031 // is not known when this function is called by operator delete because 1032 // the heap lock must be acquired to access the block header.) 1033 int const actual_use{block_use == _UNKNOWN_BLOCK && block != nullptr 1034 ? header_from_block(block)->_block_use 1035 : block_use}; 1036 1037 free_dbg_nolock(block, actual_use); 1038 } 1039 __finally 1040 { 1041 __acrt_unlock(__acrt_heap_lock); 1042 } 1043 __endtry 1044} 1045 1046 1047// This function must be marked noinline, otherwise _msize and 1048// _msize_dbg will have identical COMDATs, and the linker will fold 1049// them when calling one from the CRT. This is necessary because _msize 1050// needs to support users patching in custom implementations. 1051extern "C" __declspec(noinline) size_t __cdecl _msize_dbg(void* const block, int const block_use) 1052{ 1053 UNREFERENCED_PARAMETER(block_use); 1054 1055 _VALIDATE_RETURN(block != nullptr, EINVAL, static_cast<size_t>(-1)); 1056 1057 size_t size{0}; 1058 1059 __acrt_lock(__acrt_heap_lock); 1060 __try 1061 { 1062 validate_heap_if_required_nolock(); 1063 1064 // If this assert fails, a bad pointer has been passed in. It may be 1065 // totally bogus, or it may have been allocated from another heap. The 1066 // pointer must have been allocated from the CRT heap. 1067 _ASSERTE(_CrtIsValidHeapPointer(block)); 1068 1069 _CrtMemBlockHeader* const header{header_from_block(block)}; 1070 1071 _ASSERTE(is_block_type_valid(header->_block_use)); 1072 1073 size = header->_data_size; 1074 } 1075 __finally 1076 { 1077 __acrt_unlock(__acrt_heap_lock); 1078 } 1079 __endtry 1080 1081 return size; 1082} 1083 1084 1085 1086//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1087// 1088// Public Debug Heap Control and Status APIs 1089// 1090//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1091 1092// Configures the CRT to break on allocation operation number new_break_alloc. 1093// Returns the previous break allocation value. 1094extern "C" long __cdecl _CrtSetBreakAlloc(long const new_break_alloc) 1095{ 1096 long const old_break_alloc{_crtBreakAlloc}; 1097 _crtBreakAlloc = new_break_alloc; 1098 return old_break_alloc; 1099} 1100 1101 1102 1103// Changes the block use for a block allocated on the debug heap. 1104extern "C" void __cdecl _CrtSetDbgBlockType( 1105 void* const block, 1106 int const block_use 1107 ) 1108{ 1109 __acrt_lock(__acrt_heap_lock); 1110 __try 1111 { 1112 if (!_CrtIsValidHeapPointer(block)) 1113 __leave; 1114 1115 _CrtMemBlockHeader* const header{header_from_block(block)}; 1116 1117 _ASSERTE(is_block_type_valid(header->_block_use)); 1118 1119 header->_block_use = block_use; 1120 } 1121 __finally 1122 { 1123 __acrt_unlock(__acrt_heap_lock); 1124 } 1125 __endtry 1126} 1127 1128 1129 1130// These get and set the allocation hook function, which is called for debug 1131// heap allocation operations. 1132extern "C" _CRT_ALLOC_HOOK __cdecl _CrtGetAllocHook() 1133{ 1134 return _pfnAllocHook; 1135} 1136 1137extern "C" _CRT_ALLOC_HOOK __cdecl _CrtSetAllocHook(_CRT_ALLOC_HOOK const new_hook) 1138{ 1139 _CRT_ALLOC_HOOK const old_hook{_pfnAllocHook}; 1140 _pfnAllocHook = new_hook; 1141 return old_hook; 1142} 1143 1144 1145 1146// Checks the integrity of the debug heap. Returns TRUE if the debug heap (and 1147// the underlying Windows heap) appears valid; returns FALSE and asserts if the 1148// heap appears corrupted or otherwise invalid. 1149static bool __cdecl check_block(_CrtMemBlockHeader* const header) throw() 1150{ 1151 bool this_block_okay{true}; 1152 char const* block_use{nullptr}; 1153 1154 if (is_block_type_valid(header->_block_use)) 1155 { 1156 block_use = block_use_names[_BLOCK_TYPE(header->_block_use)]; 1157 } 1158 else 1159 { 1160 block_use = "DAMAGED"; 1161 } 1162 1163 // Check the no-man's-land gaps: 1164 if (!check_bytes(header->_gap, no_mans_land_fill, no_mans_land_size)) 1165 { 1166 if (header->_file_name) 1167 { 1168 _RPTN(_CRT_WARN, "HEAP CORRUPTION DETECTED: before %hs block (#%d) at 0x%p.\n" 1169 "CRT detected that the application wrote to memory before start of heap buffer.\n" 1170 _ALLOCATION_FILE_LINENUM, 1171 block_use, 1172 header->_request_number, 1173 block_from_header(header), 1174 header->_file_name, 1175 header->_line_number); 1176 } 1177 else 1178 { 1179 _RPTN(_CRT_WARN, "HEAP CORRUPTION DETECTED: before %hs block (#%d) at 0x%p.\n" 1180 "CRT detected that the application wrote to memory before start of heap buffer.\n", 1181 block_use, header->_request_number, block_from_header(header)); 1182 } 1183 1184 this_block_okay = false; 1185 } 1186 1187 if (!check_bytes(block_from_header(header) + header->_data_size, no_mans_land_fill, no_mans_land_size)) 1188 { 1189 if (header->_file_name) 1190 { 1191 _RPTN(_CRT_WARN, "HEAP CORRUPTION DETECTED: after %hs block (#%d) at 0x%p.\n" 1192 "CRT detected that the application wrote to memory after end of heap buffer.\n" 1193 _ALLOCATION_FILE_LINENUM, 1194 block_use, 1195 header->_request_number, 1196 block_from_header(header), 1197 header->_file_name, 1198 header->_line_number); 1199 } 1200 else 1201 { 1202 _RPTN(_CRT_WARN, "HEAP CORRUPTION DETECTED: after %hs block (#%d) at 0x%p.\n" 1203 "CRT detected that the application wrote to memory after end of heap buffer.\n", 1204 block_use, header->_request_number, block_from_header(header)); 1205 } 1206 1207 this_block_okay = false; 1208 } 1209 1210 // Free blocks should remain undisturbed: 1211 if (header->_block_use == _FREE_BLOCK && !check_bytes(block_from_header(header), dead_land_fill, header->_data_size)) 1212 { 1213 if (header->_file_name) 1214 { 1215 _RPTN(_CRT_WARN, "HEAP CORRUPTION DETECTED: on top of Free block at 0x%p.\n" 1216 "CRT detected that the application wrote to a heap buffer that was freed.\n" 1217 _ALLOCATION_FILE_LINENUM, 1218 block_from_header(header), 1219 header->_file_name, 1220 header->_line_number); 1221 } 1222 else 1223 { 1224 _RPTN(_CRT_WARN, "HEAP CORRUPTION DETECTED: on top of Free block at 0x%p.\n" 1225 "CRT detected that the application wrote to a heap buffer that was freed.\n", 1226 block_from_header(header)); 1227 } 1228 1229 this_block_okay = false; 1230 } 1231 1232 if (!this_block_okay) 1233 { 1234 // Report statistics about the broken object: 1235 if (header->_file_name) 1236 { 1237 _RPTN(_CRT_WARN, 1238 "%hs located at 0x%p is %Iu bytes long.\n" 1239 _ALLOCATION_FILE_LINENUM, 1240 block_use, 1241 block_from_header(header), 1242 header->_data_size, 1243 header->_file_name, 1244 header->_line_number); 1245 } 1246 else 1247 { 1248 _RPTN(_CRT_WARN, "%hs located at 0x%p is %Iu bytes long.\n", 1249 block_use, block_from_header(header), header->_data_size); 1250 } 1251 } 1252 1253 return this_block_okay; 1254} 1255 1256extern "C" int __cdecl _CrtCheckMemory() 1257{ 1258 if ((_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF) == 0) 1259 { 1260 return TRUE; 1261 } 1262 1263 bool all_okay{true}; 1264 1265 __acrt_lock(__acrt_heap_lock); 1266 __try 1267 { 1268 // First walk our allocated heap blocks and verify consistency of our 1269 // internal data structures. We do this first because we can give 1270 // better diagnostics to client code than the underlying Windows heap 1271 // can (we have source file names and line numbers and other metadata). 1272 // We use Floyd's cycle finding algorithm to detect cycles in the block 1273 // list. 1274 _CrtMemBlockHeader* trail_it{__acrt_first_block}; 1275 _CrtMemBlockHeader* lead_it {__acrt_first_block == nullptr ? nullptr : __acrt_first_block->_block_header_next}; 1276 while (trail_it != nullptr) 1277 { 1278 all_okay &= check_block(trail_it); 1279 1280 if (trail_it == lead_it) 1281 { 1282 _RPTN(_CRT_WARN, 1283 "Cycle in block list detected while processing block located at 0x%p.\n", 1284 trail_it); 1285 all_okay = false; 1286 break; 1287 } 1288 1289 trail_it = trail_it->_block_header_next; 1290 1291 // Advance the lead iterator twice as fast as the trail iterator: 1292 if (lead_it != nullptr) 1293 { 1294 lead_it = lead_it->_block_header_next == nullptr 1295 ? nullptr 1296 : lead_it->_block_header_next->_block_header_next; 1297 } 1298 } 1299 1300 // Then check the underlying Windows heap: 1301 if (!HeapValidate(__acrt_heap, 0, nullptr)) 1302 { 1303 _RPT0(_CRT_WARN, "Heap validation failed.\n"); 1304 all_okay = false; 1305 __leave; 1306 } 1307 } 1308 __finally 1309 { 1310 __acrt_unlock(__acrt_heap_lock); 1311 } 1312 __endtry 1313 1314 return all_okay ? TRUE : FALSE; 1315} 1316 1317 1318 1319// Configures the debug heap behavior flags. Note that only the flags listed at 1320// the top of the function definition are valid; any other flags will cause the 1321// invalid parameter handler to be invoked. Returns the previous flag state. 1322extern "C" int __cdecl _CrtSetDbgFlag(int const new_bits) 1323{ 1324 int const valid_flags{ 1325 _CRTDBG_ALLOC_MEM_DF | 1326 _CRTDBG_DELAY_FREE_MEM_DF | 1327 _CRTDBG_CHECK_ALWAYS_DF | 1328 _CRTDBG_CHECK_CRT_DF | 1329 _CRTDBG_LEAK_CHECK_DF}; 1330 1331 bool const new_bits_have_only_valid_flags = (new_bits & 0xffff & ~valid_flags) == 0; 1332 _VALIDATE_RETURN(new_bits == _CRTDBG_REPORT_FLAG || new_bits_have_only_valid_flags, EINVAL, _crtDbgFlag); 1333 1334 int old_bits{0}; 1335 1336 __acrt_lock(__acrt_heap_lock); 1337 __try 1338 { 1339 old_bits = _crtDbgFlag; 1340 1341 if (new_bits == _CRTDBG_REPORT_FLAG) 1342 __leave; 1343 1344 if (new_bits & _CRTDBG_CHECK_ALWAYS_DF) 1345 __acrt_check_frequency = 1; 1346 else 1347 __acrt_check_frequency = (new_bits >> 16) & 0x0ffff; 1348 1349 __acrt_check_counter = 0; 1350 _crtDbgFlag = new_bits; 1351 } 1352 __finally 1353 { 1354 __acrt_unlock(__acrt_heap_lock); 1355 } 1356 __endtry 1357 1358 return old_bits; 1359} 1360 1361 1362 1363// Calls a caller-provided function for each client object in the heap. 1364extern "C" void __cdecl _CrtDoForAllClientObjects( 1365 _CrtDoForAllClientObjectsCallback const callback, 1366 void* const context 1367 ) 1368{ 1369 _VALIDATE_RETURN_VOID(callback != nullptr, EINVAL); 1370 1371 if ((_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF) == 0) 1372 return; 1373 1374 __acrt_lock(__acrt_heap_lock); 1375 __try 1376 { 1377 for (_CrtMemBlockHeader* header{__acrt_first_block}; header != nullptr; header = header->_block_header_next) 1378 { 1379 if (_BLOCK_TYPE(header->_block_use) == _CLIENT_BLOCK) 1380 callback(block_from_header(header), context); 1381 } 1382 } 1383 __finally 1384 { 1385 __acrt_unlock(__acrt_heap_lock); 1386 } 1387 __endtry 1388} 1389 1390 1391 1392// This function is provided for backwards compatibility only. It just tests 1393// whether the provided pointer is null. 1394extern "C" int __cdecl _CrtIsValidPointer( 1395 void const* const p, 1396 unsigned int const size_in_bytes, 1397 int const read_write 1398 ) 1399{ 1400 UNREFERENCED_PARAMETER(size_in_bytes); 1401 UNREFERENCED_PARAMETER(read_write); 1402 1403 return p != nullptr; 1404} 1405 1406 1407 1408// This function is provided for backwards compatibility only. It returns TRUE 1409// if the given block points to an allocation from the OS heap that underlies 1410// this CRT debug heap. Back when the CRT used its own OS heap (prior to Dev10), 1411// this function would thus also tell you whether the block was allocated by this 1412// debug heap. Now, it just tells you whether the block was allocated by some 1413// debug heap. 1414extern "C" int __cdecl _CrtIsValidHeapPointer(void const* const block) 1415{ 1416 if (!block) 1417 return FALSE; 1418 1419 return HeapValidate(__acrt_heap, 0, header_from_block(block)); 1420} 1421 1422 1423 1424// Verifies that the provided memory block is a block allocated by this debug 1425// heap. Returns TRUE if it is; FALSE otherwise. If the request_number, 1426// file_name, and line_number arguments are non-null, and if the block was 1427// allocated by this debug heap, this function fills in those argments with the 1428// actual values for the block. 1429extern "C" int __cdecl _CrtIsMemoryBlock( 1430 void const* const block, 1431 unsigned const size, 1432 long* const request_number, 1433 char** const file_name, 1434 int* const line_number 1435 ) 1436{ 1437 if (request_number) 1438 *request_number = 0; 1439 1440 if (file_name) 1441 *file_name = nullptr; 1442 1443 if (line_number) 1444 *line_number = 0; 1445 1446 if (!block) 1447 return FALSE; 1448 1449 int result{FALSE}; 1450 1451 __acrt_lock(__acrt_heap_lock); 1452 __try 1453 { 1454 _CrtMemBlockHeader* const header{header_from_block(block)}; 1455 if (!is_block_type_valid(header->_block_use)) 1456 __leave; 1457 1458 if (!_CrtIsValidPointer(block, size, TRUE)) 1459 __leave; 1460 1461 if (header->_data_size != size) 1462 __leave; 1463 1464 if (header->_request_number > __acrt_current_request_number) 1465 __leave; 1466 1467 // The block is valid 1468 if (request_number) 1469 *request_number = header->_request_number; 1470 1471 if (file_name) 1472 *file_name = const_cast<char*>(header->_file_name); 1473 1474 if (line_number) 1475 *line_number = header->_line_number; 1476 1477 result = TRUE; 1478 } 1479 __finally 1480 { 1481 __acrt_unlock(__acrt_heap_lock); 1482 } 1483 __endtry 1484 1485 return result; 1486} 1487 1488 1489 1490// Tests whether the block was allocated by this heap and, if it was, returns 1491// its block use. Returns -1 if this block was not allocated by this heap. 1492extern "C" int _CrtReportBlockType(void const* const block) 1493{ 1494 if (!_CrtIsValidHeapPointer(block)) 1495 return -1; 1496 1497 return header_from_block(block)->_block_use; 1498} 1499 1500 1501 1502// These get and set the active dump client, which is used when dumping the state 1503// of the debug heap. 1504extern "C" _CRT_DUMP_CLIENT __cdecl _CrtGetDumpClient() 1505{ 1506 return _pfnDumpClient; 1507} 1508 1509extern "C" _CRT_DUMP_CLIENT __cdecl _CrtSetDumpClient(_CRT_DUMP_CLIENT const new_client) 1510{ 1511 _CRT_DUMP_CLIENT const old_client{_pfnDumpClient}; 1512 _pfnDumpClient = new_client; 1513 return old_client; 1514} 1515 1516 1517 1518// Creates a checkpoint for the current state of the debug heap. Fills in the 1519// object pointed to by state; state must be non-null. 1520extern "C" void __cdecl _CrtMemCheckpoint(_CrtMemState* const state) 1521{ 1522 _VALIDATE_RETURN_VOID(state != nullptr, EINVAL); 1523 1524 __acrt_lock(__acrt_heap_lock); 1525 __try 1526 { 1527 state->pBlockHeader = __acrt_first_block; 1528 1529 for (unsigned use{0}; use < _MAX_BLOCKS; ++use) 1530 { 1531 state->lCounts[use] = 0; 1532 state->lSizes [use] = 0; 1533 } 1534 1535 for (_CrtMemBlockHeader* header{__acrt_first_block}; header != nullptr; header = header->_block_header_next) 1536 { 1537 if (_BLOCK_TYPE(header->_block_use) >= 0 && _BLOCK_TYPE(header->_block_use) < _MAX_BLOCKS) 1538 { 1539 ++state->lCounts[_BLOCK_TYPE(header->_block_use)]; 1540 state->lSizes[_BLOCK_TYPE(header->_block_use)] += header->_data_size; 1541 } 1542 else if (header->_file_name) 1543 { 1544 _RPTN(_CRT_WARN, "Bad memory block found at 0x%p.\n" _ALLOCATION_FILE_LINENUM, 1545 header, 1546 header->_file_name, 1547 header->_line_number); 1548 } 1549 else 1550 { 1551 _RPTN(_CRT_WARN, "Bad memory block found at 0x%p.\n", header); 1552 } 1553 } 1554 1555 state->lHighWaterCount = __acrt_max_allocations; 1556 state->lTotalCount = __acrt_total_allocations; 1557 } 1558 __finally 1559 { 1560 __acrt_unlock(__acrt_heap_lock); 1561 } 1562 __endtry 1563} 1564 1565 1566 1567// Computes the difference between two memory states. The difference between 1568// the old_state and new_state is stored in the object pointed to by state. 1569// Returns TRUE if there is a difference; FALSE otherwise. All three state 1570// pointers must be valid and non-null. 1571extern "C" int __cdecl _CrtMemDifference( 1572 _CrtMemState* const state, 1573 _CrtMemState const* const old_state, 1574 _CrtMemState const* const new_state 1575 ) 1576{ 1577 _VALIDATE_RETURN(state != nullptr, EINVAL, FALSE); 1578 _VALIDATE_RETURN(old_state != nullptr, EINVAL, FALSE); 1579 _VALIDATE_RETURN(new_state != nullptr, EINVAL, FALSE); 1580 1581 bool significant_difference_found{false}; 1582 for (int use{0}; use < _MAX_BLOCKS; ++use) 1583 { 1584 state->lSizes[use] = new_state->lSizes[use] - old_state->lSizes[use]; 1585 state->lCounts[use] = new_state->lCounts[use] - old_state->lCounts[use]; 1586 1587 if (state->lSizes[use] == 0 && state->lCounts[use] == 0) 1588 continue; 1589 1590 if (use == _FREE_BLOCK) 1591 continue; 1592 1593 if (use == _CRT_BLOCK && (_crtDbgFlag & _CRTDBG_CHECK_CRT_DF) == 0) 1594 continue; 1595 1596 significant_difference_found = true; 1597 } 1598 1599 state->lHighWaterCount = new_state->lHighWaterCount - old_state->lHighWaterCount; 1600 state->lTotalCount = new_state->lTotalCount - old_state->lTotalCount; 1601 state->pBlockHeader = nullptr; 1602 1603 return significant_difference_found ? 1 : 0; 1604} 1605 1606 1607 1608// Prints metadata for a block of memory. 1609static void __cdecl print_block_data( 1610 _locale_t const locale, 1611 _CrtMemBlockHeader* const header 1612 ) throw() 1613{ 1614 _LocaleUpdate locale_update{locale}; 1615 1616 static size_t const max_print = 16; 1617 1618 char print_buffer[max_print + 1]; 1619 char value_buffer[max_print * 3 + 1]; 1620 1621 size_t i{0}; 1622 for (; i < min(header->_data_size, max_print); ++i) 1623 { 1624 unsigned char const c{block_from_header(header)[i]}; 1625 1626 print_buffer[i] = _isprint_l(c, locale_update.GetLocaleT()) ? c : ' '; 1627 _ERRCHECK_SPRINTF(sprintf_s(value_buffer + i * 3, _countof(value_buffer) - (i * 3), "%.2X ", c)); 1628 } 1629 1630 print_buffer[i] = '\0'; 1631 _RPTN(_CRT_WARN, " Data: <%s> %s\n", print_buffer, value_buffer); 1632} 1633 1634// Prints metadata for all blocks allocated since the provided state was taken. 1635static void __cdecl dump_all_object_since_nolock(_CrtMemState const* const state) throw() 1636{ 1637 _LocaleUpdate locale_update{nullptr}; 1638 _locale_t locale{locale_update.GetLocaleT()}; 1639 1640 _RPT0(_CRT_WARN, "Dumping objects ->\n"); 1641 1642 _CrtMemBlockHeader* const stop_block{state ? state->pBlockHeader : nullptr}; 1643 1644 for (_CrtMemBlockHeader* header{__acrt_first_block}; header != nullptr && header != stop_block; header = header->_block_header_next) 1645 { 1646 if (_BLOCK_TYPE(header->_block_use) == _IGNORE_BLOCK) 1647 continue; 1648 1649 if (_BLOCK_TYPE(header->_block_use) == _FREE_BLOCK) 1650 continue; 1651 1652 if (_BLOCK_TYPE(header->_block_use) == _CRT_BLOCK && (_crtDbgFlag & _CRTDBG_CHECK_CRT_DF) == 0) 1653 continue; 1654 1655 if (header->_file_name != nullptr) 1656 { 1657 if (!_CrtIsValidPointer(header->_file_name, 1, FALSE) || is_bad_read_pointer(header->_file_name, 1)) 1658 { 1659 _RPTN(_CRT_WARN, "#File Error#(%d) : ", header->_line_number); 1660 } 1661 else 1662 { 1663 _RPTN(_CRT_WARN, "%hs(%d) : ", header->_file_name, header->_line_number); 1664 } 1665 } 1666 1667 _RPTN(_CRT_WARN, "{%ld} ", header->_request_number); 1668 1669 if (_BLOCK_TYPE(header->_block_use) == _CLIENT_BLOCK) 1670 { 1671 _RPTN(_CRT_WARN, "client block at 0x%p, subtype %x, %Iu bytes long.\n", 1672 block_from_header(header), 1673 _BLOCK_SUBTYPE(header->_block_use), 1674 header->_data_size); 1675 1676 if (_pfnDumpClient && !is_bad_read_pointer(block_from_header(header), header->_data_size)) 1677 { 1678 _pfnDumpClient(block_from_header(header), header->_data_size); 1679 } 1680 else 1681 { 1682 print_block_data(locale, header); 1683 } 1684 } 1685 else if (header->_block_use == _NORMAL_BLOCK) 1686 { 1687 _RPTN(_CRT_WARN, "normal block at 0x%p, %Iu bytes long.\n", 1688 block_from_header(header), 1689 header->_data_size); 1690 1691 print_block_data(locale, header); 1692 } 1693 else if (_BLOCK_TYPE(header->_block_use) == _CRT_BLOCK) 1694 { 1695 _RPTN(_CRT_WARN, "crt block at 0x%p, subtype %x, %Iu bytes long.\n", 1696 block_from_header(header), 1697 _BLOCK_SUBTYPE(header->_block_use), 1698 header->_data_size); 1699 1700 print_block_data(locale, header); 1701 } 1702 } 1703} 1704 1705// Prints metadata for all blocks allocated since the provided state was taken. 1706extern "C" void __cdecl _CrtMemDumpAllObjectsSince(_CrtMemState const* const state) 1707{ 1708 __acrt_lock(__acrt_heap_lock); 1709 __try 1710 { 1711 dump_all_object_since_nolock(state); 1712 } 1713 __finally 1714 { 1715 __acrt_unlock(__acrt_heap_lock); 1716 } 1717 __endtry 1718 1719 _RPT0(_CRT_WARN, "Object dump complete.\n"); 1720} 1721 1722 1723 1724// Dumps all currently active allocations in this heap. Returns TRUE if there 1725// are memory leaks; false otherwise. It is assumed that all client allocations 1726// remaining in the heap are memory leaks. 1727extern "C" int __cdecl _CrtDumpMemoryLeaks() 1728{ 1729 _CrtMemState state; 1730 _CrtMemCheckpoint(&state); 1731 1732 if (state.lCounts[_CLIENT_BLOCK] != 0 || 1733 state.lCounts[_NORMAL_BLOCK] != 0 || 1734 (_crtDbgFlag & _CRTDBG_CHECK_CRT_DF && state.lCounts[_CRT_BLOCK] != 0)) 1735 { 1736 _RPT0(_CRT_WARN, "Detected memory leaks!\n"); 1737 1738 _CrtMemDumpAllObjectsSince(nullptr); 1739 return TRUE; 1740 } 1741 1742 return FALSE; 1743} 1744 1745 1746 1747// Prints some brief information about the provided state of the heap. 1748extern "C" void __cdecl _CrtMemDumpStatistics(_CrtMemState const* const state) 1749{ 1750 _VALIDATE_RETURN_VOID(state != nullptr, EINVAL); 1751 1752 for (unsigned use{0}; use < _MAX_BLOCKS; ++use) 1753 { 1754 _RPTN(_CRT_WARN, "%Id bytes in %Id %hs Blocks.\n", 1755 state->lSizes[use], 1756 state->lCounts[use], 1757 block_use_names[use]); 1758 } 1759 1760 _RPTN(_CRT_WARN, "Largest number used: %Id bytes.\n", state->lHighWaterCount); 1761 _RPTN(_CRT_WARN, "Total allocations: %Id bytes.\n", state->lTotalCount); 1762} 1763 1764 1765 1766//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1767// 1768// Aligned Allocation 1769// 1770//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1771// These functions are equivalent to the normal aligned allocation functions in 1772// alignment.cpp, but these functions (suffixed with _dbg instead of _base) utilize 1773// the debug heap and accept the file name and line number as arguments. Consult 1774// alignment.cpp for more information on the behavior of these functions. 1775struct _AlignMemBlockHdr 1776{ 1777 void* _head; 1778 unsigned char _gap[align_gap_size]; 1779}; 1780 1781 1782 1783#define IS_2_POW_N(X) ((X) != 0 && ((X) & ((X) - 1)) == 0) 1784 1785 1786 1787extern "C" void* __cdecl _aligned_malloc_dbg( 1788 size_t const size, 1789 size_t const alignment, 1790 char const* const file_name, 1791 int const line_number 1792 ) 1793{ 1794 return _aligned_offset_malloc_dbg(size, alignment, 0, file_name, line_number); 1795} 1796 1797extern "C" void* __cdecl _aligned_offset_malloc_dbg( 1798 size_t const size, 1799 size_t alignment, 1800 size_t const offset, 1801 char const* const file_name, 1802 int const line_number 1803 ) 1804{ 1805 _VALIDATE_RETURN(IS_2_POW_N(alignment), EINVAL, nullptr); 1806 _VALIDATE_RETURN(offset == 0 || offset < size, EINVAL, nullptr); 1807 1808 alignment = (alignment > sizeof(uintptr_t) ? alignment : sizeof(uintptr_t)) - 1; 1809 1810 uintptr_t const t_ptr = (0 -offset) & (sizeof(uintptr_t) -1); 1811 1812 size_t const nonuser_size = t_ptr + alignment + sizeof(_AlignMemBlockHdr); // Cannot overflow 1813 size_t const block_size = size + nonuser_size; 1814 _VALIDATE_RETURN_NOEXC(size <= block_size, ENOMEM, nullptr); 1815 1816 uintptr_t const ptr = reinterpret_cast<uintptr_t>(_malloc_dbg(block_size, _NORMAL_BLOCK, file_name, line_number)); 1817 if (ptr == reinterpret_cast<uintptr_t>(nullptr)) 1818 return nullptr; 1819 1820 uintptr_t const r_ptr = ((ptr +nonuser_size +offset)&~alignment)-offset; 1821 _AlignMemBlockHdr* const header_from_block = reinterpret_cast<_AlignMemBlockHdr*>(r_ptr - t_ptr) - 1; 1822 memset(header_from_block->_gap, align_land_fill, align_gap_size); 1823 header_from_block->_head = reinterpret_cast<void*>(ptr); 1824 return reinterpret_cast<void*>(r_ptr); 1825} 1826 1827extern "C" void* __cdecl _aligned_realloc_dbg( 1828 void* const block, 1829 size_t const size, 1830 size_t const alignment, 1831 char const* const file_name, 1832 int const line_number 1833 ) 1834{ 1835 return _aligned_offset_realloc_dbg(block, size, alignment, 0, file_name, line_number); 1836} 1837 1838extern "C" void* __cdecl _aligned_recalloc_dbg( 1839 void* const block, 1840 size_t const count, 1841 size_t const size, 1842 size_t const alignment, 1843 char const* const file_name, 1844 int const line_number 1845 ) 1846{ 1847 return _aligned_offset_recalloc_dbg(block, count, size, alignment, 0, file_name, line_number); 1848} 1849 1850extern "C" void* __cdecl _aligned_offset_realloc_dbg( 1851 void * block, 1852 size_t size, 1853 size_t alignment, 1854 size_t offset, 1855 const char * file_name, 1856 int line_number 1857 ) 1858{ 1859 uintptr_t ptr, r_ptr, t_ptr, mov_sz; 1860 _AlignMemBlockHdr *header_from_block, *s_header_from_block; 1861 size_t nonuser_size, block_size; 1862 1863 if (block == nullptr) 1864 { 1865 return _aligned_offset_malloc_dbg(size, alignment, offset, file_name, line_number); 1866 } 1867 if (size == 0) 1868 { 1869 _aligned_free_dbg(block); 1870 return nullptr; 1871 } 1872 1873 s_header_from_block = (_AlignMemBlockHdr *)((uintptr_t)block & ~(sizeof(uintptr_t) -1)) -1; 1874 1875 if (check_bytes((unsigned char *)block -no_mans_land_size, no_mans_land_fill, no_mans_land_size)) 1876 { 1877 // We don't know where (file, linenum) block was allocated 1878 _RPTN(_CRT_ERROR, "The block at 0x%p was not allocated by _aligned routines, use realloc()", block); 1879 errno = EINVAL; 1880 return nullptr; 1881 } 1882 1883 if(!check_bytes(s_header_from_block->_gap, align_land_fill, align_gap_size)) 1884 { 1885 // We don't know where (file, linenum) block was allocated 1886 _RPTN(_CRT_ERROR, "Damage before 0x%p which was allocated by aligned routine\n", block); 1887 } 1888 1889 /* validation section */ 1890 _VALIDATE_RETURN(IS_2_POW_N(alignment), EINVAL, nullptr); 1891 _VALIDATE_RETURN(offset == 0 || offset < size, EINVAL, nullptr); 1892 1893 mov_sz = _msize_dbg(s_header_from_block->_head, _NORMAL_BLOCK) - ((uintptr_t)block - (uintptr_t)s_header_from_block->_head); 1894 1895 alignment = (alignment > sizeof(uintptr_t) ? alignment : sizeof(uintptr_t)) -1; 1896 1897 t_ptr = (0 -offset) & (sizeof(uintptr_t) - 1); 1898 1899 nonuser_size = t_ptr + alignment + sizeof(_AlignMemBlockHdr); // Cannot overflow 1900 block_size = size + nonuser_size; 1901 _VALIDATE_RETURN_NOEXC(size <= block_size, ENOMEM, nullptr); 1902 1903 if ((ptr = (uintptr_t)_malloc_dbg(block_size, _NORMAL_BLOCK, file_name, line_number)) == (uintptr_t)nullptr) 1904 return nullptr; 1905 1906 r_ptr = ((ptr + nonuser_size + offset) & ~alignment) - offset; 1907 header_from_block = (_AlignMemBlockHdr*)(r_ptr - t_ptr) - 1; 1908 memset(header_from_block->_gap, align_land_fill, align_gap_size); 1909 header_from_block->_head = reinterpret_cast<void*>(ptr); 1910 1911 memcpy(reinterpret_cast<void*>(r_ptr), block, mov_sz > size ? size : mov_sz); 1912 _free_dbg(s_header_from_block->_head, _NORMAL_BLOCK); 1913 1914 return (void *) r_ptr; 1915} 1916 1917extern "C" size_t __cdecl _aligned_msize_dbg( 1918 void* const block, 1919 size_t alignment, 1920 size_t const offset 1921 ) 1922{ 1923 size_t header_size = 0; // Size of the header block 1924 size_t footer_size = 0; // Size of the footer block 1925 size_t total_size = 0; // total size of the allocated block 1926 size_t user_size = 0; // size of the user block 1927 uintptr_t gap = 0; // keep the alignment of the data block 1928 // after the sizeof(void*) aligned pointer 1929 // to the beginning of the allocated block 1930 1931 // HEADER SIZE + FOOTER SIZE = GAP + ALIGN + SIZE OF A POINTER 1932 // HEADER SIZE + USER SIZE + FOOTER SIZE = TOTAL SIZE 1933 _VALIDATE_RETURN (block != nullptr, EINVAL, static_cast<size_t>(-1)); 1934 1935 _AlignMemBlockHdr* header_from_block = nullptr; // points to the beginning of the allocated block 1936 header_from_block = (_AlignMemBlockHdr*)((uintptr_t)block & ~(sizeof(uintptr_t) - 1)) - 1; 1937 total_size = _msize_dbg(header_from_block->_head, _NORMAL_BLOCK); 1938 header_size = (uintptr_t)block - (uintptr_t)header_from_block->_head; 1939 gap = (0 - offset) & (sizeof(uintptr_t) - 1); 1940 // The alignment cannot be smaller than the sizeof(uintptr_t) 1941 alignment = (alignment > sizeof(uintptr_t) ? alignment : sizeof(uintptr_t)) - 1; 1942 footer_size = gap + alignment + sizeof(_AlignMemBlockHdr) - header_size; 1943 user_size = total_size - header_size - footer_size; 1944 return user_size; 1945} 1946 1947extern "C" void* __cdecl _aligned_offset_recalloc_dbg( 1948 void* const block, 1949 size_t const count, 1950 size_t const element_size, 1951 size_t const alignment, 1952 size_t const offset, 1953 char const* const file_name, 1954 int const line_number 1955 ) 1956{ 1957 _VALIDATE_RETURN_NOEXC(count == 0 || _HEAP_MAXREQ / count >= element_size, ENOMEM, nullptr); 1958 1959 size_t const old_allocation_size{block ? _aligned_msize_dbg(block, alignment, offset) : 0}; 1960 size_t const new_allocation_size{element_size * count}; 1961 1962 void* const new_block{_aligned_offset_realloc_dbg(block, new_allocation_size, alignment, offset, file_name, line_number)}; 1963 if (!new_block) 1964 return nullptr; 1965 1966 if (old_allocation_size < new_allocation_size) 1967 memset(static_cast<unsigned char*>(new_block) + old_allocation_size, 0, new_allocation_size - old_allocation_size); 1968 1969 return new_block; 1970} 1971 1972extern "C" void __cdecl _aligned_free_dbg(void* const block) 1973{ 1974 if (!block) 1975 return; 1976 1977 _AlignMemBlockHdr* const header{reinterpret_cast<_AlignMemBlockHdr*>( 1978 reinterpret_cast<uintptr_t>(block) & ~(sizeof(uintptr_t) - 1) 1979 ) -1}; 1980 1981 if (check_bytes(static_cast<unsigned char*>(block) - no_mans_land_size, no_mans_land_fill, no_mans_land_size)) 1982 { 1983 // We don't know where (file, linenum) block was allocated 1984 _RPTN(_CRT_ERROR, "The block at 0x%p was not allocated by _aligned routines, use free()", block); 1985 return; 1986 } 1987 1988 if (!check_bytes(header->_gap, align_land_fill, align_gap_size)) 1989 { 1990 // We don't know where (file, linenum) block was allocated 1991 _RPTN(_CRT_ERROR, "Damage before 0x%p which was allocated by aligned routine\n", block); 1992 } 1993 1994 _free_dbg(header->_head, _NORMAL_BLOCK); 1995}