1 /*
2 * Copyright 2015-2026 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10 #ifndef PCMK__INCLUDED_CRM_COMMON_INTERNAL_H
11 #error "Include <crm/common/internal.h> instead of <memory_internal.h> directly"
12 #endif
13
14 #ifndef PCMK__CRM_COMMON_MEMORY_INTERNAL__H
15 #define PCMK__CRM_COMMON_MEMORY_INTERNAL__H
16
17 #include <stddef.h> // size_t
18 #include <stdint.h> // uint32_t
19 #include <stdlib.h> // abort, calloc, free, realloc
20
21 #include <glib.h> // FALSE, TRUE
22
23 #include <crm/common/results.h> // CRM_EX_OSERR, crm_abort, crm_exit
24 #include <crm/common/results_internal.h> // pcmk__assert
25
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29
30 /*!
31 * \internal
32 * \brief Abort without dumping core if a pointer is \c NULL
33 *
34 * This is intended to check for memory allocation failure, rather than for null
35 * pointers in general.
36 *
37 * \param[in] ptr Pointer to check
38 */
39 #define pcmk__mem_assert(ptr) do { \
40 if ((ptr) == NULL) { \
41 crm_abort(__FILE__, __func__, __LINE__, "Out of memory", FALSE, \
42 TRUE); \
43 crm_exit(CRM_EX_OSERR); \
44 } \
45 } while (0)
46
47 /*!
48 * \internal
49 * \brief Allocate new zero-initialized memory, asserting on failure
50 *
51 * \param[in] file File where \p function is located
52 * \param[in] function Calling function
53 * \param[in] line Line within \p file
54 * \param[in] nmemb Number of elements to allocate memory for
55 * \param[in] size Size of each element
56 *
57 * \return Newly allocated memory of of size <tt>nmemb * size</tt> (guaranteed
58 * not to be \c NULL)
59 *
60 * \note The caller is responsible for freeing the return value using \c free().
61 */
62 static inline void *
63 pcmk__assert_alloc_as(const char *file, const char *function, uint32_t line,
64 size_t nmemb, size_t size)
65 {
|
(1) Event alloc_fn: |
Storage is returned from allocation function "calloc". |
|
(2) Event assign: |
Assigning: "ptr" = "calloc(nmemb, size)". |
| Also see events: |
[return_alloc] |
66 void *ptr = calloc(nmemb, size);
67
|
(3) Event path: |
Condition "ptr == NULL", taking false branch. |
68 if (ptr == NULL) {
69 crm_abort(file, function, line, "Out of memory", FALSE, TRUE);
70 crm_exit(CRM_EX_OSERR);
71 }
|
(4) Event return_alloc: |
Returning allocated memory "ptr". |
| Also see events: |
[alloc_fn][assign] |
72 return ptr;
73 }
74
75 /*!
76 * \internal
77 * \brief Allocate new zero-initialized memory, asserting on failure
78 *
79 * \param[in] nmemb Number of elements to allocate memory for
80 * \param[in] size Size of each element
81 *
82 * \return Newly allocated memory of of size <tt>nmemb * size</tt> (guaranteed
83 * not to be \c NULL)
84 *
85 * \note The caller is responsible for freeing the return value using \c free().
86 */
87 #define pcmk__assert_alloc(nmemb, size) \
88 pcmk__assert_alloc_as(__FILE__, __func__, __LINE__, nmemb, size)
89
90 /*!
91 * \internal
92 * \brief Resize a dynamically allocated memory block
93 *
94 * \param[in] ptr Memory block to resize (or NULL to allocate new memory)
95 * \param[in] size New size of memory block in bytes (must be > 0)
96 *
97 * \return Pointer to resized memory block
98 *
99 * \note This asserts on error, so the result is guaranteed to be non-NULL
100 * (which is the main advantage of this over directly using realloc()).
101 */
102 static inline void *
103 pcmk__realloc(void *ptr, size_t size)
104 {
105 void *new_ptr;
106
107 // realloc(p, 0) can replace free(p) but this wrapper can't
108 pcmk__assert(size > 0);
109
110 new_ptr = realloc(ptr, size);
111 if (new_ptr == NULL) {
112 free(ptr);
113 abort();
114 }
115 return new_ptr;
116 }
117
118 #ifdef __cplusplus
119 }
120 #endif
121
122 #endif // PCMK__CRM_COMMON_MEMORY_INTERNAL__H
123