1 /* alloc - Convenience routines for safely allocating memory 2 * Copyright (C) 2007-2009 Josh Coalson 3 * Copyright (C) 2011-2014 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 #if 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 0xffffffffffffffffui64 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 /* avoid malloc()ing 0 bytes, see: 67 * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003 68 */ 69 static inline void *safe_malloc_(size_t size) 70 { 71 /* malloc(0) is undefined; FLAC src convention is to always allocate */ 72 if(!size) 73 size++; 74 return malloc(size); 75 } 76 77 static inline void *safe_calloc_(size_t nmemb, size_t size) 78 { 79 if(!nmemb || !size) 80 return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ 81 return calloc(nmemb, size); 82 } 83 84 /*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */ 85 86 static inline void *safe_malloc_add_2op_(size_t size1, size_t size2) 87 { 88 size2 += size1; 89 if(size2 < size1) 90 return 0; 91 return safe_malloc_(size2); 92 } 93 94 static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3) 95 { 96 size2 += size1; 97 if(size2 < size1) 98 return 0; 99 size3 += size2; 100 if(size3 < size2) 101 return 0; 102 return safe_malloc_(size3); 103 } 104 105 static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4) 106 { 107 size2 += size1; 108 if(size2 < size1) 109 return 0; 110 size3 += size2; 111 if(size3 < size2) 112 return 0; 113 size4 += size3; 114 if(size4 < size3) 115 return 0; 116 return safe_malloc_(size4); 117 } 118 119 void *safe_malloc_mul_2op_(size_t size1, size_t size2) ; 120 121 static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3) 122 { 123 if(!size1 || !size2 || !size3) 124 return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ 125 if(size1 > SIZE_MAX / size2) 126 return 0; 127 size1 *= size2; 128 if(size1 > SIZE_MAX / size3) 129 return 0; 130 return malloc(size1*size3); 131 } 132 133 /* size1*size2 + size3 */ 134 static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3) 135 { 136 if(!size1 || !size2) 137 return safe_malloc_(size3); 138 if(size1 > SIZE_MAX / size2) 139 return 0; 140 return safe_malloc_add_2op_(size1*size2, size3); 141 } 142 143 /* size1 * (size2 + size3) */ 144 static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3) 145 { 146 if(!size1 || (!size2 && !size3)) 147 return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ 148 size2 += size3; 149 if(size2 < size3) 150 return 0; 151 if(size1 > SIZE_MAX / size2) 152 return 0; 153 return malloc(size1*size2); 154 } 155 156 static inline void *safe_realloc_(void *ptr, size_t size) 157 { 158 void *oldptr = ptr; 159 void *newptr = realloc(ptr, size); 160 if(size > 0 && newptr == 0) 161 free(oldptr); 162 return newptr; 163 } 164 static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2) 165 { 166 size2 += size1; 167 if(size2 < size1) { 168 free(ptr); 169 return 0; 170 } 171 return realloc(ptr, size2); 172 } 173 174 static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) 175 { 176 size2 += size1; 177 if(size2 < size1) 178 return 0; 179 size3 += size2; 180 if(size3 < size2) 181 return 0; 182 return realloc(ptr, size3); 183 } 184 185 static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) 186 { 187 size2 += size1; 188 if(size2 < size1) 189 return 0; 190 size3 += size2; 191 if(size3 < size2) 192 return 0; 193 size4 += size3; 194 if(size4 < size3) 195 return 0; 196 return realloc(ptr, size4); 197 } 198 199 static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) 200 { 201 if(!size1 || !size2) 202 return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ 203 if(size1 > SIZE_MAX / size2) 204 return 0; 205 return safe_realloc_(ptr, size1*size2); 206 } 207 208 /* size1 * (size2 + size3) */ 209 static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) 210 { 211 if(!size1 || (!size2 && !size3)) 212 return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ 213 size2 += size3; 214 if(size2 < size3) 215 return 0; 216 return safe_realloc_mul_2op_(ptr, size1, size2); 217 } 218 219 #endif 220