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