Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * default memory allocator for libavutil | |
3 | * Copyright (c) 2002 Fabrice Bellard | |
4 | * | |
5 | * This file is part of FFmpeg. | |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * FFmpeg is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with FFmpeg; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | */ | |
21 | ||
22 | /** | |
23 | * @file | |
24 | * default memory allocator for libavutil | |
25 | */ | |
26 | ||
27 | #define _XOPEN_SOURCE 600 | |
28 | ||
29 | #include "config.h" | |
30 | ||
31 | #include <limits.h> | |
32 | #include <stdint.h> | |
33 | #include <stdlib.h> | |
34 | #include <string.h> | |
35 | #if HAVE_MALLOC_H | |
36 | #include <malloc.h> | |
37 | #endif | |
38 | ||
39 | #include "avassert.h" | |
40 | #include "avutil.h" | |
41 | #include "common.h" | |
42 | #include "dynarray.h" | |
43 | #include "intreadwrite.h" | |
44 | #include "mem.h" | |
45 | ||
46 | #ifdef MALLOC_PREFIX | |
47 | ||
48 | #define malloc AV_JOIN(MALLOC_PREFIX, malloc) | |
49 | #define memalign AV_JOIN(MALLOC_PREFIX, memalign) | |
50 | #define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign) | |
51 | #define realloc AV_JOIN(MALLOC_PREFIX, realloc) | |
52 | #define free AV_JOIN(MALLOC_PREFIX, free) | |
53 | ||
54 | void *malloc(size_t size); | |
55 | void *memalign(size_t align, size_t size); | |
56 | int posix_memalign(void **ptr, size_t align, size_t size); | |
57 | void *realloc(void *ptr, size_t size); | |
58 | void free(void *ptr); | |
59 | ||
60 | #endif /* MALLOC_PREFIX */ | |
61 | ||
62 | #define ALIGN (HAVE_AVX ? 32 : 16) | |
63 | ||
64 | /* NOTE: if you want to override these functions with your own | |
65 | * implementations (not recommended) you have to link libav* as | |
66 | * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags. | |
67 | * Note that this will cost performance. */ | |
68 | ||
69 | static size_t max_alloc_size= INT_MAX; | |
70 | ||
71 | void av_max_alloc(size_t max){ | |
72 | max_alloc_size = max; | |
73 | } | |
74 | ||
75 | void *av_malloc(size_t size) | |
76 | { | |
77 | void *ptr = NULL; | |
78 | #if CONFIG_MEMALIGN_HACK | |
79 | long diff; | |
80 | #endif | |
81 | ||
82 | /* let's disallow possibly ambiguous cases */ | |
83 | if (size > (max_alloc_size - 32)) | |
84 | return NULL; | |
85 | ||
86 | #if CONFIG_MEMALIGN_HACK | |
87 | ptr = malloc(size + ALIGN); | |
88 | if (!ptr) | |
89 | return ptr; | |
90 | diff = ((~(long)ptr)&(ALIGN - 1)) + 1; | |
91 | ptr = (char *)ptr + diff; | |
92 | ((char *)ptr)[-1] = diff; | |
93 | #elif HAVE_POSIX_MEMALIGN | |
94 | if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation | |
95 | if (posix_memalign(&ptr, ALIGN, size)) | |
96 | ptr = NULL; | |
97 | #elif HAVE_ALIGNED_MALLOC | |
98 | ptr = _aligned_malloc(size, ALIGN); | |
99 | #elif HAVE_MEMALIGN | |
100 | #ifndef __DJGPP__ | |
101 | ptr = memalign(ALIGN, size); | |
102 | #else | |
103 | ptr = memalign(size, ALIGN); | |
104 | #endif | |
105 | /* Why 64? | |
106 | * Indeed, we should align it: | |
107 | * on 4 for 386 | |
108 | * on 16 for 486 | |
109 | * on 32 for 586, PPro - K6-III | |
110 | * on 64 for K7 (maybe for P3 too). | |
111 | * Because L1 and L2 caches are aligned on those values. | |
112 | * But I don't want to code such logic here! | |
113 | */ | |
114 | /* Why 32? | |
115 | * For AVX ASM. SSE / NEON needs only 16. | |
116 | * Why not larger? Because I did not see a difference in benchmarks ... | |
117 | */ | |
118 | /* benchmarks with P3 | |
119 | * memalign(64) + 1 3071, 3051, 3032 | |
120 | * memalign(64) + 2 3051, 3032, 3041 | |
121 | * memalign(64) + 4 2911, 2896, 2915 | |
122 | * memalign(64) + 8 2545, 2554, 2550 | |
123 | * memalign(64) + 16 2543, 2572, 2563 | |
124 | * memalign(64) + 32 2546, 2545, 2571 | |
125 | * memalign(64) + 64 2570, 2533, 2558 | |
126 | * | |
127 | * BTW, malloc seems to do 8-byte alignment by default here. | |
128 | */ | |
129 | #else | |
130 | ptr = malloc(size); | |
131 | #endif | |
132 | if(!ptr && !size) { | |
133 | size = 1; | |
134 | ptr= av_malloc(1); | |
135 | } | |
136 | #if CONFIG_MEMORY_POISONING | |
137 | if (ptr) | |
138 | memset(ptr, FF_MEMORY_POISON, size); | |
139 | #endif | |
140 | return ptr; | |
141 | } | |
142 | ||
143 | void *av_realloc(void *ptr, size_t size) | |
144 | { | |
145 | #if CONFIG_MEMALIGN_HACK | |
146 | int diff; | |
147 | #endif | |
148 | ||
149 | /* let's disallow possibly ambiguous cases */ | |
150 | if (size > (max_alloc_size - 32)) | |
151 | return NULL; | |
152 | ||
153 | #if CONFIG_MEMALIGN_HACK | |
154 | //FIXME this isn't aligned correctly, though it probably isn't needed | |
155 | if (!ptr) | |
156 | return av_malloc(size); | |
157 | diff = ((char *)ptr)[-1]; | |
158 | av_assert0(diff>0 && diff<=ALIGN); | |
159 | ptr = realloc((char *)ptr - diff, size + diff); | |
160 | if (ptr) | |
161 | ptr = (char *)ptr + diff; | |
162 | return ptr; | |
163 | #elif HAVE_ALIGNED_MALLOC | |
164 | return _aligned_realloc(ptr, size + !size, ALIGN); | |
165 | #else | |
166 | return realloc(ptr, size + !size); | |
167 | #endif | |
168 | } | |
169 | ||
170 | void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) | |
171 | { | |
172 | size_t size; | |
173 | void *r; | |
174 | ||
175 | if (av_size_mult(elsize, nelem, &size)) { | |
176 | av_free(ptr); | |
177 | return NULL; | |
178 | } | |
179 | r = av_realloc(ptr, size); | |
180 | if (!r && size) | |
181 | av_free(ptr); | |
182 | return r; | |
183 | } | |
184 | ||
185 | int av_reallocp(void *ptr, size_t size) | |
186 | { | |
187 | void **ptrptr = ptr; | |
188 | void *ret; | |
189 | ||
190 | if (!size) { | |
191 | av_freep(ptr); | |
192 | return 0; | |
193 | } | |
194 | ret = av_realloc(*ptrptr, size); | |
195 | ||
196 | if (!ret) { | |
197 | av_freep(ptr); | |
198 | return AVERROR(ENOMEM); | |
199 | } | |
200 | ||
201 | *ptrptr = ret; | |
202 | return 0; | |
203 | } | |
204 | ||
205 | void *av_realloc_array(void *ptr, size_t nmemb, size_t size) | |
206 | { | |
207 | if (!size || nmemb >= INT_MAX / size) | |
208 | return NULL; | |
209 | return av_realloc(ptr, nmemb * size); | |
210 | } | |
211 | ||
212 | int av_reallocp_array(void *ptr, size_t nmemb, size_t size) | |
213 | { | |
214 | void **ptrptr = ptr; | |
215 | *ptrptr = av_realloc_f(*ptrptr, nmemb, size); | |
216 | if (!*ptrptr && nmemb && size) | |
217 | return AVERROR(ENOMEM); | |
218 | return 0; | |
219 | } | |
220 | ||
221 | void av_free(void *ptr) | |
222 | { | |
223 | #if CONFIG_MEMALIGN_HACK | |
224 | if (ptr) { | |
225 | int v= ((char *)ptr)[-1]; | |
226 | av_assert0(v>0 && v<=ALIGN); | |
227 | free((char *)ptr - v); | |
228 | } | |
229 | #elif HAVE_ALIGNED_MALLOC | |
230 | _aligned_free(ptr); | |
231 | #else | |
232 | free(ptr); | |
233 | #endif | |
234 | } | |
235 | ||
236 | void av_freep(void *arg) | |
237 | { | |
238 | void **ptr = (void **)arg; | |
239 | av_free(*ptr); | |
240 | *ptr = NULL; | |
241 | } | |
242 | ||
243 | void *av_mallocz(size_t size) | |
244 | { | |
245 | void *ptr = av_malloc(size); | |
246 | if (ptr) | |
247 | memset(ptr, 0, size); | |
248 | return ptr; | |
249 | } | |
250 | ||
251 | void *av_calloc(size_t nmemb, size_t size) | |
252 | { | |
253 | if (size <= 0 || nmemb >= INT_MAX / size) | |
254 | return NULL; | |
255 | return av_mallocz(nmemb * size); | |
256 | } | |
257 | ||
258 | char *av_strdup(const char *s) | |
259 | { | |
260 | char *ptr = NULL; | |
261 | if (s) { | |
262 | int len = strlen(s) + 1; | |
263 | ptr = av_realloc(NULL, len); | |
264 | if (ptr) | |
265 | memcpy(ptr, s, len); | |
266 | } | |
267 | return ptr; | |
268 | } | |
269 | ||
270 | char *av_strndup(const char *s, size_t len) | |
271 | { | |
272 | char *ret = NULL, *end; | |
273 | ||
274 | if (!s) | |
275 | return NULL; | |
276 | ||
277 | end = memchr(s, 0, len); | |
278 | if (end) | |
279 | len = end - s; | |
280 | ||
281 | ret = av_realloc(NULL, len + 1); | |
282 | if (!ret) | |
283 | return NULL; | |
284 | ||
285 | memcpy(ret, s, len); | |
286 | ret[len] = 0; | |
287 | return ret; | |
288 | } | |
289 | ||
290 | void *av_memdup(const void *p, size_t size) | |
291 | { | |
292 | void *ptr = NULL; | |
293 | if (p) { | |
294 | ptr = av_malloc(size); | |
295 | if (ptr) | |
296 | memcpy(ptr, p, size); | |
297 | } | |
298 | return ptr; | |
299 | } | |
300 | ||
301 | int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem) | |
302 | { | |
303 | void **tab = *(void ***)tab_ptr; | |
304 | ||
305 | AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { | |
306 | tab[*nb_ptr] = elem; | |
307 | *(void ***)tab_ptr = tab; | |
308 | }, { | |
309 | return AVERROR(ENOMEM); | |
310 | }); | |
311 | return 0; | |
312 | } | |
313 | ||
314 | void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem) | |
315 | { | |
316 | void **tab = *(void ***)tab_ptr; | |
317 | ||
318 | AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { | |
319 | tab[*nb_ptr] = elem; | |
320 | *(void ***)tab_ptr = tab; | |
321 | }, { | |
322 | *nb_ptr = 0; | |
323 | av_freep(tab_ptr); | |
324 | }); | |
325 | } | |
326 | ||
327 | void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, | |
328 | const uint8_t *elem_data) | |
329 | { | |
330 | uint8_t *tab_elem_data = NULL; | |
331 | ||
332 | AV_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, { | |
333 | tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size; | |
334 | if (elem_data) | |
335 | memcpy(tab_elem_data, elem_data, elem_size); | |
336 | else if (CONFIG_MEMORY_POISONING) | |
337 | memset(tab_elem_data, FF_MEMORY_POISON, elem_size); | |
338 | }, { | |
339 | av_freep(tab_ptr); | |
340 | *nb_ptr = 0; | |
341 | }); | |
342 | return tab_elem_data; | |
343 | } | |
344 | ||
345 | static void fill16(uint8_t *dst, int len) | |
346 | { | |
347 | uint32_t v = AV_RN16(dst - 2); | |
348 | ||
349 | v |= v << 16; | |
350 | ||
351 | while (len >= 4) { | |
352 | AV_WN32(dst, v); | |
353 | dst += 4; | |
354 | len -= 4; | |
355 | } | |
356 | ||
357 | while (len--) { | |
358 | *dst = dst[-2]; | |
359 | dst++; | |
360 | } | |
361 | } | |
362 | ||
363 | static void fill24(uint8_t *dst, int len) | |
364 | { | |
365 | #if HAVE_BIGENDIAN | |
366 | uint32_t v = AV_RB24(dst - 3); | |
367 | uint32_t a = v << 8 | v >> 16; | |
368 | uint32_t b = v << 16 | v >> 8; | |
369 | uint32_t c = v << 24 | v; | |
370 | #else | |
371 | uint32_t v = AV_RL24(dst - 3); | |
372 | uint32_t a = v | v << 24; | |
373 | uint32_t b = v >> 8 | v << 16; | |
374 | uint32_t c = v >> 16 | v << 8; | |
375 | #endif | |
376 | ||
377 | while (len >= 12) { | |
378 | AV_WN32(dst, a); | |
379 | AV_WN32(dst + 4, b); | |
380 | AV_WN32(dst + 8, c); | |
381 | dst += 12; | |
382 | len -= 12; | |
383 | } | |
384 | ||
385 | if (len >= 4) { | |
386 | AV_WN32(dst, a); | |
387 | dst += 4; | |
388 | len -= 4; | |
389 | } | |
390 | ||
391 | if (len >= 4) { | |
392 | AV_WN32(dst, b); | |
393 | dst += 4; | |
394 | len -= 4; | |
395 | } | |
396 | ||
397 | while (len--) { | |
398 | *dst = dst[-3]; | |
399 | dst++; | |
400 | } | |
401 | } | |
402 | ||
403 | static void fill32(uint8_t *dst, int len) | |
404 | { | |
405 | uint32_t v = AV_RN32(dst - 4); | |
406 | ||
407 | while (len >= 4) { | |
408 | AV_WN32(dst, v); | |
409 | dst += 4; | |
410 | len -= 4; | |
411 | } | |
412 | ||
413 | while (len--) { | |
414 | *dst = dst[-4]; | |
415 | dst++; | |
416 | } | |
417 | } | |
418 | ||
419 | void av_memcpy_backptr(uint8_t *dst, int back, int cnt) | |
420 | { | |
421 | const uint8_t *src = &dst[-back]; | |
422 | if (!back) | |
423 | return; | |
424 | ||
425 | if (back == 1) { | |
426 | memset(dst, *src, cnt); | |
427 | } else if (back == 2) { | |
428 | fill16(dst, cnt); | |
429 | } else if (back == 3) { | |
430 | fill24(dst, cnt); | |
431 | } else if (back == 4) { | |
432 | fill32(dst, cnt); | |
433 | } else { | |
434 | if (cnt >= 16) { | |
435 | int blocklen = back; | |
436 | while (cnt > blocklen) { | |
437 | memcpy(dst, src, blocklen); | |
438 | dst += blocklen; | |
439 | cnt -= blocklen; | |
440 | blocklen <<= 1; | |
441 | } | |
442 | memcpy(dst, src, cnt); | |
443 | return; | |
444 | } | |
445 | if (cnt >= 8) { | |
446 | AV_COPY32U(dst, src); | |
447 | AV_COPY32U(dst + 4, src + 4); | |
448 | src += 8; | |
449 | dst += 8; | |
450 | cnt -= 8; | |
451 | } | |
452 | if (cnt >= 4) { | |
453 | AV_COPY32U(dst, src); | |
454 | src += 4; | |
455 | dst += 4; | |
456 | cnt -= 4; | |
457 | } | |
458 | if (cnt >= 2) { | |
459 | AV_COPY16U(dst, src); | |
460 | src += 2; | |
461 | dst += 2; | |
462 | cnt -= 2; | |
463 | } | |
464 | if (cnt) | |
465 | *dst = *src; | |
466 | } | |
467 | } | |
468 | ||
469 | void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) | |
470 | { | |
471 | if (min_size < *size) | |
472 | return ptr; | |
473 | ||
474 | min_size = FFMAX(17 * min_size / 16 + 32, min_size); | |
475 | ||
476 | ptr = av_realloc(ptr, min_size); | |
477 | /* we could set this to the unmodified min_size but this is safer | |
478 | * if the user lost the ptr and uses NULL now | |
479 | */ | |
480 | if (!ptr) | |
481 | min_size = 0; | |
482 | ||
483 | *size = min_size; | |
484 | ||
485 | return ptr; | |
486 | } | |
487 | ||
488 | static inline int ff_fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc) | |
489 | { | |
490 | void **p = ptr; | |
491 | if (min_size < *size) | |
492 | return 0; | |
493 | min_size = FFMAX(17 * min_size / 16 + 32, min_size); | |
494 | av_free(*p); | |
495 | *p = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size); | |
496 | if (!*p) | |
497 | min_size = 0; | |
498 | *size = min_size; | |
499 | return 1; | |
500 | } | |
501 | ||
502 | void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size) | |
503 | { | |
504 | ff_fast_malloc(ptr, size, min_size, 0); | |
505 | } | |
506 |