1*600f14f4SXin Li /* alloc - Convenience routines for safely allocating memory
2*600f14f4SXin Li * Copyright (C) 2007-2009 Josh Coalson
3*600f14f4SXin Li * Copyright (C) 2011-2023 Xiph.Org Foundation
4*600f14f4SXin Li *
5*600f14f4SXin Li * Redistribution and use in source and binary forms, with or without
6*600f14f4SXin Li * modification, are permitted provided that the following conditions
7*600f14f4SXin Li * are met:
8*600f14f4SXin Li *
9*600f14f4SXin Li * - Redistributions of source code must retain the above copyright
10*600f14f4SXin Li * notice, this list of conditions and the following disclaimer.
11*600f14f4SXin Li *
12*600f14f4SXin Li * - Redistributions in binary form must reproduce the above copyright
13*600f14f4SXin Li * notice, this list of conditions and the following disclaimer in the
14*600f14f4SXin Li * documentation and/or other materials provided with the distribution.
15*600f14f4SXin Li *
16*600f14f4SXin Li * - Neither the name of the Xiph.org Foundation nor the names of its
17*600f14f4SXin Li * contributors may be used to endorse or promote products derived from
18*600f14f4SXin Li * this software without specific prior written permission.
19*600f14f4SXin Li *
20*600f14f4SXin Li * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*600f14f4SXin Li * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*600f14f4SXin Li * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*600f14f4SXin Li * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
24*600f14f4SXin Li * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25*600f14f4SXin Li * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26*600f14f4SXin Li * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27*600f14f4SXin Li * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28*600f14f4SXin Li * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29*600f14f4SXin Li * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30*600f14f4SXin Li * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*600f14f4SXin Li */
32*600f14f4SXin Li
33*600f14f4SXin Li #ifndef FLAC__SHARE__ALLOC_H
34*600f14f4SXin Li #define FLAC__SHARE__ALLOC_H
35*600f14f4SXin Li
36*600f14f4SXin Li #ifdef HAVE_CONFIG_H
37*600f14f4SXin Li # include <config.h>
38*600f14f4SXin Li #endif
39*600f14f4SXin Li
40*600f14f4SXin Li /* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early
41*600f14f4SXin Li * before #including this file, otherwise SIZE_MAX might not be defined
42*600f14f4SXin Li */
43*600f14f4SXin Li
44*600f14f4SXin Li #include <limits.h> /* for SIZE_MAX */
45*600f14f4SXin Li #ifdef HAVE_STDINT_H
46*600f14f4SXin Li #include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */
47*600f14f4SXin Li #endif
48*600f14f4SXin Li #include <stdlib.h> /* for size_t, malloc(), etc */
49*600f14f4SXin Li #include "share/compat.h"
50*600f14f4SXin Li
51*600f14f4SXin Li #ifndef SIZE_MAX
52*600f14f4SXin Li # ifndef SIZE_T_MAX
53*600f14f4SXin Li # ifdef _MSC_VER
54*600f14f4SXin Li # ifdef _WIN64
55*600f14f4SXin Li # define SIZE_T_MAX FLAC__U64L(0xffffffffffffffff)
56*600f14f4SXin Li # else
57*600f14f4SXin Li # define SIZE_T_MAX 0xffffffff
58*600f14f4SXin Li # endif
59*600f14f4SXin Li # else
60*600f14f4SXin Li # error
61*600f14f4SXin Li # endif
62*600f14f4SXin Li # endif
63*600f14f4SXin Li # define SIZE_MAX SIZE_T_MAX
64*600f14f4SXin Li #endif
65*600f14f4SXin Li
66*600f14f4SXin Li #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
67*600f14f4SXin Li extern int alloc_check_threshold, alloc_check_counter;
68*600f14f4SXin Li
alloc_check()69*600f14f4SXin Li static inline int alloc_check() {
70*600f14f4SXin Li if(alloc_check_threshold == INT32_MAX)
71*600f14f4SXin Li return 0;
72*600f14f4SXin Li else if(alloc_check_counter++ == alloc_check_threshold)
73*600f14f4SXin Li return 1;
74*600f14f4SXin Li else
75*600f14f4SXin Li return 0;
76*600f14f4SXin Li }
77*600f14f4SXin Li
78*600f14f4SXin Li #endif
79*600f14f4SXin Li
80*600f14f4SXin Li /* avoid malloc()ing 0 bytes, see:
81*600f14f4SXin Li * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003
82*600f14f4SXin Li */
83*600f14f4SXin Li
safe_malloc_(size_t size)84*600f14f4SXin Li static inline void *safe_malloc_(size_t size)
85*600f14f4SXin Li {
86*600f14f4SXin Li #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
87*600f14f4SXin Li /* Fail if requested */
88*600f14f4SXin Li if(alloc_check())
89*600f14f4SXin Li return NULL;
90*600f14f4SXin Li #endif
91*600f14f4SXin Li /* malloc(0) is undefined; FLAC src convention is to always allocate */
92*600f14f4SXin Li if(!size)
93*600f14f4SXin Li size++;
94*600f14f4SXin Li return malloc(size);
95*600f14f4SXin Li }
96*600f14f4SXin Li
97*600f14f4SXin Li #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
malloc_(size_t size)98*600f14f4SXin Li static inline void *malloc_(size_t size)
99*600f14f4SXin Li {
100*600f14f4SXin Li /* Fail if requested */
101*600f14f4SXin Li if(alloc_check())
102*600f14f4SXin Li return NULL;
103*600f14f4SXin Li return malloc(size);
104*600f14f4SXin Li }
105*600f14f4SXin Li #else
106*600f14f4SXin Li #define malloc_ malloc
107*600f14f4SXin Li #endif
108*600f14f4SXin Li
109*600f14f4SXin Li
110*600f14f4SXin Li
safe_calloc_(size_t nmemb,size_t size)111*600f14f4SXin Li static inline void *safe_calloc_(size_t nmemb, size_t size)
112*600f14f4SXin Li {
113*600f14f4SXin Li #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
114*600f14f4SXin Li /* Fail if requested */
115*600f14f4SXin Li if(alloc_check())
116*600f14f4SXin Li return NULL;
117*600f14f4SXin Li #endif
118*600f14f4SXin Li if(!nmemb || !size)
119*600f14f4SXin Li return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
120*600f14f4SXin Li return calloc(nmemb, size);
121*600f14f4SXin Li }
122*600f14f4SXin Li
123*600f14f4SXin Li /*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */
124*600f14f4SXin Li
safe_malloc_add_2op_(size_t size1,size_t size2)125*600f14f4SXin Li static inline void *safe_malloc_add_2op_(size_t size1, size_t size2)
126*600f14f4SXin Li {
127*600f14f4SXin Li size2 += size1;
128*600f14f4SXin Li if(size2 < size1)
129*600f14f4SXin Li return 0;
130*600f14f4SXin Li return safe_malloc_(size2);
131*600f14f4SXin Li }
132*600f14f4SXin Li
safe_malloc_add_3op_(size_t size1,size_t size2,size_t size3)133*600f14f4SXin Li static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3)
134*600f14f4SXin Li {
135*600f14f4SXin Li size2 += size1;
136*600f14f4SXin Li if(size2 < size1)
137*600f14f4SXin Li return 0;
138*600f14f4SXin Li size3 += size2;
139*600f14f4SXin Li if(size3 < size2)
140*600f14f4SXin Li return 0;
141*600f14f4SXin Li return safe_malloc_(size3);
142*600f14f4SXin Li }
143*600f14f4SXin Li
safe_malloc_add_4op_(size_t size1,size_t size2,size_t size3,size_t size4)144*600f14f4SXin Li static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4)
145*600f14f4SXin Li {
146*600f14f4SXin Li size2 += size1;
147*600f14f4SXin Li if(size2 < size1)
148*600f14f4SXin Li return 0;
149*600f14f4SXin Li size3 += size2;
150*600f14f4SXin Li if(size3 < size2)
151*600f14f4SXin Li return 0;
152*600f14f4SXin Li size4 += size3;
153*600f14f4SXin Li if(size4 < size3)
154*600f14f4SXin Li return 0;
155*600f14f4SXin Li return safe_malloc_(size4);
156*600f14f4SXin Li }
157*600f14f4SXin Li
158*600f14f4SXin Li void *safe_malloc_mul_2op_(size_t size1, size_t size2) ;
159*600f14f4SXin Li
safe_malloc_mul_3op_(size_t size1,size_t size2,size_t size3)160*600f14f4SXin Li static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3)
161*600f14f4SXin Li {
162*600f14f4SXin Li if(!size1 || !size2 || !size3)
163*600f14f4SXin Li return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
164*600f14f4SXin Li if(size1 > SIZE_MAX / size2)
165*600f14f4SXin Li return 0;
166*600f14f4SXin Li size1 *= size2;
167*600f14f4SXin Li if(size1 > SIZE_MAX / size3)
168*600f14f4SXin Li return 0;
169*600f14f4SXin Li return malloc_(size1*size3);
170*600f14f4SXin Li }
171*600f14f4SXin Li
172*600f14f4SXin Li /* size1*size2 + size3 */
safe_malloc_mul2add_(size_t size1,size_t size2,size_t size3)173*600f14f4SXin Li static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3)
174*600f14f4SXin Li {
175*600f14f4SXin Li if(!size1 || !size2)
176*600f14f4SXin Li return safe_malloc_(size3);
177*600f14f4SXin Li if(size1 > SIZE_MAX / size2)
178*600f14f4SXin Li return 0;
179*600f14f4SXin Li return safe_malloc_add_2op_(size1*size2, size3);
180*600f14f4SXin Li }
181*600f14f4SXin Li
182*600f14f4SXin Li /* size1 * (size2 + size3) */
safe_malloc_muladd2_(size_t size1,size_t size2,size_t size3)183*600f14f4SXin Li static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3)
184*600f14f4SXin Li {
185*600f14f4SXin Li if(!size1 || (!size2 && !size3))
186*600f14f4SXin Li return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
187*600f14f4SXin Li size2 += size3;
188*600f14f4SXin Li if(size2 < size3)
189*600f14f4SXin Li return 0;
190*600f14f4SXin Li if(size1 > SIZE_MAX / size2)
191*600f14f4SXin Li return 0;
192*600f14f4SXin Li return malloc_(size1*size2);
193*600f14f4SXin Li }
194*600f14f4SXin Li
safe_realloc_(void * ptr,size_t size)195*600f14f4SXin Li static inline void *safe_realloc_(void *ptr, size_t size)
196*600f14f4SXin Li {
197*600f14f4SXin Li void *oldptr;
198*600f14f4SXin Li void *newptr;
199*600f14f4SXin Li #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
200*600f14f4SXin Li /* Fail if requested */
201*600f14f4SXin Li if(alloc_check() && size > 0) {
202*600f14f4SXin Li free(ptr);
203*600f14f4SXin Li return NULL;
204*600f14f4SXin Li }
205*600f14f4SXin Li #endif
206*600f14f4SXin Li oldptr = ptr;
207*600f14f4SXin Li newptr = realloc(ptr, size);
208*600f14f4SXin Li if(size > 0 && newptr == 0)
209*600f14f4SXin Li free(oldptr);
210*600f14f4SXin Li return newptr;
211*600f14f4SXin Li }
212*600f14f4SXin Li
213*600f14f4SXin Li #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
realloc_(void * ptr,size_t size)214*600f14f4SXin Li static inline void *realloc_(void *ptr, size_t size)
215*600f14f4SXin Li {
216*600f14f4SXin Li /* Fail if requested */
217*600f14f4SXin Li if(alloc_check())
218*600f14f4SXin Li return NULL;
219*600f14f4SXin Li return realloc(ptr, size);
220*600f14f4SXin Li }
221*600f14f4SXin Li #else
222*600f14f4SXin Li #define realloc_ realloc
223*600f14f4SXin Li #endif
224*600f14f4SXin Li
225*600f14f4SXin Li
safe_realloc_nofree_add_2op_(void * ptr,size_t size1,size_t size2)226*600f14f4SXin Li static inline void *safe_realloc_nofree_add_2op_(void *ptr, size_t size1, size_t size2)
227*600f14f4SXin Li {
228*600f14f4SXin Li size2 += size1;
229*600f14f4SXin Li if(size2 < size1)
230*600f14f4SXin Li return 0;
231*600f14f4SXin Li return realloc_(ptr, size2);
232*600f14f4SXin Li }
233*600f14f4SXin Li
safe_realloc_add_3op_(void * ptr,size_t size1,size_t size2,size_t size3)234*600f14f4SXin Li static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
235*600f14f4SXin Li {
236*600f14f4SXin Li size2 += size1;
237*600f14f4SXin Li if(size2 < size1) {
238*600f14f4SXin Li free(ptr);
239*600f14f4SXin Li return 0;
240*600f14f4SXin Li }
241*600f14f4SXin Li size3 += size2;
242*600f14f4SXin Li if(size3 < size2) {
243*600f14f4SXin Li free(ptr);
244*600f14f4SXin Li return 0;
245*600f14f4SXin Li }
246*600f14f4SXin Li return safe_realloc_(ptr, size3);
247*600f14f4SXin Li }
248*600f14f4SXin Li
safe_realloc_nofree_add_3op_(void * ptr,size_t size1,size_t size2,size_t size3)249*600f14f4SXin Li static inline void *safe_realloc_nofree_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
250*600f14f4SXin Li {
251*600f14f4SXin Li size2 += size1;
252*600f14f4SXin Li if(size2 < size1)
253*600f14f4SXin Li return 0;
254*600f14f4SXin Li size3 += size2;
255*600f14f4SXin Li if(size3 < size2)
256*600f14f4SXin Li return 0;
257*600f14f4SXin Li return realloc_(ptr, size3);
258*600f14f4SXin Li }
259*600f14f4SXin Li
safe_realloc_nofree_add_4op_(void * ptr,size_t size1,size_t size2,size_t size3,size_t size4)260*600f14f4SXin Li static inline void *safe_realloc_nofree_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4)
261*600f14f4SXin Li {
262*600f14f4SXin Li size2 += size1;
263*600f14f4SXin Li if(size2 < size1)
264*600f14f4SXin Li return 0;
265*600f14f4SXin Li size3 += size2;
266*600f14f4SXin Li if(size3 < size2)
267*600f14f4SXin Li return 0;
268*600f14f4SXin Li size4 += size3;
269*600f14f4SXin Li if(size4 < size3)
270*600f14f4SXin Li return 0;
271*600f14f4SXin Li return realloc_(ptr, size4);
272*600f14f4SXin Li }
273*600f14f4SXin Li
safe_realloc_mul_2op_(void * ptr,size_t size1,size_t size2)274*600f14f4SXin Li static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2)
275*600f14f4SXin Li {
276*600f14f4SXin Li if(!size1 || !size2)
277*600f14f4SXin Li return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
278*600f14f4SXin Li if(size1 > SIZE_MAX / size2) {
279*600f14f4SXin Li free(ptr);
280*600f14f4SXin Li return 0;
281*600f14f4SXin Li }
282*600f14f4SXin Li return safe_realloc_(ptr, size1*size2);
283*600f14f4SXin Li }
284*600f14f4SXin Li
safe_realloc_nofree_mul_2op_(void * ptr,size_t size1,size_t size2)285*600f14f4SXin Li static inline void *safe_realloc_nofree_mul_2op_(void *ptr, size_t size1, size_t size2)
286*600f14f4SXin Li {
287*600f14f4SXin Li if(!size1 || !size2)
288*600f14f4SXin Li return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
289*600f14f4SXin Li if(size1 > SIZE_MAX / size2)
290*600f14f4SXin Li return 0;
291*600f14f4SXin Li return realloc_(ptr, size1*size2);
292*600f14f4SXin Li }
293*600f14f4SXin Li
294*600f14f4SXin Li /* size1 * (size2 + size3) */
safe_realloc_muladd2_(void * ptr,size_t size1,size_t size2,size_t size3)295*600f14f4SXin Li static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
296*600f14f4SXin Li {
297*600f14f4SXin Li if(!size1 || (!size2 && !size3))
298*600f14f4SXin Li return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
299*600f14f4SXin Li size2 += size3;
300*600f14f4SXin Li if(size2 < size3) {
301*600f14f4SXin Li free(ptr);
302*600f14f4SXin Li return 0;
303*600f14f4SXin Li }
304*600f14f4SXin Li return safe_realloc_mul_2op_(ptr, size1, size2);
305*600f14f4SXin Li }
306*600f14f4SXin Li
307*600f14f4SXin Li /* size1 * (size2 + size3) */
safe_realloc_nofree_muladd2_(void * ptr,size_t size1,size_t size2,size_t size3)308*600f14f4SXin Li static inline void *safe_realloc_nofree_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
309*600f14f4SXin Li {
310*600f14f4SXin Li if(!size1 || (!size2 && !size3))
311*600f14f4SXin Li return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
312*600f14f4SXin Li size2 += size3;
313*600f14f4SXin Li if(size2 < size3)
314*600f14f4SXin Li return 0;
315*600f14f4SXin Li return safe_realloc_nofree_mul_2op_(ptr, size1, size2);
316*600f14f4SXin Li }
317*600f14f4SXin Li
318*600f14f4SXin Li #endif
319