diff options
Diffstat (limited to 'include/share/alloc.h')
-rw-r--r-- | include/share/alloc.h | 231 |
1 files changed, 184 insertions, 47 deletions
diff --git a/include/share/alloc.h b/include/share/alloc.h index 2e92dd8..5e1f1e2 100644 --- a/include/share/alloc.h +++ b/include/share/alloc.h @@ -1,72 +1,209 @@ -/* - * Copyright (C) 2011 The Android Open Source Project +/* alloc - Convenience routines for safely allocating memory + * Copyright (C) 2007-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * http://www.apache.org/licenses/LICENSE-2.0 + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__SHARE__ALLOC_H +#define FLAC__SHARE__ALLOC_H + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early + * before #including this file, otherwise SIZE_MAX might not be defined */ -#ifndef __SHARE_ALLOC_H_ -#define __SHARE_ALLOC_H_ +#include <limits.h> /* for SIZE_MAX */ +#if HAVE_STDINT_H +#include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */ +#endif +#include <stdlib.h> /* for size_t, malloc(), etc */ +#include "share/compat.h" -#include <limits.h> +#ifndef SIZE_MAX +# ifndef SIZE_T_MAX +# ifdef _MSC_VER +# ifdef _WIN64 +# define SIZE_T_MAX 0xffffffffffffffffui64 +# else +# define SIZE_T_MAX 0xffffffff +# endif +# else +# error +# endif +# endif +# define SIZE_MAX SIZE_T_MAX +#endif + +/* avoid malloc()ing 0 bytes, see: + * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003 +*/ +static inline void *safe_malloc_(size_t size) +{ + /* malloc(0) is undefined; FLAC src convention is to always allocate */ + if(!size) + size++; + return malloc(size); +} + +static inline void *safe_calloc_(size_t nmemb, size_t size) +{ + if(!nmemb || !size) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + return calloc(nmemb, size); +} + +/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */ + +static inline void *safe_malloc_add_2op_(size_t size1, size_t size2) +{ + size2 += size1; + if(size2 < size1) + return 0; + return safe_malloc_(size2); +} + +static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + return safe_malloc_(size3); +} + +static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + size4 += size3; + if(size4 < size3) + return 0; + return safe_malloc_(size4); +} + +void *safe_malloc_mul_2op_(size_t size1, size_t size2) ; + +static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3) +{ + if(!size1 || !size2 || !size3) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + if(size1 > SIZE_MAX / size2) + return 0; + size1 *= size2; + if(size1 > SIZE_MAX / size3) + return 0; + return malloc(size1*size3); +} + +/* size1*size2 + size3 */ +static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3) +{ + if(!size1 || !size2) + return safe_malloc_(size3); + if(size1 > SIZE_MAX / size2) + return 0; + return safe_malloc_add_2op_(size1*size2, size3); +} -// malloc(n floor 1) -static inline void *safe_malloc_(size_t n) +/* size1 * (size2 + size3) */ +static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3) { - // dlmalloc is already safe - return malloc(n); + if(!size1 || (!size2 && !size3)) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + size2 += size3; + if(size2 < size3) + return 0; + if(size1 > SIZE_MAX / size2) + return 0; + return malloc(size1*size2); } -// malloc(n1 * n2) then memset to zero -static inline void *safe_calloc_(size_t n1, size_t n2) +static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2) { - // dlcalloc is already safe - return calloc(n1, n2); + size2 += size1; + if(size2 < size1) + return 0; + return realloc(ptr, size2); } -// malloc(n1 + n2) -static inline void *safe_malloc_add_2op_(size_t n1, size_t n2) +static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) { - unsigned long long n = n1 + n2; - size_t ns = n; - // check for overflow - return n == ns ? malloc(ns) : NULL; + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + return realloc(ptr, size3); } -// malloc(n1 * n2) -static inline void *safe_malloc_mul_2op_(size_t n1, size_t n2) +static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) { - unsigned long long n = n1 * n2; - size_t ns = n; - // check for overflow - return n == ns ? malloc(ns) : NULL; + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + size4 += size3; + if(size4 < size3) + return 0; + return realloc(ptr, size4); } -// malloc(n1 * (n2 + n3)) -static inline void *safe_malloc_muladd2_(size_t n1, size_t n2, size_t n3) +static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) { - unsigned long long n = n1 * (n2 + n3); - size_t ns = n; - // check for overflow - return n == ns ? malloc(ns) : NULL; + if(!size1 || !size2) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + if(size1 > SIZE_MAX / size2) + return 0; + return realloc(ptr, size1*size2); } -// realloc(ptr, n1 * n2) -static inline void *safe_realloc_mul_2op_(void *ptr, size_t n1, size_t n2) +/* size1 * (size2 + size3) */ +static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) { - unsigned long long n = n1 * n2; - size_t ns = n; - // check for overflow - return n == ns ? realloc(ptr, ns) : NULL; + if(!size1 || (!size2 && !size3)) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + size2 += size3; + if(size2 < size3) + return 0; + return safe_realloc_mul_2op_(ptr, size1, size2); } -#endif // __SHARE_ALLOC_H_ +#endif |