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