Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * fe_memutils.c
4 : : * memory management support for frontend code
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/common/fe_memutils.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : :
16 : : #ifndef FRONTEND
17 : : #error "This file is not expected to be compiled for backend code"
18 : : #endif
19 : :
20 : : #include "postgres_fe.h"
21 : :
22 : : #include "common/int.h"
23 : :
24 : : pg_noreturn static pg_noinline void add_size_error(Size s1, Size s2);
25 : : pg_noreturn static pg_noinline void mul_size_error(Size s1, Size s2);
26 : :
27 : :
28 : : static inline void *
4075 fujii@postgresql.org 29 :CBC 5170262 : pg_malloc_internal(size_t size, int flags)
30 : : {
31 : : void *tmp;
32 : :
33 : : /* Avoid unportable behavior of malloc(0) */
4855 alvherre@alvh.no-ip. 34 [ + + ]: 5170262 : if (size == 0)
35 : 4493 : size = 1;
36 : 5170262 : tmp = malloc(size);
4075 fujii@postgresql.org 37 [ - + ]: 5170262 : if (tmp == NULL)
38 : : {
4075 fujii@postgresql.org 39 [ # # ]:UBC 0 : if ((flags & MCXT_ALLOC_NO_OOM) == 0)
40 : : {
41 : 0 : fprintf(stderr, _("out of memory\n"));
42 : 0 : exit(EXIT_FAILURE);
43 : : }
44 : 0 : return NULL;
45 : : }
46 : :
4075 fujii@postgresql.org 47 [ + + ]:CBC 5170262 : if ((flags & MCXT_ALLOC_ZERO) != 0)
48 [ + - + + : 6522633 : MemSet(tmp, 0, size);
+ - + + +
+ ]
4855 alvherre@alvh.no-ip. 49 : 5170262 : return tmp;
50 : : }
51 : :
52 : : void *
4075 fujii@postgresql.org 53 : 2259532 : pg_malloc(size_t size)
54 : : {
55 : 2259532 : return pg_malloc_internal(size, 0);
56 : : }
57 : :
58 : : void *
4855 alvherre@alvh.no-ip. 59 : 1679294 : pg_malloc0(size_t size)
60 : : {
4075 fujii@postgresql.org 61 : 1679294 : return pg_malloc_internal(size, MCXT_ALLOC_ZERO);
62 : : }
63 : :
64 : : void *
65 : 77100 : pg_malloc_extended(size_t size, int flags)
66 : : {
67 : 77100 : return pg_malloc_internal(size, flags);
68 : : }
69 : :
70 : : void *
4855 alvherre@alvh.no-ip. 71 : 96181 : pg_realloc(void *ptr, size_t size)
72 : : {
73 : : void *tmp;
74 : :
75 : : /* Avoid unportable behavior of realloc(NULL, 0) */
4749 bruce@momjian.us 76 [ + + - + ]: 96181 : if (ptr == NULL && size == 0)
4749 bruce@momjian.us 77 :UBC 0 : size = 1;
4749 bruce@momjian.us 78 :CBC 96181 : tmp = realloc(ptr, size);
79 [ - + ]: 96181 : if (!tmp)
80 : : {
4855 alvherre@alvh.no-ip. 81 :UBC 0 : fprintf(stderr, _("out of memory\n"));
82 : 0 : exit(EXIT_FAILURE);
83 : : }
4749 bruce@momjian.us 84 :CBC 96181 : return tmp;
85 : : }
86 : :
87 : : /*
88 : : * "Safe" wrapper around strdup().
89 : : */
90 : : char *
4855 alvherre@alvh.no-ip. 91 : 8897514 : pg_strdup(const char *in)
92 : : {
93 : : char *tmp;
94 : :
95 [ - + ]: 8897514 : if (!in)
96 : : {
4855 alvherre@alvh.no-ip. 97 :UBC 0 : fprintf(stderr,
98 : 0 : _("cannot duplicate null pointer (internal error)\n"));
99 : 0 : exit(EXIT_FAILURE);
100 : : }
4855 alvherre@alvh.no-ip. 101 :CBC 8897514 : tmp = strdup(in);
102 [ - + ]: 8897514 : if (!tmp)
103 : : {
4855 alvherre@alvh.no-ip. 104 :UBC 0 : fprintf(stderr, _("out of memory\n"));
105 : 0 : exit(EXIT_FAILURE);
106 : : }
4855 alvherre@alvh.no-ip. 107 :CBC 8897514 : return tmp;
108 : : }
109 : :
110 : : void
111 : 5623472 : pg_free(void *ptr)
112 : : {
1444 peter@eisentraut.org 113 : 5623472 : free(ptr);
4855 alvherre@alvh.no-ip. 114 : 5623472 : }
115 : :
116 : : /*
117 : : * Frontend emulation of backend memory management functions. Useful for
118 : : * programs that compile backend files.
119 : : */
120 : : void *
121 : 1150659 : palloc(Size size)
122 : : {
4075 fujii@postgresql.org 123 : 1150659 : return pg_malloc_internal(size, 0);
124 : : }
125 : :
126 : : void *
4855 alvherre@alvh.no-ip. 127 : 3161 : palloc0(Size size)
128 : : {
4075 fujii@postgresql.org 129 : 3161 : return pg_malloc_internal(size, MCXT_ALLOC_ZERO);
130 : : }
131 : :
132 : : void *
133 : 516 : palloc_extended(Size size, int flags)
134 : : {
135 : 516 : return pg_malloc_internal(size, flags);
136 : : }
137 : :
138 : : void
4855 alvherre@alvh.no-ip. 139 : 2753621 : pfree(void *pointer)
140 : : {
141 : 2753621 : pg_free(pointer);
142 : 2753621 : }
143 : :
144 : : char *
145 : 1325639 : pstrdup(const char *in)
146 : : {
147 : 1325639 : return pg_strdup(in);
148 : : }
149 : :
150 : : char *
2369 151 : 331 : pnstrdup(const char *in, Size size)
152 : : {
153 : : char *tmp;
154 : : int len;
155 : :
156 [ - + ]: 331 : if (!in)
157 : : {
2369 alvherre@alvh.no-ip. 158 :UBC 0 : fprintf(stderr,
159 : 0 : _("cannot duplicate null pointer (internal error)\n"));
160 : 0 : exit(EXIT_FAILURE);
161 : : }
162 : :
2369 alvherre@alvh.no-ip. 163 :CBC 331 : len = strnlen(in, size);
164 : 331 : tmp = malloc(len + 1);
165 [ - + ]: 331 : if (tmp == NULL)
166 : : {
2369 alvherre@alvh.no-ip. 167 :UBC 0 : fprintf(stderr, _("out of memory\n"));
168 : 0 : exit(EXIT_FAILURE);
169 : : }
170 : :
2369 alvherre@alvh.no-ip. 171 :CBC 331 : memcpy(tmp, in, len);
172 : 331 : tmp[len] = '\0';
173 : :
174 : 331 : return tmp;
175 : : }
176 : :
177 : : void *
4855 178 : 59037 : repalloc(void *pointer, Size size)
179 : : {
180 : 59037 : return pg_realloc(pointer, size);
181 : : }
182 : :
183 : : /*
184 : : * Support for safe calculation of memory request sizes
185 : : *
186 : : * These functions perform the requested calculation, but throw error if the
187 : : * result overflows.
188 : : *
189 : : * An important property of these functions is that if an argument was a
190 : : * negative signed int before promotion (implying overflow in calculating it)
191 : : * we will detect that as an error. That happens because we reject results
192 : : * larger than SIZE_MAX / 2. In the backend we rely on later checks to do
193 : : * that, but in frontend we must do it here.
194 : : */
195 : : Size
19 tgl@sss.pgh.pa.us 196 :UBC 0 : add_size(Size s1, Size s2)
197 : : {
198 : : Size result;
199 : :
200 [ # # # # : 0 : if (unlikely(pg_add_size_overflow(s1, s2, &result) ||
# # ]
201 : : result > (SIZE_MAX / 2)))
202 : 0 : add_size_error(s1, s2);
203 : 0 : return result;
204 : : }
205 : :
206 : : pg_noreturn static pg_noinline void
207 : 0 : add_size_error(Size s1, Size s2)
208 : : {
209 : 0 : fprintf(stderr, _("invalid memory allocation request size %zu + %zu\n"),
210 : : s1, s2);
211 : 0 : exit(EXIT_FAILURE);
212 : : }
213 : :
214 : : Size
215 : 0 : mul_size(Size s1, Size s2)
216 : : {
217 : : Size result;
218 : :
219 [ # # # # : 0 : if (unlikely(pg_mul_size_overflow(s1, s2, &result) ||
# # ]
220 : : result > (SIZE_MAX / 2)))
221 : 0 : mul_size_error(s1, s2);
222 : 0 : return result;
223 : : }
224 : :
225 : : pg_noreturn static pg_noinline void
226 : 0 : mul_size_error(Size s1, Size s2)
227 : : {
228 : 0 : fprintf(stderr, _("invalid memory allocation request size %zu * %zu\n"),
229 : : s1, s2);
230 : 0 : exit(EXIT_FAILURE);
231 : : }
232 : :
233 : : /*
234 : : * pg_malloc_mul
235 : : * Equivalent to pg_malloc(mul_size(s1, s2)).
236 : : */
237 : : void *
19 tgl@sss.pgh.pa.us 238 :CBC 1270613 : pg_malloc_mul(Size s1, Size s2)
239 : : {
240 : : /* inline mul_size() for efficiency */
241 : : Size req;
242 : :
243 [ + - - + : 1270613 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
- + ]
244 : : req > (SIZE_MAX / 2)))
19 tgl@sss.pgh.pa.us 245 :UBC 0 : mul_size_error(s1, s2);
19 tgl@sss.pgh.pa.us 246 :CBC 1270613 : return pg_malloc(req);
247 : : }
248 : :
249 : : /*
250 : : * pg_malloc0_mul
251 : : * Equivalent to pg_malloc0(mul_size(s1, s2)).
252 : : *
253 : : * This is comparable to standard calloc's behavior.
254 : : */
255 : : void *
19 tgl@sss.pgh.pa.us 256 :GBC 1550284 : pg_malloc0_mul(Size s1, Size s2)
257 : : {
258 : : /* inline mul_size() for efficiency */
259 : : Size req;
260 : :
261 [ + - - + : 1550284 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
- + ]
262 : : req > (SIZE_MAX / 2)))
19 tgl@sss.pgh.pa.us 263 :UBC 0 : mul_size_error(s1, s2);
19 tgl@sss.pgh.pa.us 264 :GBC 1550284 : return pg_malloc0(req);
265 : : }
266 : :
267 : : /*
268 : : * pg_malloc_mul_extended
269 : : * Equivalent to pg_malloc_extended(mul_size(s1, s2), flags).
270 : : */
271 : : void *
19 tgl@sss.pgh.pa.us 272 :UBC 0 : pg_malloc_mul_extended(Size s1, Size s2, int flags)
273 : : {
274 : : /* inline mul_size() for efficiency */
275 : : Size req;
276 : :
277 [ # # # # : 0 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
# # ]
278 : : req > (SIZE_MAX / 2)))
279 : 0 : mul_size_error(s1, s2);
280 : 0 : return pg_malloc_extended(req, flags);
281 : : }
282 : :
283 : : /*
284 : : * pg_realloc_mul
285 : : * Equivalent to pg_realloc(p, mul_size(s1, s2)).
286 : : */
287 : : void *
19 tgl@sss.pgh.pa.us 288 :CBC 35770 : pg_realloc_mul(void *p, Size s1, Size s2)
289 : : {
290 : : /* inline mul_size() for efficiency */
291 : : Size req;
292 : :
293 [ + - - + : 35770 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
- + ]
294 : : req > (SIZE_MAX / 2)))
19 tgl@sss.pgh.pa.us 295 :UBC 0 : mul_size_error(s1, s2);
19 tgl@sss.pgh.pa.us 296 :CBC 35770 : return pg_realloc(p, req);
297 : : }
298 : :
299 : : /*
300 : : * palloc_mul
301 : : * Equivalent to palloc(mul_size(s1, s2)).
302 : : */
303 : : void *
304 : 3739 : palloc_mul(Size s1, Size s2)
305 : : {
306 : : /* inline mul_size() for efficiency */
307 : : Size req;
308 : :
309 [ + - - + : 3739 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
- + ]
310 : : req > (SIZE_MAX / 2)))
19 tgl@sss.pgh.pa.us 311 :UBC 0 : mul_size_error(s1, s2);
19 tgl@sss.pgh.pa.us 312 :CBC 3739 : return palloc(req);
313 : : }
314 : :
315 : : /*
316 : : * palloc0_mul
317 : : * Equivalent to palloc0(mul_size(s1, s2)).
318 : : *
319 : : * This is comparable to standard calloc's behavior.
320 : : */
321 : : void *
19 tgl@sss.pgh.pa.us 322 :UBC 0 : palloc0_mul(Size s1, Size s2)
323 : : {
324 : : /* inline mul_size() for efficiency */
325 : : Size req;
326 : :
327 [ # # # # : 0 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
# # ]
328 : : req > (SIZE_MAX / 2)))
329 : 0 : mul_size_error(s1, s2);
330 : 0 : return palloc0(req);
331 : : }
332 : :
333 : : /*
334 : : * palloc_mul_extended
335 : : * Equivalent to palloc_extended(mul_size(s1, s2), flags).
336 : : */
337 : : void *
338 : 0 : palloc_mul_extended(Size s1, Size s2, int flags)
339 : : {
340 : : /* inline mul_size() for efficiency */
341 : : Size req;
342 : :
343 [ # # # # : 0 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
# # ]
344 : : req > (SIZE_MAX / 2)))
345 : 0 : mul_size_error(s1, s2);
346 : 0 : return palloc_extended(req, flags);
347 : : }
348 : :
349 : : /*
350 : : * repalloc_mul
351 : : * Equivalent to repalloc(p, mul_size(s1, s2)).
352 : : */
353 : : void *
354 : 0 : repalloc_mul(void *p, Size s1, Size s2)
355 : : {
356 : : /* inline mul_size() for efficiency */
357 : : Size req;
358 : :
359 [ # # # # : 0 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
# # ]
360 : : req > (SIZE_MAX / 2)))
361 : 0 : mul_size_error(s1, s2);
362 : 0 : return repalloc(p, req);
363 : : }
|