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 <stdatomic.h>
35 #include <string.h>
36 #if HAVE_MALLOC_H
37 #include <malloc.h>
38 #endif
39
40 #include "attributes.h"
41 #include "avassert.h"
42 #include "dynarray.h"
43 #include "error.h"
44 #include "internal.h"
45 #include "intreadwrite.h"
46 #include "macros.h"
47 #include "mem.h"
48
49 #ifdef MALLOC_PREFIX
50
51 #define malloc AV_JOIN(MALLOC_PREFIX, malloc)
52 #define memalign AV_JOIN(MALLOC_PREFIX, memalign)
53 #define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign)
54 #define realloc AV_JOIN(MALLOC_PREFIX, realloc)
55 #define free AV_JOIN(MALLOC_PREFIX, free)
56
57 void *malloc(size_t size);
58 void *memalign(size_t align, size_t size);
59 int posix_memalign(void **ptr, size_t align, size_t size);
60 void *realloc(void *ptr, size_t size);
61 void free(void *ptr);
62
63 #endif /* MALLOC_PREFIX */
64
65 #define ALIGN (HAVE_AVX512 ? 64 : (HAVE_AVX ? 32 : 16))
66
67 /* NOTE: if you want to override these functions with your own
68 * implementations (not recommended) you have to link libav* as
69 * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags.
70 * Note that this will cost performance. */
71
72 static atomic_size_t max_alloc_size = ATOMIC_VAR_INIT(INT_MAX);
73
av_max_alloc(size_t max)74 void av_max_alloc(size_t max){
75 atomic_store_explicit(&max_alloc_size, max, memory_order_relaxed);
76 }
77
size_mult(size_t a,size_t b,size_t * r)78 static int size_mult(size_t a, size_t b, size_t *r)
79 {
80 size_t t;
81
82 #if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_mul_overflow)
83 if (__builtin_mul_overflow(a, b, &t))
84 return AVERROR(EINVAL);
85 #else
86 t = a * b;
87 /* Hack inspired from glibc: don't try the division if nelem and elsize
88 * are both less than sqrt(SIZE_MAX). */
89 if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b)
90 return AVERROR(EINVAL);
91 #endif
92 *r = t;
93 return 0;
94 }
95
av_malloc(size_t size)96 void *av_malloc(size_t size)
97 {
98 void *ptr = NULL;
99
100 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
101 return NULL;
102
103 #if HAVE_POSIX_MEMALIGN
104 if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
105 if (posix_memalign(&ptr, ALIGN, size))
106 ptr = NULL;
107 #elif HAVE_ALIGNED_MALLOC
108 ptr = _aligned_malloc(size, ALIGN);
109 #elif HAVE_MEMALIGN
110 #ifndef __DJGPP__
111 ptr = memalign(ALIGN, size);
112 #else
113 ptr = memalign(size, ALIGN);
114 #endif
115 /* Why 64?
116 * Indeed, we should align it:
117 * on 4 for 386
118 * on 16 for 486
119 * on 32 for 586, PPro - K6-III
120 * on 64 for K7 (maybe for P3 too).
121 * Because L1 and L2 caches are aligned on those values.
122 * But I don't want to code such logic here!
123 */
124 /* Why 32?
125 * For AVX ASM. SSE / NEON needs only 16.
126 * Why not larger? Because I did not see a difference in benchmarks ...
127 */
128 /* benchmarks with P3
129 * memalign(64) + 1 3071, 3051, 3032
130 * memalign(64) + 2 3051, 3032, 3041
131 * memalign(64) + 4 2911, 2896, 2915
132 * memalign(64) + 8 2545, 2554, 2550
133 * memalign(64) + 16 2543, 2572, 2563
134 * memalign(64) + 32 2546, 2545, 2571
135 * memalign(64) + 64 2570, 2533, 2558
136 *
137 * BTW, malloc seems to do 8-byte alignment by default here.
138 */
139 #else
140 ptr = malloc(size);
141 #endif
142 if(!ptr && !size) {
143 size = 1;
144 ptr= av_malloc(1);
145 }
146 #if CONFIG_MEMORY_POISONING
147 if (ptr)
148 memset(ptr, FF_MEMORY_POISON, size);
149 #endif
150 return ptr;
151 }
152
av_realloc(void * ptr,size_t size)153 void *av_realloc(void *ptr, size_t size)
154 {
155 void *ret;
156 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
157 return NULL;
158
159 #if HAVE_ALIGNED_MALLOC
160 ret = _aligned_realloc(ptr, size + !size, ALIGN);
161 #else
162 ret = realloc(ptr, size + !size);
163 #endif
164 #if CONFIG_MEMORY_POISONING
165 if (ret && !ptr)
166 memset(ret, FF_MEMORY_POISON, size);
167 #endif
168 return ret;
169 }
170
av_realloc_f(void * ptr,size_t nelem,size_t elsize)171 void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
172 {
173 size_t size;
174 void *r;
175
176 if (size_mult(elsize, nelem, &size)) {
177 av_free(ptr);
178 return NULL;
179 }
180 r = av_realloc(ptr, size);
181 if (!r)
182 av_free(ptr);
183 return r;
184 }
185
av_reallocp(void * ptr,size_t size)186 int av_reallocp(void *ptr, size_t size)
187 {
188 void *val;
189
190 if (!size) {
191 av_freep(ptr);
192 return 0;
193 }
194
195 memcpy(&val, ptr, sizeof(val));
196 val = av_realloc(val, size);
197
198 if (!val) {
199 av_freep(ptr);
200 return AVERROR(ENOMEM);
201 }
202
203 memcpy(ptr, &val, sizeof(val));
204 return 0;
205 }
206
av_malloc_array(size_t nmemb,size_t size)207 void *av_malloc_array(size_t nmemb, size_t size)
208 {
209 size_t result;
210 if (size_mult(nmemb, size, &result) < 0)
211 return NULL;
212 return av_malloc(result);
213 }
214
215 #if FF_API_AV_MALLOCZ_ARRAY
av_mallocz_array(size_t nmemb,size_t size)216 void *av_mallocz_array(size_t nmemb, size_t size)
217 {
218 size_t result;
219 if (size_mult(nmemb, size, &result) < 0)
220 return NULL;
221 return av_mallocz(result);
222 }
223 #endif
224
av_realloc_array(void * ptr,size_t nmemb,size_t size)225 void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
226 {
227 size_t result;
228 if (size_mult(nmemb, size, &result) < 0)
229 return NULL;
230 return av_realloc(ptr, result);
231 }
232
av_reallocp_array(void * ptr,size_t nmemb,size_t size)233 int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
234 {
235 void *val;
236
237 memcpy(&val, ptr, sizeof(val));
238 val = av_realloc_f(val, nmemb, size);
239 memcpy(ptr, &val, sizeof(val));
240 if (!val && nmemb && size)
241 return AVERROR(ENOMEM);
242
243 return 0;
244 }
245
av_free(void * ptr)246 void av_free(void *ptr)
247 {
248 #if HAVE_ALIGNED_MALLOC
249 _aligned_free(ptr);
250 #else
251 free(ptr);
252 #endif
253 }
254
av_freep(void * arg)255 void av_freep(void *arg)
256 {
257 void *val;
258
259 memcpy(&val, arg, sizeof(val));
260 memcpy(arg, &(void *){ NULL }, sizeof(val));
261 av_free(val);
262 }
263
av_mallocz(size_t size)264 void *av_mallocz(size_t size)
265 {
266 void *ptr = av_malloc(size);
267 if (ptr)
268 memset(ptr, 0, size);
269 return ptr;
270 }
271
av_calloc(size_t nmemb,size_t size)272 void *av_calloc(size_t nmemb, size_t size)
273 {
274 size_t result;
275 if (size_mult(nmemb, size, &result) < 0)
276 return NULL;
277 return av_mallocz(result);
278 }
279
av_strdup(const char * s)280 char *av_strdup(const char *s)
281 {
282 char *ptr = NULL;
283 if (s) {
284 size_t len = strlen(s) + 1;
285 ptr = av_realloc(NULL, len);
286 if (ptr)
287 memcpy(ptr, s, len);
288 }
289 return ptr;
290 }
291
av_strndup(const char * s,size_t len)292 char *av_strndup(const char *s, size_t len)
293 {
294 char *ret = NULL, *end;
295
296 if (!s)
297 return NULL;
298
299 end = memchr(s, 0, len);
300 if (end)
301 len = end - s;
302
303 ret = av_realloc(NULL, len + 1);
304 if (!ret)
305 return NULL;
306
307 memcpy(ret, s, len);
308 ret[len] = 0;
309 return ret;
310 }
311
av_memdup(const void * p,size_t size)312 void *av_memdup(const void *p, size_t size)
313 {
314 void *ptr = NULL;
315 if (p) {
316 ptr = av_malloc(size);
317 if (ptr)
318 memcpy(ptr, p, size);
319 }
320 return ptr;
321 }
322
av_dynarray_add_nofree(void * tab_ptr,int * nb_ptr,void * elem)323 int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
324 {
325 void **tab;
326 memcpy(&tab, tab_ptr, sizeof(tab));
327
328 FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
329 tab[*nb_ptr] = elem;
330 memcpy(tab_ptr, &tab, sizeof(tab));
331 }, {
332 return AVERROR(ENOMEM);
333 });
334 return 0;
335 }
336
av_dynarray_add(void * tab_ptr,int * nb_ptr,void * elem)337 void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
338 {
339 void **tab;
340 memcpy(&tab, tab_ptr, sizeof(tab));
341
342 FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
343 tab[*nb_ptr] = elem;
344 memcpy(tab_ptr, &tab, sizeof(tab));
345 }, {
346 *nb_ptr = 0;
347 av_freep(tab_ptr);
348 });
349 }
350
av_dynarray2_add(void ** tab_ptr,int * nb_ptr,size_t elem_size,const uint8_t * elem_data)351 void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
352 const uint8_t *elem_data)
353 {
354 uint8_t *tab_elem_data = NULL;
355
356 FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
357 tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
358 if (elem_data)
359 memcpy(tab_elem_data, elem_data, elem_size);
360 else if (CONFIG_MEMORY_POISONING)
361 memset(tab_elem_data, FF_MEMORY_POISON, elem_size);
362 }, {
363 av_freep(tab_ptr);
364 *nb_ptr = 0;
365 });
366 return tab_elem_data;
367 }
368
fill16(uint8_t * dst,int len)369 static void fill16(uint8_t *dst, int len)
370 {
371 uint32_t v = AV_RN16(dst - 2);
372
373 v |= v << 16;
374
375 while (len >= 4) {
376 AV_WN32(dst, v);
377 dst += 4;
378 len -= 4;
379 }
380
381 while (len--) {
382 *dst = dst[-2];
383 dst++;
384 }
385 }
386
fill24(uint8_t * dst,int len)387 static void fill24(uint8_t *dst, int len)
388 {
389 #if HAVE_BIGENDIAN
390 uint32_t v = AV_RB24(dst - 3);
391 uint32_t a = v << 8 | v >> 16;
392 uint32_t b = v << 16 | v >> 8;
393 uint32_t c = v << 24 | v;
394 #else
395 uint32_t v = AV_RL24(dst - 3);
396 uint32_t a = v | v << 24;
397 uint32_t b = v >> 8 | v << 16;
398 uint32_t c = v >> 16 | v << 8;
399 #endif
400
401 while (len >= 12) {
402 AV_WN32(dst, a);
403 AV_WN32(dst + 4, b);
404 AV_WN32(dst + 8, c);
405 dst += 12;
406 len -= 12;
407 }
408
409 if (len >= 4) {
410 AV_WN32(dst, a);
411 dst += 4;
412 len -= 4;
413 }
414
415 if (len >= 4) {
416 AV_WN32(dst, b);
417 dst += 4;
418 len -= 4;
419 }
420
421 while (len--) {
422 *dst = dst[-3];
423 dst++;
424 }
425 }
426
fill32(uint8_t * dst,int len)427 static void fill32(uint8_t *dst, int len)
428 {
429 uint32_t v = AV_RN32(dst - 4);
430
431 #if HAVE_FAST_64BIT
432 uint64_t v2= v + ((uint64_t)v<<32);
433 while (len >= 32) {
434 AV_WN64(dst , v2);
435 AV_WN64(dst+ 8, v2);
436 AV_WN64(dst+16, v2);
437 AV_WN64(dst+24, v2);
438 dst += 32;
439 len -= 32;
440 }
441 #endif
442
443 while (len >= 4) {
444 AV_WN32(dst, v);
445 dst += 4;
446 len -= 4;
447 }
448
449 while (len--) {
450 *dst = dst[-4];
451 dst++;
452 }
453 }
454
av_memcpy_backptr(uint8_t * dst,int back,int cnt)455 void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
456 {
457 const uint8_t *src = &dst[-back];
458 if (!back)
459 return;
460
461 if (back == 1) {
462 memset(dst, *src, cnt);
463 } else if (back == 2) {
464 fill16(dst, cnt);
465 } else if (back == 3) {
466 fill24(dst, cnt);
467 } else if (back == 4) {
468 fill32(dst, cnt);
469 } else {
470 if (cnt >= 16) {
471 int blocklen = back;
472 while (cnt > blocklen) {
473 memcpy(dst, src, blocklen);
474 dst += blocklen;
475 cnt -= blocklen;
476 blocklen <<= 1;
477 }
478 memcpy(dst, src, cnt);
479 return;
480 }
481 if (cnt >= 8) {
482 AV_COPY32U(dst, src);
483 AV_COPY32U(dst + 4, src + 4);
484 src += 8;
485 dst += 8;
486 cnt -= 8;
487 }
488 if (cnt >= 4) {
489 AV_COPY32U(dst, src);
490 src += 4;
491 dst += 4;
492 cnt -= 4;
493 }
494 if (cnt >= 2) {
495 AV_COPY16U(dst, src);
496 src += 2;
497 dst += 2;
498 cnt -= 2;
499 }
500 if (cnt)
501 *dst = *src;
502 }
503 }
504
av_fast_realloc(void * ptr,unsigned int * size,size_t min_size)505 void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
506 {
507 size_t max_size;
508
509 if (min_size <= *size)
510 return ptr;
511
512 max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
513 /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
514 max_size = FFMIN(max_size, UINT_MAX);
515
516 if (min_size > max_size) {
517 *size = 0;
518 return NULL;
519 }
520
521 min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
522
523 ptr = av_realloc(ptr, min_size);
524 /* we could set this to the unmodified min_size but this is safer
525 * if the user lost the ptr and uses NULL now
526 */
527 if (!ptr)
528 min_size = 0;
529
530 *size = min_size;
531
532 return ptr;
533 }
534
fast_malloc(void * ptr,unsigned int * size,size_t min_size,int zero_realloc)535 static inline void fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
536 {
537 size_t max_size;
538 void *val;
539
540 memcpy(&val, ptr, sizeof(val));
541 if (min_size <= *size) {
542 av_assert0(val || !min_size);
543 return;
544 }
545
546 max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
547 /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
548 max_size = FFMIN(max_size, UINT_MAX);
549
550 if (min_size > max_size) {
551 av_freep(ptr);
552 *size = 0;
553 return;
554 }
555 min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
556 av_freep(ptr);
557 val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
558 memcpy(ptr, &val, sizeof(val));
559 if (!val)
560 min_size = 0;
561 *size = min_size;
562 return;
563 }
564
av_fast_malloc(void * ptr,unsigned int * size,size_t min_size)565 void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
566 {
567 fast_malloc(ptr, size, min_size, 0);
568 }
569
av_fast_mallocz(void * ptr,unsigned int * size,size_t min_size)570 void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
571 {
572 fast_malloc(ptr, size, min_size, 1);
573 }
574
av_size_mult(size_t a,size_t b,size_t * r)575 int av_size_mult(size_t a, size_t b, size_t *r)
576 {
577 return size_mult(a, b, r);
578 }
579