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