1 //
2 // calloc_base.cpp
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // Implementation of _calloc_base(). This is defined in a different source file
7 // from the calloc() function to allow calloc() to be replaced by the user.
8 //
9 #include <corecrt_internal.h>
10 #include <malloc.h>
11 #include <new.h>
12
13 // This function implements the logic of calloc().
14 //
15 // This function must be marked noinline, otherwise calloc and
16 // _calloc_base will have identical COMDATs, and the linker will fold
17 // them when calling one from the CRT. This is necessary because calloc
18 // needs to support users patching in custom implementations.
_calloc_base(size_t const count,size_t const size)19 extern "C" __declspec(noinline) _CRTRESTRICT void* __cdecl _calloc_base(
20 size_t const count,
21 size_t const size
22 )
23 {
24 // Ensure that (count * size) does not overflow
25 _VALIDATE_RETURN_NOEXC(count == 0 || (_HEAP_MAXREQ / count) >= size, ENOMEM, nullptr);
26
27 // Ensure that we allocate a nonzero block size:
28 size_t const requested_block_size = count * size;
29 size_t const actual_block_size = requested_block_size == 0
30 ? 1
31 : requested_block_size;
32
33 for (;;)
34 {
35 void* const block = HeapAlloc(__acrt_heap, HEAP_ZERO_MEMORY, actual_block_size);
36
37 // If allocation succeeded, return the pointer to the new block:
38 if (block)
39 {
40 return block;
41 }
42
43 // Otherwise, see if we need to call the new handler, and if so call it.
44 // If the new handler fails, just return nullptr:
45 if (_query_new_mode() == 0 || !_callnewh(actual_block_size))
46 {
47 errno = ENOMEM;
48 return nullptr;
49 }
50
51 // The new handler was successful; try to allocate aagain...
52 }
53 }
54