Branch data 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 *
29 : 4692034 : pg_malloc_internal(size_t size, int flags)
30 : : {
31 : : void *tmp;
32 : :
33 : : /* Avoid unportable behavior of malloc(0) */
34 [ + + ]: 4692034 : if (size == 0)
35 : 3437 : size = 1;
36 : 4692034 : tmp = malloc(size);
37 [ - + ]: 4692034 : if (tmp == NULL)
38 : : {
39 [ # # ]: 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 : :
47 [ + + ]: 4692034 : if ((flags & MCXT_ALLOC_ZERO) != 0)
48 [ + - + + : 6477839 : MemSet(tmp, 0, size);
+ - + + +
+ ]
49 : 4692034 : return tmp;
50 : : }
51 : :
52 : : void *
53 : 2170646 : pg_malloc(size_t size)
54 : : {
55 : 2170646 : return pg_malloc_internal(size, 0);
56 : : }
57 : :
58 : : void *
59 : 1697745 : pg_malloc0(size_t size)
60 : : {
61 : 1697745 : return pg_malloc_internal(size, MCXT_ALLOC_ZERO);
62 : : }
63 : :
64 : : void *
65 : 244909 : pg_malloc_extended(size_t size, int flags)
66 : : {
67 : 244909 : return pg_malloc_internal(size, flags);
68 : : }
69 : :
70 : : void *
71 : 94279 : pg_realloc(void *ptr, size_t size)
72 : : {
73 : : void *tmp;
74 : :
75 : : /* Avoid unportable behavior of realloc(NULL, 0) */
76 [ + + - + ]: 94279 : if (ptr == NULL && size == 0)
77 : 0 : size = 1;
78 : 94279 : tmp = realloc(ptr, size);
79 [ - + ]: 94279 : if (!tmp)
80 : : {
81 : 0 : fprintf(stderr, _("out of memory\n"));
82 : 0 : exit(EXIT_FAILURE);
83 : : }
84 : 94279 : return tmp;
85 : : }
86 : :
87 : : /*
88 : : * "Safe" wrapper around strdup().
89 : : */
90 : : char *
91 : 8106852 : pg_strdup(const char *in)
92 : : {
93 : : char *tmp;
94 : :
95 [ - + ]: 8106852 : if (!in)
96 : : {
97 : 0 : fprintf(stderr,
98 : 0 : _("cannot duplicate null pointer (internal error)\n"));
99 : 0 : exit(EXIT_FAILURE);
100 : : }
101 : 8106852 : tmp = strdup(in);
102 [ - + ]: 8106852 : if (!tmp)
103 : : {
104 : 0 : fprintf(stderr, _("out of memory\n"));
105 : 0 : exit(EXIT_FAILURE);
106 : : }
107 : 8106852 : return tmp;
108 : : }
109 : :
110 : : void
111 : 7758689 : pg_free(void *ptr)
112 : : {
113 : 7758689 : free(ptr);
114 : 7758689 : }
115 : :
116 : : /*
117 : : * Frontend emulation of backend memory management functions. Useful for
118 : : * programs that compile backend files.
119 : : */
120 : : void *
121 : 575023 : palloc(Size size)
122 : : {
123 : 575023 : return pg_malloc_internal(size, 0);
124 : : }
125 : :
126 : : void *
127 : 3192 : palloc0(Size size)
128 : : {
129 : 3192 : return pg_malloc_internal(size, MCXT_ALLOC_ZERO);
130 : : }
131 : :
132 : : void *
133 : 519 : palloc_extended(Size size, int flags)
134 : : {
135 : 519 : return pg_malloc_internal(size, flags);
136 : : }
137 : :
138 : : void
139 : 2103318 : pfree(void *pointer)
140 : : {
141 : 2103318 : pg_free(pointer);
142 : 2103318 : }
143 : :
144 : : char *
145 : 1243689 : pstrdup(const char *in)
146 : : {
147 : 1243689 : return pg_strdup(in);
148 : : }
149 : :
150 : : char *
151 : 314 : pnstrdup(const char *in, Size size)
152 : : {
153 : : char *tmp;
154 : :
155 [ - + ]: 314 : if (!in)
156 : : {
157 : 0 : fprintf(stderr,
158 : 0 : _("cannot duplicate null pointer (internal error)\n"));
159 : 0 : exit(EXIT_FAILURE);
160 : : }
161 : :
162 : 314 : size = strnlen(in, size);
163 : 314 : tmp = malloc(size + 1);
164 [ - + ]: 314 : if (tmp == NULL)
165 : : {
166 : 0 : fprintf(stderr, _("out of memory\n"));
167 : 0 : exit(EXIT_FAILURE);
168 : : }
169 : :
170 : 314 : memcpy(tmp, in, size);
171 : 314 : tmp[size] = '\0';
172 : :
173 : 314 : return tmp;
174 : : }
175 : :
176 : : void *
177 : 59102 : repalloc(void *pointer, Size size)
178 : : {
179 : 59102 : return pg_realloc(pointer, size);
180 : : }
181 : :
182 : : /*
183 : : * Support for safe calculation of memory request sizes
184 : : *
185 : : * These functions perform the requested calculation, but throw error if the
186 : : * result overflows.
187 : : *
188 : : * An important property of these functions is that if an argument was a
189 : : * negative signed int before promotion (implying overflow in calculating it)
190 : : * we will detect that as an error. That happens because we reject results
191 : : * larger than SIZE_MAX / 2. In the backend we rely on later checks to do
192 : : * that, but in frontend we must do it here.
193 : : */
194 : : Size
195 : 113 : add_size(Size s1, Size s2)
196 : : {
197 : : Size result;
198 : :
199 [ + - - + : 113 : if (unlikely(pg_add_size_overflow(s1, s2, &result) ||
- + ]
200 : : result > (SIZE_MAX / 2)))
201 : 0 : add_size_error(s1, s2);
202 : 113 : return result;
203 : : }
204 : :
205 : : pg_noreturn static pg_noinline void
206 : 0 : add_size_error(Size s1, Size s2)
207 : : {
208 : 0 : fprintf(stderr, _("invalid memory allocation request size %zu + %zu\n"),
209 : : s1, s2);
210 : 0 : exit(EXIT_FAILURE);
211 : : }
212 : :
213 : : Size
214 : 113 : mul_size(Size s1, Size s2)
215 : : {
216 : : Size result;
217 : :
218 [ + - - + : 113 : if (unlikely(pg_mul_size_overflow(s1, s2, &result) ||
- + ]
219 : : result > (SIZE_MAX / 2)))
220 : 0 : mul_size_error(s1, s2);
221 : 113 : return result;
222 : : }
223 : :
224 : : pg_noreturn static pg_noinline void
225 : 0 : mul_size_error(Size s1, Size s2)
226 : : {
227 : 0 : fprintf(stderr, _("invalid memory allocation request size %zu * %zu\n"),
228 : : s1, s2);
229 : 0 : exit(EXIT_FAILURE);
230 : : }
231 : :
232 : : /*
233 : : * pg_malloc_mul
234 : : * Equivalent to pg_malloc(mul_size(s1, s2)).
235 : : */
236 : : void *
237 : 1184850 : pg_malloc_mul(Size s1, Size s2)
238 : : {
239 : : /* inline mul_size() for efficiency */
240 : : Size req;
241 : :
242 [ + - - + : 1184850 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
- + ]
243 : : req > (SIZE_MAX / 2)))
244 : 0 : mul_size_error(s1, s2);
245 : 1184850 : return pg_malloc(req);
246 : : }
247 : :
248 : : /*
249 : : * pg_malloc0_mul
250 : : * Equivalent to pg_malloc0(mul_size(s1, s2)).
251 : : *
252 : : * This is comparable to standard calloc's behavior.
253 : : */
254 : : void *
255 : 1570324 : pg_malloc0_mul(Size s1, Size s2)
256 : : {
257 : : /* inline mul_size() for efficiency */
258 : : Size req;
259 : :
260 [ + - - + : 1570324 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
- + ]
261 : : req > (SIZE_MAX / 2)))
262 : 0 : mul_size_error(s1, s2);
263 : 1570324 : return pg_malloc0(req);
264 : : }
265 : :
266 : : /*
267 : : * pg_malloc_mul_extended
268 : : * Equivalent to pg_malloc_extended(mul_size(s1, s2), flags).
269 : : */
270 : : void *
271 : 0 : pg_malloc_mul_extended(Size s1, Size s2, int flags)
272 : : {
273 : : /* inline mul_size() for efficiency */
274 : : Size req;
275 : :
276 [ # # # # : 0 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
# # ]
277 : : req > (SIZE_MAX / 2)))
278 : 0 : mul_size_error(s1, s2);
279 : 0 : return pg_malloc_extended(req, flags);
280 : : }
281 : :
282 : : /*
283 : : * pg_realloc_mul
284 : : * Equivalent to pg_realloc(p, mul_size(s1, s2)).
285 : : */
286 : : void *
287 : 33803 : pg_realloc_mul(void *p, Size s1, Size s2)
288 : : {
289 : : /* inline mul_size() for efficiency */
290 : : Size req;
291 : :
292 [ + - - + : 33803 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
- + ]
293 : : req > (SIZE_MAX / 2)))
294 : 0 : mul_size_error(s1, s2);
295 : 33803 : return pg_realloc(p, req);
296 : : }
297 : :
298 : : /*
299 : : * palloc_mul
300 : : * Equivalent to palloc(mul_size(s1, s2)).
301 : : */
302 : : void *
303 : 4625 : palloc_mul(Size s1, Size s2)
304 : : {
305 : : /* inline mul_size() for efficiency */
306 : : Size req;
307 : :
308 [ + - - + : 4625 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
- + ]
309 : : req > (SIZE_MAX / 2)))
310 : 0 : mul_size_error(s1, s2);
311 : 4625 : return palloc(req);
312 : : }
313 : :
314 : : /*
315 : : * palloc0_mul
316 : : * Equivalent to palloc0(mul_size(s1, s2)).
317 : : *
318 : : * This is comparable to standard calloc's behavior.
319 : : */
320 : : void *
321 : 0 : palloc0_mul(Size s1, Size s2)
322 : : {
323 : : /* inline mul_size() for efficiency */
324 : : Size req;
325 : :
326 [ # # # # : 0 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
# # ]
327 : : req > (SIZE_MAX / 2)))
328 : 0 : mul_size_error(s1, s2);
329 : 0 : return palloc0(req);
330 : : }
331 : :
332 : : /*
333 : : * palloc_mul_extended
334 : : * Equivalent to palloc_extended(mul_size(s1, s2), flags).
335 : : */
336 : : void *
337 : 0 : palloc_mul_extended(Size s1, Size s2, int flags)
338 : : {
339 : : /* inline mul_size() for efficiency */
340 : : Size req;
341 : :
342 [ # # # # : 0 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
# # ]
343 : : req > (SIZE_MAX / 2)))
344 : 0 : mul_size_error(s1, s2);
345 : 0 : return palloc_extended(req, flags);
346 : : }
347 : :
348 : : /*
349 : : * repalloc_mul
350 : : * Equivalent to repalloc(p, mul_size(s1, s2)).
351 : : */
352 : : void *
353 : 224 : repalloc_mul(void *p, Size s1, Size s2)
354 : : {
355 : : /* inline mul_size() for efficiency */
356 : : Size req;
357 : :
358 [ + - - + : 224 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
- + ]
359 : : req > (SIZE_MAX / 2)))
360 : 0 : mul_size_error(s1, s2);
361 : 224 : return repalloc(p, req);
362 : : }
|