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