Bug 1874684 - Part 28: Return DateDuration from DifferenceISODateTime. r=mgaudet
[gecko.git] / media / ffvpx / libavutil / mem.c
blob36b8940a0cf5c95608ac23a99af1e6371faafbc9
1 /*
2 * default memory allocator for libavutil
3 * Copyright (c) 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
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.
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.
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
22 /**
23 * @file
24 * default memory allocator for libavutil
27 #define _XOPEN_SOURCE 600
29 #include "config.h"
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
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"
49 #ifdef MALLOC_PREFIX
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)
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);
63 #endif /* MALLOC_PREFIX */
65 #define ALIGN (HAVE_AVX512 ? 64 : (HAVE_AVX ? 32 : 16))
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. */
72 static atomic_size_t max_alloc_size = ATOMIC_VAR_INIT(INT_MAX);
74 void av_max_alloc(size_t max){
75 atomic_store_explicit(&max_alloc_size, max, memory_order_relaxed);
78 static int size_mult(size_t a, size_t b, size_t *r)
80 size_t t;
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;
96 void *av_malloc(size_t size)
98 void *ptr = NULL;
100 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
101 return NULL;
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!
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 ...
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
137 * BTW, malloc seems to do 8-byte alignment by default here.
139 #else
140 ptr = malloc(size);
141 #endif
142 if(!ptr && !size) {
143 size = 1;
144 ptr= av_malloc(1);
146 #if CONFIG_MEMORY_POISONING
147 if (ptr)
148 memset(ptr, FF_MEMORY_POISON, size);
149 #endif
150 return ptr;
153 void *av_realloc(void *ptr, size_t size)
155 void *ret;
156 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
157 return NULL;
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;
171 void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
173 size_t size;
174 void *r;
176 if (size_mult(elsize, nelem, &size)) {
177 av_free(ptr);
178 return NULL;
180 r = av_realloc(ptr, size);
181 if (!r)
182 av_free(ptr);
183 return r;
186 int av_reallocp(void *ptr, size_t size)
188 void *val;
190 if (!size) {
191 av_freep(ptr);
192 return 0;
195 memcpy(&val, ptr, sizeof(val));
196 val = av_realloc(val, size);
198 if (!val) {
199 av_freep(ptr);
200 return AVERROR(ENOMEM);
203 memcpy(ptr, &val, sizeof(val));
204 return 0;
207 void *av_malloc_array(size_t nmemb, size_t size)
209 size_t result;
210 if (size_mult(nmemb, size, &result) < 0)
211 return NULL;
212 return av_malloc(result);
215 void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
217 size_t result;
218 if (size_mult(nmemb, size, &result) < 0)
219 return NULL;
220 return av_realloc(ptr, result);
223 int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
225 void *val;
227 memcpy(&val, ptr, sizeof(val));
228 val = av_realloc_f(val, nmemb, size);
229 memcpy(ptr, &val, sizeof(val));
230 if (!val && nmemb && size)
231 return AVERROR(ENOMEM);
233 return 0;
236 void av_free(void *ptr)
238 #if HAVE_ALIGNED_MALLOC
239 _aligned_free(ptr);
240 #else
241 free(ptr);
242 #endif
245 void av_freep(void *arg)
247 void *val;
249 memcpy(&val, arg, sizeof(val));
250 memcpy(arg, &(void *){ NULL }, sizeof(val));
251 av_free(val);
254 void *av_mallocz(size_t size)
256 void *ptr = av_malloc(size);
257 if (ptr)
258 memset(ptr, 0, size);
259 return ptr;
262 void *av_calloc(size_t nmemb, size_t size)
264 size_t result;
265 if (size_mult(nmemb, size, &result) < 0)
266 return NULL;
267 return av_mallocz(result);
270 char *av_strdup(const char *s)
272 char *ptr = NULL;
273 if (s) {
274 size_t len = strlen(s) + 1;
275 ptr = av_realloc(NULL, len);
276 if (ptr)
277 memcpy(ptr, s, len);
279 return ptr;
282 char *av_strndup(const char *s, size_t len)
284 char *ret = NULL, *end;
286 if (!s)
287 return NULL;
289 end = memchr(s, 0, len);
290 if (end)
291 len = end - s;
293 ret = av_realloc(NULL, len + 1);
294 if (!ret)
295 return NULL;
297 memcpy(ret, s, len);
298 ret[len] = 0;
299 return ret;
302 void *av_memdup(const void *p, size_t size)
304 void *ptr = NULL;
305 if (p) {
306 ptr = av_malloc(size);
307 if (ptr)
308 memcpy(ptr, p, size);
310 return ptr;
313 int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
315 void **tab;
316 memcpy(&tab, tab_ptr, sizeof(tab));
318 FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
319 tab[*nb_ptr] = elem;
320 memcpy(tab_ptr, &tab, sizeof(tab));
321 }, {
322 return AVERROR(ENOMEM);
324 return 0;
327 void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
329 void **tab;
330 memcpy(&tab, tab_ptr, sizeof(tab));
332 FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
333 tab[*nb_ptr] = elem;
334 memcpy(tab_ptr, &tab, sizeof(tab));
335 }, {
336 *nb_ptr = 0;
337 av_freep(tab_ptr);
341 void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
342 const uint8_t *elem_data)
344 uint8_t *tab_elem_data = NULL;
346 FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
347 tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
348 if (elem_data)
349 memcpy(tab_elem_data, elem_data, elem_size);
350 else if (CONFIG_MEMORY_POISONING)
351 memset(tab_elem_data, FF_MEMORY_POISON, elem_size);
352 }, {
353 av_freep(tab_ptr);
354 *nb_ptr = 0;
356 return tab_elem_data;
359 static void fill16(uint8_t *dst, int len)
361 uint32_t v = AV_RN16(dst - 2);
363 v |= v << 16;
365 while (len >= 4) {
366 AV_WN32(dst, v);
367 dst += 4;
368 len -= 4;
371 while (len--) {
372 *dst = dst[-2];
373 dst++;
377 static void fill24(uint8_t *dst, int len)
379 #if HAVE_BIGENDIAN
380 uint32_t v = AV_RB24(dst - 3);
381 uint32_t a = v << 8 | v >> 16;
382 uint32_t b = v << 16 | v >> 8;
383 uint32_t c = v << 24 | v;
384 #else
385 uint32_t v = AV_RL24(dst - 3);
386 uint32_t a = v | v << 24;
387 uint32_t b = v >> 8 | v << 16;
388 uint32_t c = v >> 16 | v << 8;
389 #endif
391 while (len >= 12) {
392 AV_WN32(dst, a);
393 AV_WN32(dst + 4, b);
394 AV_WN32(dst + 8, c);
395 dst += 12;
396 len -= 12;
399 if (len >= 4) {
400 AV_WN32(dst, a);
401 dst += 4;
402 len -= 4;
405 if (len >= 4) {
406 AV_WN32(dst, b);
407 dst += 4;
408 len -= 4;
411 while (len--) {
412 *dst = dst[-3];
413 dst++;
417 static void fill32(uint8_t *dst, int len)
419 uint32_t v = AV_RN32(dst - 4);
421 #if HAVE_FAST_64BIT
422 uint64_t v2= v + ((uint64_t)v<<32);
423 while (len >= 32) {
424 AV_WN64(dst , v2);
425 AV_WN64(dst+ 8, v2);
426 AV_WN64(dst+16, v2);
427 AV_WN64(dst+24, v2);
428 dst += 32;
429 len -= 32;
431 #endif
433 while (len >= 4) {
434 AV_WN32(dst, v);
435 dst += 4;
436 len -= 4;
439 while (len--) {
440 *dst = dst[-4];
441 dst++;
445 void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
447 const uint8_t *src = &dst[-back];
448 if (!back)
449 return;
451 if (back == 1) {
452 memset(dst, *src, cnt);
453 } else if (back == 2) {
454 fill16(dst, cnt);
455 } else if (back == 3) {
456 fill24(dst, cnt);
457 } else if (back == 4) {
458 fill32(dst, cnt);
459 } else {
460 if (cnt >= 16) {
461 int blocklen = back;
462 while (cnt > blocklen) {
463 memcpy(dst, src, blocklen);
464 dst += blocklen;
465 cnt -= blocklen;
466 blocklen <<= 1;
468 memcpy(dst, src, cnt);
469 return;
471 if (cnt >= 8) {
472 AV_COPY32U(dst, src);
473 AV_COPY32U(dst + 4, src + 4);
474 src += 8;
475 dst += 8;
476 cnt -= 8;
478 if (cnt >= 4) {
479 AV_COPY32U(dst, src);
480 src += 4;
481 dst += 4;
482 cnt -= 4;
484 if (cnt >= 2) {
485 AV_COPY16U(dst, src);
486 src += 2;
487 dst += 2;
488 cnt -= 2;
490 if (cnt)
491 *dst = *src;
495 void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
497 size_t max_size;
499 if (min_size <= *size)
500 return ptr;
502 max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
503 /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
504 max_size = FFMIN(max_size, UINT_MAX);
506 if (min_size > max_size) {
507 *size = 0;
508 return NULL;
511 min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
513 ptr = av_realloc(ptr, min_size);
514 /* we could set this to the unmodified min_size but this is safer
515 * if the user lost the ptr and uses NULL now
517 if (!ptr)
518 min_size = 0;
520 *size = min_size;
522 return ptr;
525 static inline void fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
527 size_t max_size;
528 void *val;
530 memcpy(&val, ptr, sizeof(val));
531 if (min_size <= *size) {
532 av_assert0(val || !min_size);
533 return;
536 max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
537 /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
538 max_size = FFMIN(max_size, UINT_MAX);
540 if (min_size > max_size) {
541 av_freep(ptr);
542 *size = 0;
543 return;
545 min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
546 av_freep(ptr);
547 val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
548 memcpy(ptr, &val, sizeof(val));
549 if (!val)
550 min_size = 0;
551 *size = min_size;
552 return;
555 void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
557 fast_malloc(ptr, size, min_size, 0);
560 void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
562 fast_malloc(ptr, size, min_size, 1);
565 int av_size_mult(size_t a, size_t b, size_t *r)
567 return size_mult(a, b, r);