xref: /reactos/sdk/lib/ucrt/heap/calloc_base.cpp (revision 04e0dc4a)
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