Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 1 | /* libFLAC - Free Lossless Audio Codec library |
Josh Coalson | dea0f5a | 2009-01-07 07:31:28 +0000 | [diff] [blame] | 2 | * Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008,2009 Josh Coalson |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 3 | * |
Josh Coalson | afd8107 | 2003-01-31 23:34:56 +0000 | [diff] [blame] | 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions |
| 6 | * are met: |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 7 | * |
Josh Coalson | afd8107 | 2003-01-31 23:34:56 +0000 | [diff] [blame] | 8 | * - Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 10 | * |
Josh Coalson | afd8107 | 2003-01-31 23:34:56 +0000 | [diff] [blame] | 11 | * - Redistributions in binary form must reproduce the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer in the |
| 13 | * documentation and/or other materials provided with the distribution. |
| 14 | * |
| 15 | * - Neither the name of the Xiph.org Foundation nor the names of its |
| 16 | * contributors may be used to endorse or promote products derived from |
| 17 | * this software without specific prior written permission. |
| 18 | * |
| 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
| 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 30 | */ |
| 31 | |
Josh Coalson | b1ec796 | 2006-05-24 04:41:36 +0000 | [diff] [blame] | 32 | #if HAVE_CONFIG_H |
| 33 | # include <config.h> |
| 34 | #endif |
| 35 | |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 36 | #include "private/memory.h" |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 37 | #include "FLAC/assert.h" |
Josh Coalson | 0f008d2 | 2007-09-11 04:49:56 +0000 | [diff] [blame] | 38 | #include "share/alloc.h" |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 39 | |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 40 | void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address) |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 41 | { |
| 42 | void *x; |
| 43 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 44 | FLAC__ASSERT(0 != aligned_address); |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 45 | |
| 46 | #ifdef FLAC__ALIGN_MALLOC_DATA |
| 47 | /* align on 32-byte (256-bit) boundary */ |
Josh Coalson | 0f008d2 | 2007-09-11 04:49:56 +0000 | [diff] [blame] | 48 | x = safe_malloc_add_2op_(bytes, /*+*/31); |
Josh Coalson | cebba2a | 2007-06-14 06:10:00 +0000 | [diff] [blame] | 49 | #ifdef SIZEOF_VOIDP |
| 50 | #if SIZEOF_VOIDP == 4 |
| 51 | /* could do *aligned_address = x + ((unsigned) (32 - (((unsigned)x) & 31))) & 31; */ |
| 52 | *aligned_address = (void*)(((unsigned)x + 31) & -32); |
| 53 | #elif SIZEOF_VOIDP == 8 |
| 54 | *aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32))); |
| 55 | #else |
| 56 | # error Unsupported sizeof(void*) |
| 57 | #endif |
| 58 | #else |
Josh Coalson | ab56ef1 | 2006-11-17 06:52:19 +0000 | [diff] [blame] | 59 | /* there's got to be a better way to do this right for all archs */ |
| 60 | if(sizeof(void*) == sizeof(unsigned)) |
| 61 | *aligned_address = (void*)(((unsigned)x + 31) & -32); |
| 62 | else if(sizeof(void*) == sizeof(FLAC__uint64)) |
| 63 | *aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32))); |
| 64 | else |
| 65 | return 0; |
Josh Coalson | cebba2a | 2007-06-14 06:10:00 +0000 | [diff] [blame] | 66 | #endif |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 67 | #else |
Josh Coalson | 0f008d2 | 2007-09-11 04:49:56 +0000 | [diff] [blame] | 68 | x = safe_malloc_(bytes); |
Josh Coalson | de469cf | 2001-05-11 23:54:27 +0000 | [diff] [blame] | 69 | *aligned_address = x; |
| 70 | #endif |
| 71 | return x; |
| 72 | } |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 73 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 74 | FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer) |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 75 | { |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 76 | FLAC__int32 *pu; /* unaligned pointer */ |
| 77 | union { /* union needed to comply with C99 pointer aliasing rules */ |
| 78 | FLAC__int32 *pa; /* aligned pointer */ |
| 79 | void *pv; /* aligned pointer alias */ |
| 80 | } u; |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 81 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 82 | FLAC__ASSERT(elements > 0); |
| 83 | FLAC__ASSERT(0 != unaligned_pointer); |
| 84 | FLAC__ASSERT(0 != aligned_pointer); |
| 85 | FLAC__ASSERT(unaligned_pointer != aligned_pointer); |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 86 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 87 | if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ |
Josh Coalson | 0f008d2 | 2007-09-11 04:49:56 +0000 | [diff] [blame] | 88 | return false; |
| 89 | |
Erik de Castro Lopo | 6c2040d | 2012-04-04 21:29:25 +1000 | [diff] [blame] | 90 | pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 91 | if(0 == pu) { |
| 92 | return false; |
| 93 | } |
| 94 | else { |
| 95 | if(*unaligned_pointer != 0) |
| 96 | free(*unaligned_pointer); |
| 97 | *unaligned_pointer = pu; |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 98 | *aligned_pointer = u.pa; |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 99 | return true; |
| 100 | } |
| 101 | } |
| 102 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 103 | FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer) |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 104 | { |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 105 | FLAC__uint32 *pu; /* unaligned pointer */ |
| 106 | union { /* union needed to comply with C99 pointer aliasing rules */ |
| 107 | FLAC__uint32 *pa; /* aligned pointer */ |
| 108 | void *pv; /* aligned pointer alias */ |
| 109 | } u; |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 110 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 111 | FLAC__ASSERT(elements > 0); |
| 112 | FLAC__ASSERT(0 != unaligned_pointer); |
| 113 | FLAC__ASSERT(0 != aligned_pointer); |
| 114 | FLAC__ASSERT(unaligned_pointer != aligned_pointer); |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 115 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 116 | if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ |
Josh Coalson | 0f008d2 | 2007-09-11 04:49:56 +0000 | [diff] [blame] | 117 | return false; |
| 118 | |
Erik de Castro Lopo | 6c2040d | 2012-04-04 21:29:25 +1000 | [diff] [blame] | 119 | pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 120 | if(0 == pu) { |
| 121 | return false; |
| 122 | } |
| 123 | else { |
| 124 | if(*unaligned_pointer != 0) |
| 125 | free(*unaligned_pointer); |
| 126 | *unaligned_pointer = pu; |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 127 | *aligned_pointer = u.pa; |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 128 | return true; |
| 129 | } |
| 130 | } |
| 131 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 132 | FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer) |
Josh Coalson | bf9dd76 | 2001-07-16 18:04:52 +0000 | [diff] [blame] | 133 | { |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 134 | FLAC__uint64 *pu; /* unaligned pointer */ |
| 135 | union { /* union needed to comply with C99 pointer aliasing rules */ |
| 136 | FLAC__uint64 *pa; /* aligned pointer */ |
| 137 | void *pv; /* aligned pointer alias */ |
| 138 | } u; |
Josh Coalson | bf9dd76 | 2001-07-16 18:04:52 +0000 | [diff] [blame] | 139 | |
| 140 | FLAC__ASSERT(elements > 0); |
| 141 | FLAC__ASSERT(0 != unaligned_pointer); |
| 142 | FLAC__ASSERT(0 != aligned_pointer); |
| 143 | FLAC__ASSERT(unaligned_pointer != aligned_pointer); |
| 144 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 145 | if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ |
Josh Coalson | 0f008d2 | 2007-09-11 04:49:56 +0000 | [diff] [blame] | 146 | return false; |
| 147 | |
Erik de Castro Lopo | 6c2040d | 2012-04-04 21:29:25 +1000 | [diff] [blame] | 148 | pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); |
Josh Coalson | bf9dd76 | 2001-07-16 18:04:52 +0000 | [diff] [blame] | 149 | if(0 == pu) { |
| 150 | return false; |
| 151 | } |
| 152 | else { |
| 153 | if(*unaligned_pointer != 0) |
| 154 | free(*unaligned_pointer); |
| 155 | *unaligned_pointer = pu; |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 156 | *aligned_pointer = u.pa; |
Josh Coalson | bf9dd76 | 2001-07-16 18:04:52 +0000 | [diff] [blame] | 157 | return true; |
| 158 | } |
| 159 | } |
| 160 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 161 | FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, unsigned **unaligned_pointer, unsigned **aligned_pointer) |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 162 | { |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 163 | unsigned *pu; /* unaligned pointer */ |
| 164 | union { /* union needed to comply with C99 pointer aliasing rules */ |
| 165 | unsigned *pa; /* aligned pointer */ |
| 166 | void *pv; /* aligned pointer alias */ |
| 167 | } u; |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 168 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 169 | FLAC__ASSERT(elements > 0); |
| 170 | FLAC__ASSERT(0 != unaligned_pointer); |
| 171 | FLAC__ASSERT(0 != aligned_pointer); |
| 172 | FLAC__ASSERT(unaligned_pointer != aligned_pointer); |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 173 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 174 | if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ |
Josh Coalson | 0f008d2 | 2007-09-11 04:49:56 +0000 | [diff] [blame] | 175 | return false; |
| 176 | |
Erik de Castro Lopo | 6c2040d | 2012-04-04 21:29:25 +1000 | [diff] [blame] | 177 | pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 178 | if(0 == pu) { |
| 179 | return false; |
| 180 | } |
| 181 | else { |
| 182 | if(*unaligned_pointer != 0) |
| 183 | free(*unaligned_pointer); |
| 184 | *unaligned_pointer = pu; |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 185 | *aligned_pointer = u.pa; |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 186 | return true; |
| 187 | } |
| 188 | } |
| 189 | |
Josh Coalson | 5f2b46d | 2004-11-09 01:34:01 +0000 | [diff] [blame] | 190 | #ifndef FLAC__INTEGER_ONLY_LIBRARY |
| 191 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 192 | FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer) |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 193 | { |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 194 | FLAC__real *pu; /* unaligned pointer */ |
| 195 | union { /* union needed to comply with C99 pointer aliasing rules */ |
| 196 | FLAC__real *pa; /* aligned pointer */ |
| 197 | void *pv; /* aligned pointer alias */ |
| 198 | } u; |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 199 | |
Josh Coalson | 1b68982 | 2001-05-31 20:11:02 +0000 | [diff] [blame] | 200 | FLAC__ASSERT(elements > 0); |
| 201 | FLAC__ASSERT(0 != unaligned_pointer); |
| 202 | FLAC__ASSERT(0 != aligned_pointer); |
| 203 | FLAC__ASSERT(unaligned_pointer != aligned_pointer); |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 204 | |
Erik de Castro Lopo | 587e118 | 2012-02-17 17:52:12 +1100 | [diff] [blame] | 205 | if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ |
Josh Coalson | 0f008d2 | 2007-09-11 04:49:56 +0000 | [diff] [blame] | 206 | return false; |
| 207 | |
Erik de Castro Lopo | 6c2040d | 2012-04-04 21:29:25 +1000 | [diff] [blame] | 208 | pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 209 | if(0 == pu) { |
| 210 | return false; |
| 211 | } |
| 212 | else { |
| 213 | if(*unaligned_pointer != 0) |
| 214 | free(*unaligned_pointer); |
| 215 | *unaligned_pointer = pu; |
Josh Coalson | 5e8e733 | 2004-10-07 00:22:03 +0000 | [diff] [blame] | 216 | *aligned_pointer = u.pa; |
Josh Coalson | 02f3900 | 2001-05-13 05:15:47 +0000 | [diff] [blame] | 217 | return true; |
| 218 | } |
| 219 | } |
Josh Coalson | 5f2b46d | 2004-11-09 01:34:01 +0000 | [diff] [blame] | 220 | |
| 221 | #endif |
Erik de Castro Lopo | b489097 | 2012-02-26 20:00:36 +1100 | [diff] [blame] | 222 | |
Erik de Castro Lopo | 8749dc2 | 2012-06-22 14:23:56 +1000 | [diff] [blame] | 223 | void *safe_malloc_mul_2op_p(size_t size1, size_t size2) |
Erik de Castro Lopo | b489097 | 2012-02-26 20:00:36 +1100 | [diff] [blame] | 224 | { |
| 225 | if(!size1 || !size2) |
| 226 | return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ |
| 227 | if(size1 > SIZE_MAX / size2) |
| 228 | return 0; |
| 229 | return malloc(size1*size2); |
| 230 | } |