ReactOS 0.4.16-dev-974-g5022a45
debug_heap.cpp
Go to the documentation of this file.
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.
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.
84{
87 char const* _file_name;
89
91 size_t _data_size;
92
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(
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.
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};
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.
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" {
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{
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.
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 }
241 {
242 return true;
243 }
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
263{
264 if (__acrt_check_frequency == 0)
265 {
266 return;
267 }
268
270 {
272 return;
273 }
274
276 {
277 return;
278 }
279
281 __try
282 {
284 }
286 {
288 }
290
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.
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
314 __try
315 {
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
328 nullptr,
329 size,
330 block_use,
331 request_number,
332 reinterpret_cast<unsigned char const*>(file_name),
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
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
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:
375
376 if (ignore_block)
377 {
378 header->_block_header_next = nullptr;
379 header->_block_header_prev = nullptr;
380 header->_file_name = nullptr;
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:
390 {
392 }
393 else
394 {
396 }
397
399
402
404 {
406 }
407 else
408 {
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
421 }
422
423 // Fill the gap before and after the data block:
426
427 // Fill the data block with a silly (but non-zero) value:
429
431 }
433 {
435 }
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.
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 {
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.
494 size_t const size,
495 int const block_use,
496 char const* const file_name,
497 int const line_number
498 )
499{
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{
517
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.
524 if (block)
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.
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 {
548 }
549
550 // realloc(block, 0) is equivalent to free(block):
551 if (reallocation_is_allowed && *new_size == 0)
552 {
554 return nullptr;
555 }
556
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
568 block,
569 *new_size,
570 block_use,
571 request_number,
572 reinterpret_cast<unsigned char const*>(file_name),
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:
585 {
586 if (file_name)
587 {
589 "Error: memory allocation: bad memory block type.\n" _ALLOCATION_FILE_LINENUM,
591 }
592 else
593 {
594 _RPT0(_CRT_ERROR, "Error: memory allocation: bad memory block type.\n");
595 }
596 }
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.
610
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)
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:
664 if (!is_ignore_block)
665 {
667 {
668 __acrt_total_allocations -= new_head->_data_size;
670 ? *new_size
671 : SIZE_MAX;
672 }
673
674 __acrt_current_allocations -= new_head->_data_size;
676
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:
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);
716 }
717
718 if (new_head->_block_header_prev)
719 {
721 }
722 else
723 {
724 _ASSERTE(__acrt_first_block == old_head);
726 }
727
729 {
731 }
732 else
733 {
734 __acrt_last_block = new_head;
735 }
736
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
761 {
762 size_t new_size{requested_size};
764 }
766 {
768 }
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{
789
792
794 if (!new_block)
795 return nullptr;
796
797 // Zero the "expansion," if the block was expanded:
799 {
800 memset(
801 static_cast<unsigned char*>(new_block) + old_allocation_size,
802 0,
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
833 __try
834 {
835 size_t new_size{requested_size};
837 }
839 {
841 }
843
844 return new_block;
845}
846
847
848
850 void* const block,
851 int const block_use
852 ) throw()
853{
855
856 if (block == nullptr)
857 return;
858
859 #if _UCRT_HEAP_MISMATCH_DETECTION && (defined _M_IX86 || defined _M_AMD64)
860
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
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.
912
913 // Get a pointer to memory block header:
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:
920 {
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"
928 block_use_names[_BLOCK_TYPE(header->_block_use)],
929 header->_request_number,
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,
941 }
942 }
943
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"
951 block_use_names[_BLOCK_TYPE(header->_block_use)],
952 header->_request_number,
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,
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 {
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:
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 {
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 {
1004 __acrt_first_block = header->_block_header_next;
1005 }
1006
1009 }
1010 else
1011 {
1012 header->_block_use = _FREE_BLOCK;
1013
1014 // Keep memory around as dead space:
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{
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
1035 : block_use};
1036
1038 }
1039 __finally
1040 {
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{
1054
1055 _VALIDATE_RETURN(block != nullptr, EINVAL, static_cast<size_t>(-1));
1056
1057 size_t size{0};
1058
1060 __try
1061 {
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.
1068
1070
1072
1073 size = header->_data_size;
1074 }
1075 __finally
1076 {
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.
1105 void* const block,
1106 int const block_use
1107 )
1108{
1110 __try
1111 {
1113 __leave;
1114
1116
1117 _ASSERTE(is_block_type_valid(header->_block_use));
1118
1119 header->_block_use = block_use;
1120 }
1121 __finally
1122 {
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.
1133{
1134 return _pfnAllocHook;
1135}
1136
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.
1150{
1151 bool this_block_okay{true};
1152 char const* block_use{nullptr};
1153
1154 if (is_block_type_valid(header->_block_use))
1155 {
1157 }
1158 else
1159 {
1160 block_use = "DAMAGED";
1161 }
1162
1163 // Check the no-man's-land gaps:
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"
1171 block_use,
1172 header->_request_number,
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
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"
1194 block_use,
1195 header->_request_number,
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"
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",
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 {
1238 "%hs located at 0x%p is %Iu bytes long.\n"
1240 block_use,
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
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.
1276 while (trail_it != nullptr)
1277 {
1278 all_okay &= check_block(trail_it);
1279
1280 if (trail_it == lead_it)
1281 {
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 {
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{
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
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)
1346 else
1347 __acrt_check_frequency = (new_bits >> 16) & 0x0ffff;
1348
1350 _crtDbgFlag = new_bits;
1351 }
1352 __finally
1353 {
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.
1365 _CrtDoForAllClientObjectsCallback const callback,
1366 void* const context
1367 )
1368{
1370
1371 if ((_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF) == 0)
1372 return;
1373
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)
1381 }
1382 }
1383 __finally
1384 {
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.
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);
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
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.
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
1452 __try
1453 {
1455 if (!is_block_type_valid(header->_block_use))
1456 __leave;
1457
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 {
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{
1495 return -1;
1496
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.
1505{
1506 return _pfnDumpClient;
1507}
1508
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.
1521{
1522 _VALIDATE_RETURN_VOID(state != nullptr, EINVAL);
1523
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 {
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.
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.
1610 _locale_t const locale,
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.
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",
1673 _BLOCK_SUBTYPE(header->_block_use),
1674 header->_data_size);
1675
1677 {
1679 }
1680 else
1681 {
1683 }
1684 }
1685 else if (header->_block_use == _NORMAL_BLOCK)
1686 {
1687 _RPTN(_CRT_WARN, "normal block at 0x%p, %Iu bytes long.\n",
1689 header->_data_size);
1690
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",
1697 _BLOCK_SUBTYPE(header->_block_use),
1698 header->_data_size);
1699
1701 }
1702 }
1703}
1704
1705// Prints metadata for all blocks allocated since the provided state was taken.
1707{
1709 __try
1710 {
1712 }
1713 __finally
1714 {
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.
1728{
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
1739 return TRUE;
1740 }
1741
1742 return FALSE;
1743}
1744
1745
1746
1747// Prints some brief information about the provided state of the heap.
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.
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
1788 size_t const size,
1789 size_t const alignment,
1790 char const* const file_name,
1791 int const line_number
1792 )
1793{
1795}
1796
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{
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;
1815
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;
1823 header_from_block->_head = reinterpret_cast<void*>(ptr);
1824 return reinterpret_cast<void*>(r_ptr);
1825}
1826
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{
1836}
1837
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{
1848}
1849
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 {
1866 }
1867 if (size == 0)
1868 {
1870 return nullptr;
1871 }
1872
1873 s_header_from_block = (_AlignMemBlockHdr *)((uintptr_t)block & ~(sizeof(uintptr_t) -1)) -1;
1874
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 */
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;
1902
1904 return nullptr;
1905
1906 r_ptr = ((ptr + nonuser_size + offset) & ~alignment) - offset;
1907 header_from_block = (_AlignMemBlockHdr*)(r_ptr - t_ptr) - 1;
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
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{
1958
1960 size_t const new_allocation_size{element_size * count};
1961
1963 if (!new_block)
1964 return nullptr;
1965
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
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
1995}
#define EINVAL
Definition: acclib.h:90
#define ENOMEM
Definition: acclib.h:84
#define __cdecl
Definition: accygwin.h:79
_Check_return_ _Ret_maybenull_ _In_ size_t alignment
Definition: align.cpp:48
static int state
Definition: maze.c:121
Definition: _locale.h:75
void __cdecl __acrt_unlock(_In_ __acrt_lock_id lock)
Definition: locks.cpp:57
@ __acrt_heap_lock
#define _ERRCHECK_SPRINTF(_PrintfCall)
#define _VALIDATE_RETURN_VOID(expr, errorcode)
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
_ACRTIMP void __cdecl _free_base(_Pre_maybenull_ _Post_invalid_ void *_Block)
_Check_return_ _ACRTIMP int __cdecl _callnewh(_In_ size_t _Size)
#define _FREE_BLOCK
Definition: crtdbg.h:66
#define _free_dbg(p, t)
Definition: crtdbg.h:209
#define _CrtSetAllocHook(f)
Definition: crtdbg.h:243
#define _CrtMemDumpAllObjectsSince(s)
Definition: crtdbg.h:256
void(__cdecl * _CRT_DUMP_CLIENT)(void *, size_t)
Definition: crtdbg.h:73
#define _realloc_dbg(p, s, t, f, l)
Definition: crtdbg.h:206
#define _aligned_offset_malloc_dbg(s, a, o, f, l)
Definition: crtdbg.h:216
#define _CRTDBG_CHECK_ALWAYS_DF
Definition: crtdbg.h:50
#define _CrtIsValidHeapPointer(p)
Definition: crtdbg.h:249
#define _aligned_recalloc_dbg(p, c, s, a, f, l)
Definition: crtdbg.h:214
#define _ASSERTE(expr)
Definition: crtdbg.h:114
#define _CrtIsValidPointer(p, n, r)
Definition: crtdbg.h:248
#define _CRTDBG_CHECK_CRT_DF
Definition: crtdbg.h:52
#define _IGNORE_BLOCK
Definition: crtdbg.h:69
#define _CrtDoForAllClientObjects(f, c)
Definition: crtdbg.h:247
#define _CLIENT_BLOCK
Definition: crtdbg.h:70
#define _CRTDBG_LEAK_CHECK_DF
Definition: crtdbg.h:53
#define _CRTDBG_REPORT_FLAG
Definition: crtdbg.h:61
#define _malloc_dbg(s, t, f, l)
Definition: crtdbg.h:204
#define _aligned_offset_realloc_dbg(p, s, a, o, f, l)
Definition: crtdbg.h:217
#define _HOOK_FREE
Definition: crtdbg.h:44
#define _aligned_realloc_dbg(p, s, a, f, l)
Definition: crtdbg.h:213
#define _aligned_malloc_dbg(s, a, f, l)
Definition: crtdbg.h:212
#define _CRT_ERROR
Definition: crtdbg.h:21
#define _recalloc_dbg(p, c, s, t, f, l)
Definition: crtdbg.h:207
#define _CRT_WARN
Definition: crtdbg.h:20
#define _HOOK_ALLOC
Definition: crtdbg.h:42
#define _NORMAL_BLOCK
Definition: crtdbg.h:67
#define _CrtSetBreakAlloc(a)
Definition: crtdbg.h:242
#define _RPT0(rptno, msg)
Definition: crtdbg.h:118
#define _CRT_BLOCK
Definition: crtdbg.h:68
#define _CrtMemDifference(s1, s2, s3)
Definition: crtdbg.h:255
#define _calloc_dbg(c, s, t, f, l)
Definition: crtdbg.h:205
#define _aligned_free_dbg(p)
Definition: crtdbg.h:215
#define _MAX_BLOCKS
Definition: crtdbg.h:71
#define _CRTDBG_CHECK_DEFAULT_DF
Definition: crtdbg.h:59
#define _CrtDbgBreak()
Definition: crtdbg.h:103
#define _aligned_offset_recalloc_dbg(p, c, s, a, o, f, l)
Definition: crtdbg.h:218
#define _CrtSetDbgFlag(f)
Definition: crtdbg.h:246
#define _CrtSetDumpClient(f)
Definition: crtdbg.h:252
#define _HOOK_REALLOC
Definition: crtdbg.h:43
#define _BLOCK_SUBTYPE(block)
Definition: crtdbg.h:64
#define _expand_dbg(p, s, t, f, l)
Definition: crtdbg.h:208
#define _msize_dbg(p, t)
Definition: crtdbg.h:210
#define _RPT1
Definition: crtdbg.h:175
#define _CRTDBG_ALLOC_MEM_DF
Definition: crtdbg.h:48
#define _CRTDBG_DELAY_FREE_MEM_DF
Definition: crtdbg.h:49
int(__cdecl * _CRT_ALLOC_HOOK)(int, void *, size_t, int, long, const unsigned char *, int)
Definition: crtdbg.h:46
#define _CrtIsMemoryBlock(p, t, r, f, l)
Definition: crtdbg.h:250
#define _RPTN(rptno, msg,...)
Definition: crtdbg.h:119
#define _CrtMemDumpStatistics(s)
Definition: crtdbg.h:257
#define _CrtReportBlockType(p)
Definition: crtdbg.h:251
#define _BLOCK_TYPE(block)
Definition: crtdbg.h:63
#define _CrtMemCheckpoint(s)
Definition: crtdbg.h:254
#define _HEAP_MAXREQ
Definition: malloc.h:24
result_buffer_count char *const _In_ int const _In_ bool const _In_ unsigned const _In_ STRFLT const _In_ bool const _Inout_ __crt_cached_ptd_host &ptd throw()
Definition: cvt.cpp:119
static bool heap_validation_pending
Definition: debug_heap.cpp:260
int __cdecl _CrtCheckMemory()
static unsigned char const dead_land_fill
Definition: debug_heap.cpp:61
static size_t __acrt_current_allocations
Definition: debug_heap.cpp:122
static void __cdecl validate_heap_if_required_nolock()
Definition: debug_heap.cpp:262
#define _ALLOCATION_FILE_LINENUM
Definition: debug_heap.cpp:27
static unsigned __acrt_check_frequency
Definition: debug_heap.cpp:127
long _crtBreakAlloc
Definition: debug_heap.cpp:146
static _CrtMemBlockHeader * __acrt_last_block
Definition: debug_heap.cpp:115
static void *__cdecl realloc_dbg_nolock(void *const block, size_t *const new_size, int const block_use, char const *const file_name, int const line_number, bool const reallocation_is_allowed)
Definition: debug_heap.cpp:535
static long const request_number_for_ignore_blocks
Definition: debug_heap.cpp:69
size_t const old_allocation_size
Definition: debug_heap.cpp:790
static bool __cdecl is_bad_read_pointer(void const *const p, size_t const size)
Definition: debug_heap.cpp:206
static _CrtMemBlockHeader * __acrt_first_block
Definition: debug_heap.cpp:114
static void *__cdecl heap_alloc_dbg(size_t const size, int const block_use, char const *const file_name, int const line_number)
Definition: debug_heap.cpp:445
static bool __cdecl check_block(_CrtMemBlockHeader *const header)
size_t const allocation_size
Definition: debug_heap.cpp:518
int __cdecl _CrtDumpMemoryLeaks()
static long __acrt_current_request_number
Definition: debug_heap.cpp:132
_CrtMemBlockHeader *const header
__acrt_lock(__acrt_heap_lock)
int const char const *const file_name
Definition: debug_heap.cpp:496
static unsigned __acrt_check_counter
Definition: debug_heap.cpp:128
static void __cdecl free_dbg_nolock(void *const block, int const block_use)
Definition: debug_heap.cpp:849
size_t const requested_size
Definition: debug_heap.cpp:751
static bool __cdecl check_bytes(unsigned char const *const first, unsigned char const value, size_t const size)
Definition: debug_heap.cpp:187
static void *__cdecl heap_alloc_dbg_internal(size_t const size, int const block_use, char const *const file_name, int const line_number)
Definition: debug_heap.cpp:304
__try
Definition: debug_heap.cpp:761
int const block_use
Definition: debug_heap.cpp:495
_CRT_ALLOC_HOOK __cdecl _CrtGetAllocHook()
_CRT_DUMP_CLIENT _pfnDumpClient
Definition: debug_heap.cpp:147
__finally
Definition: debug_heap.cpp:766
int _crtDbgFlag
Definition: debug_heap.cpp:145
static size_t const align_gap_size
Definition: debug_heap.cpp:66
static char const *const block_use_names[_MAX_BLOCKS]
Definition: debug_heap.cpp:34
static bool __cdecl is_block_an_aligned_allocation(void const *const block)
Definition: debug_heap.cpp:249
static void __cdecl print_block_data(_locale_t const locale, _CrtMemBlockHeader *const header)
size_t size
static int const line_number_for_ignore_blocks
Definition: debug_heap.cpp:70
int const char const *const int const line_number
Definition: debug_heap.cpp:499
static _CrtMemBlockHeader *__cdecl header_from_block(void const *const block)
Definition: debug_heap.cpp:172
static unsigned char const align_land_fill
Definition: debug_heap.cpp:60
void __cdecl _CrtSetDbgBlockType(void *const block, int const block_use)
static unsigned char const clean_land_fill
Definition: debug_heap.cpp:62
static unsigned char const no_mans_land_fill
Definition: debug_heap.cpp:59
static size_t __acrt_total_allocations
Definition: debug_heap.cpp:121
static size_t const no_mans_land_size
Definition: debug_heap.cpp:65
size_t const new_allocation_size
Definition: debug_heap.cpp:791
size_t const element_size
Definition: debug_heap.cpp:510
static void __cdecl dump_all_object_since_nolock(_CrtMemState const *const state)
_CRT_DUMP_CLIENT __cdecl _CrtGetDumpClient()
static bool __cdecl is_block_type_valid(int const block_use)
Definition: debug_heap.cpp:177
long * __p__crtBreakAlloc()
Definition: debug_heap.cpp:155
new_block
Definition: debug_heap.cpp:763
static unsigned char *__cdecl block_from_header(_CrtMemBlockHeader *const header)
Definition: debug_heap.cpp:167
void *const block
Definition: debug_heap.cpp:523
int * __p__crtDbgFlag()
Definition: debug_heap.cpp:150
#define IS_2_POW_N(X)
static size_t __acrt_max_allocations
Definition: debug_heap.cpp:123
_CRT_ALLOC_HOOK _pfnAllocHook
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
VOID WINAPI GetSystemInfo(IN LPSYSTEM_INFO lpSystemInfo)
Definition: sysinfo.c:143
#define noinline
Definition: types.h:64
return nullptr
Definition: expand.cpp:78
size_t const new_size
Definition: expand.cpp:66
unsigned long DWORD
Definition: ntddk_ex.h:95
void __declspec(noinline) __cdecl _free_base(void *const block)
Definition: free_base.cpp:98
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
const GLubyte * c
Definition: glext.h:8905
GLenum GLint GLuint mask
Definition: glext.h:6028
const GLint * first
Definition: glext.h:5794
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
HANDLE __acrt_heap
Definition: heap_handle.cpp:15
BOOL WINAPI HeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
Definition: heapmem.c:156
#define _isprint_l(_Char, _Locale)
Definition: ctype.h:651
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define _VALIDATE_RETURN_NOEXC(expr, errorcode, retexpr)
static DWORD block_size(DWORD block)
Definition: jsutils.c:66
#define c
Definition: ke_i.h:80
unsigned int uintptr_t
Definition: intrin.h:47
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static PVOID ptr
Definition: dispmode.c:27
static const struct @1680 read_write[]
static IPrintDialogCallback callback
Definition: printdlg.c:326
static UINT UINT last
Definition: font.c:45
static DWORD page_size
Definition: loader.c:53
#define min(a, b)
Definition: monoChain.cc:55
#define _Analysis_assume_
Definition: no_sal2.h:388
#define MEMORY_ALLOCATION_ALIGNMENT
Definition: ntbasedef.h:90
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
#define __leave
Definition: pseh2_64.h:192
#define __except
Definition: pseh2_64.h:189
#define __endtry
Definition: pseh2_64.h:191
_CRTIMP int *__cdecl _errno(void)
Definition: errno.c:17
#define errno
Definition: errno.h:18
#define SIZE_MAX
Definition: compat.h:66
#define memset(x, y, z)
Definition: compat.h:39
#define _countof(array)
Definition: sndvol32.h:70
unsigned char _gap[align_gap_size]
unsigned char _gap[no_mans_land_size]
Definition: debug_heap.cpp:94
_CrtMemBlockHeader * _block_header_next
Definition: debug_heap.cpp:85
char const * _file_name
Definition: debug_heap.cpp:87
_CrtMemBlockHeader * _block_header_prev
Definition: debug_heap.cpp:86
size_t lHighWaterCount
Definition: crtdbg.h:81
size_t lTotalCount
Definition: crtdbg.h:82
size_t lCounts[_MAX_BLOCKS]
Definition: crtdbg.h:79
size_t lSizes[_MAX_BLOCKS]
Definition: crtdbg.h:80
Definition: http.c:7252
int errno_t
Definition: corecrt.h:615
#define _aligned_msize_dbg(p, a, o)
Definition: crtdbg.h:260
#define _UNKNOWN_BLOCK
Definition: crtdbg.h:111
_ACRTIMP int __cdecl _query_new_mode(void)
Definition: heap.c:217
Definition: pdh_main.c:96
SIZE_T WINAPI HeapSize(HANDLE, DWORD, LPCVOID)
#define const
Definition: zconf.h:233