xref: /reactos/sdk/lib/ucrt/heap/debug_heap.cpp (revision e98e9000)
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 
33 static 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.
59 static unsigned char const no_mans_land_fill{0xFD}; // Fill unaligned no-man's land
60 static unsigned char const align_land_fill  {0xED}; // Fill aligned no-man's land
61 static unsigned char const dead_land_fill   {0xDD}; // Fill free objects with this
62 static 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:
65 static size_t const no_mans_land_size = 4;
66 static size_t const align_gap_size    = sizeof(void *);
67 
68 // For _IGNORE_BLOCK blocks, we use these request and line numbers as sentinels.
69 static long const request_number_for_ignore_blocks{0};
70 static 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.
83 struct _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 
101 static_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.
114 static _CrtMemBlockHeader* __acrt_first_block{nullptr};
115 static _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.
121 static size_t __acrt_total_allocations  {0};
122 static size_t __acrt_current_allocations{0};
123 static size_t __acrt_max_allocations    {0};
124 
125 // These states control the frequency with which _CrtCheckMemory.  The units are
126 // "calls to allocation functions."
127 static unsigned __acrt_check_frequency{0};
128 static 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.
132 static 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 
144 extern "C" {
145     int              _crtDbgFlag{_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_DEFAULT_DF};
146     long             _crtBreakAlloc{-1};
147     _CRT_DUMP_CLIENT _pfnDumpClient{nullptr};
148 }
149 
__p__crtDbgFlag()150 extern "C" int* __p__crtDbgFlag()
151 {
152     return &_crtDbgFlag;
153 }
154 
__p__crtBreakAlloc()155 extern "C" long* __p__crtBreakAlloc()
156 {
157     return &_crtBreakAlloc;
158 }
159 
160 
161 
162 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163 //
164 // Internal Utilities
165 //
166 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
block_from_header(_CrtMemBlockHeader * const header)167 static unsigned char* __cdecl block_from_header(_CrtMemBlockHeader* const header) throw()
168 {
169     return reinterpret_cast<unsigned char*>(header + 1);
170 }
171 
header_from_block(void const * const block)172 static _CrtMemBlockHeader* __cdecl header_from_block(void const* const block) throw()
173 {
174     return static_cast<_CrtMemBlockHeader*>(const_cast<void*>(block)) - 1;
175 }
176 
is_block_type_valid(int const block_use)177 static 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.
check_bytes(unsigned char const * const first,unsigned char const value,size_t const size)187 static 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.
is_bad_read_pointer(void const * const p,size_t const size)206 static 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 
is_block_an_aligned_allocation(void const * const block)249 static 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.
260 static bool heap_validation_pending{false};
261 
validate_heap_if_required_nolock()262 static 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.
heap_alloc_dbg_internal(size_t const size,int const block_use,char const * const file_name,int const line_number)304 static 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.
heap_alloc_dbg(size_t const size,int const block_use,char const * const file_name,int const line_number)445 static 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.
_malloc_dbg(size_t const size,int const block_use,char const * const file_name,int const line_number)493 extern "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.
_calloc_dbg(size_t const count,size_t const element_size,int const block_use,char const * const file_name,int const line_number)508 extern "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.
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)535 static 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.
_realloc_dbg(void * const block,size_t const requested_size,int const block_use,char const * const file_name,int const line_number)749 extern "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.
_recalloc_dbg(void * const block,size_t const count,size_t const element_size,int const block_use,char const * const file_name,int const line_number)779 extern "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.
_expand_dbg(void * const block,size_t const requested_size,int const block_use,char const * const file_name,int const line_number)814 extern "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 
free_dbg_nolock(void * const block,int const block_use)849 static 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.
_free_dbg(void * const block,int const block_use)1024 extern "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.
_msize_dbg(void * const block,int const block_use)1051 extern "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.
_CrtSetBreakAlloc(long const new_break_alloc)1094 extern "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.
_CrtSetDbgBlockType(void * const block,int const block_use)1104 extern "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.
_CrtGetAllocHook()1132 extern "C" _CRT_ALLOC_HOOK __cdecl _CrtGetAllocHook()
1133 {
1134     return _pfnAllocHook;
1135 }
1136 
_CrtSetAllocHook(_CRT_ALLOC_HOOK const new_hook)1137 extern "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.
check_block(_CrtMemBlockHeader * const header)1149 static 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 
_CrtCheckMemory()1256 extern "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.
_CrtSetDbgFlag(int const new_bits)1322 extern "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.
_CrtDoForAllClientObjects(_CrtDoForAllClientObjectsCallback const callback,void * const context)1364 extern "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.
_CrtIsValidPointer(void const * const p,unsigned int const size_in_bytes,int const read_write)1394 extern "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.
_CrtIsValidHeapPointer(void const * const block)1414 extern "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.
_CrtIsMemoryBlock(void const * const block,unsigned const size,long * const request_number,char ** const file_name,int * const line_number)1429 extern "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.
_CrtReportBlockType(void const * const block)1492 extern "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.
_CrtGetDumpClient()1504 extern "C" _CRT_DUMP_CLIENT __cdecl _CrtGetDumpClient()
1505 {
1506     return _pfnDumpClient;
1507 }
1508 
_CrtSetDumpClient(_CRT_DUMP_CLIENT const new_client)1509 extern "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.
_CrtMemCheckpoint(_CrtMemState * const state)1520 extern "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.
_CrtMemDifference(_CrtMemState * const state,_CrtMemState const * const old_state,_CrtMemState const * const new_state)1571 extern "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.
print_block_data(_locale_t const locale,_CrtMemBlockHeader * const header)1609 static 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.
dump_all_object_since_nolock(_CrtMemState const * const state)1635 static 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.
_CrtMemDumpAllObjectsSince(_CrtMemState const * const state)1706 extern "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.
_CrtDumpMemoryLeaks()1727 extern "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.
_CrtMemDumpStatistics(_CrtMemState const * const state)1748 extern "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.
1775 struct _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 
_aligned_malloc_dbg(size_t const size,size_t const alignment,char const * const file_name,int const line_number)1787 extern "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 
_aligned_offset_malloc_dbg(size_t const size,size_t alignment,size_t const offset,char const * const file_name,int const line_number)1797 extern "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 
_aligned_realloc_dbg(void * const block,size_t const size,size_t const alignment,char const * const file_name,int const line_number)1827 extern "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 
_aligned_recalloc_dbg(void * const block,size_t const count,size_t const size,size_t const alignment,char const * const file_name,int const line_number)1838 extern "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 
_aligned_offset_realloc_dbg(void * block,size_t size,size_t alignment,size_t offset,const char * file_name,int line_number)1850 extern "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 
_aligned_msize_dbg(void * const block,size_t alignment,size_t const offset)1917 extern "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 
_aligned_offset_recalloc_dbg(void * const block,size_t const count,size_t const element_size,size_t const alignment,size_t const offset,char const * const file_name,int const line_number)1947 extern "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 
_aligned_free_dbg(void * const block)1972 extern "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 }
1996