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 5203772 : pg_malloc_internal(size_t size, int flags)
30 : {
31 : void *tmp;
32 :
33 : /* Avoid unportable behavior of malloc(0) */
34 5203772 : if (size == 0)
35 4445 : size = 1;
36 5203772 : tmp = malloc(size);
37 5203772 : 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 5203772 : if ((flags & MCXT_ALLOC_ZERO) != 0)
48 6456854 : MemSet(tmp, 0, size);
49 5203772 : return tmp;
50 : }
51 :
52 : void *
53 2229453 : pg_malloc(size_t size)
54 : {
55 2229453 : return pg_malloc_internal(size, 0);
56 : }
57 :
58 : void *
59 1677337 : pg_malloc0(size_t size)
60 : {
61 1677337 : return pg_malloc_internal(size, MCXT_ALLOC_ZERO);
62 : }
63 :
64 : void *
65 245740 : pg_malloc_extended(size_t size, int flags)
66 : {
67 245740 : return pg_malloc_internal(size, flags);
68 : }
69 :
70 : void *
71 95559 : pg_realloc(void *ptr, size_t size)
72 : {
73 : void *tmp;
74 :
75 : /* Avoid unportable behavior of realloc(NULL, 0) */
76 95559 : if (ptr == NULL && size == 0)
77 0 : size = 1;
78 95559 : tmp = realloc(ptr, size);
79 95559 : if (!tmp)
80 : {
81 0 : fprintf(stderr, _("out of memory\n"));
82 0 : exit(EXIT_FAILURE);
83 : }
84 95559 : return tmp;
85 : }
86 :
87 : /*
88 : * "Safe" wrapper around strdup().
89 : */
90 : char *
91 8596081 : pg_strdup(const char *in)
92 : {
93 : char *tmp;
94 :
95 8596081 : if (!in)
96 : {
97 0 : fprintf(stderr,
98 0 : _("cannot duplicate null pointer (internal error)\n"));
99 0 : exit(EXIT_FAILURE);
100 : }
101 8596081 : tmp = strdup(in);
102 8596081 : if (!tmp)
103 : {
104 0 : fprintf(stderr, _("out of memory\n"));
105 0 : exit(EXIT_FAILURE);
106 : }
107 8596081 : return tmp;
108 : }
109 :
110 : void
111 5465319 : pg_free(void *ptr)
112 : {
113 5465319 : free(ptr);
114 5465319 : }
115 :
116 : /*
117 : * Frontend emulation of backend memory management functions. Useful for
118 : * programs that compile backend files.
119 : */
120 : void *
121 1047648 : palloc(Size size)
122 : {
123 1047648 : return pg_malloc_internal(size, 0);
124 : }
125 :
126 : void *
127 3099 : palloc0(Size size)
128 : {
129 3099 : return pg_malloc_internal(size, MCXT_ALLOC_ZERO);
130 : }
131 :
132 : void *
133 495 : palloc_extended(Size size, int flags)
134 : {
135 495 : return pg_malloc_internal(size, flags);
136 : }
137 :
138 : void
139 2601925 : pfree(void *pointer)
140 : {
141 2601925 : pg_free(pointer);
142 2601925 : }
143 :
144 : char *
145 1260813 : pstrdup(const char *in)
146 : {
147 1260813 : return pg_strdup(in);
148 : }
149 :
150 : char *
151 317 : pnstrdup(const char *in, Size size)
152 : {
153 : char *tmp;
154 : int len;
155 :
156 317 : if (!in)
157 : {
158 0 : fprintf(stderr,
159 0 : _("cannot duplicate null pointer (internal error)\n"));
160 0 : exit(EXIT_FAILURE);
161 : }
162 :
163 317 : len = strnlen(in, size);
164 317 : tmp = malloc(len + 1);
165 317 : if (tmp == NULL)
166 : {
167 0 : fprintf(stderr, _("out of memory\n"));
168 0 : exit(EXIT_FAILURE);
169 : }
170 :
171 317 : memcpy(tmp, in, len);
172 317 : tmp[len] = '\0';
173 :
174 317 : return tmp;
175 : }
176 :
177 : void *
178 58948 : repalloc(void *pointer, Size size)
179 : {
180 58948 : 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
196 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 *
238 1264169 : pg_malloc_mul(Size s1, Size s2)
239 : {
240 : /* inline mul_size() for efficiency */
241 : Size req;
242 :
243 1264169 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
244 : req > (SIZE_MAX / 2)))
245 0 : mul_size_error(s1, s2);
246 1264169 : 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 *
256 1549747 : pg_malloc0_mul(Size s1, Size s2)
257 : {
258 : /* inline mul_size() for efficiency */
259 : Size req;
260 :
261 1549747 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
262 : req > (SIZE_MAX / 2)))
263 0 : mul_size_error(s1, s2);
264 1549747 : 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 *
272 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 *
288 35249 : pg_realloc_mul(void *p, Size s1, Size s2)
289 : {
290 : /* inline mul_size() for efficiency */
291 : Size req;
292 :
293 35249 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
294 : req > (SIZE_MAX / 2)))
295 0 : mul_size_error(s1, s2);
296 35249 : return pg_realloc(p, req);
297 : }
298 :
299 : /*
300 : * palloc_mul
301 : * Equivalent to palloc(mul_size(s1, s2)).
302 : */
303 : void *
304 3780 : palloc_mul(Size s1, Size s2)
305 : {
306 : /* inline mul_size() for efficiency */
307 : Size req;
308 :
309 3780 : if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
310 : req > (SIZE_MAX / 2)))
311 0 : mul_size_error(s1, s2);
312 3780 : 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 *
322 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 : }
|