FFmpeg
Loading...
Searching...
No Matches
mem.c
Go to the documentation of this file.
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
57void *malloc(size_t size);
58void *memalign(size_t align, size_t size);
59int posix_memalign(void **ptr, size_t align, size_t size);
60void *realloc(void *ptr, size_t size);
61void free(void *ptr);
62
63#endif /* MALLOC_PREFIX */
64
65#define ALIGN (HAVE_SIMD_ALIGN_64 ? 64 : (HAVE_SIMD_ALIGN_32 ? 32 : 16))
66
67#define FF_MEMORY_POISON 0x2a
68
69/* NOTE: if you want to override these functions with your own
70 * implementations (not recommended) you have to link libav* as
71 * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags.
72 * Note that this will cost performance. */
73
75
76void av_max_alloc(size_t max){
77 atomic_store_explicit(&max_alloc_size, max, memory_order_relaxed);
78}
79
80static int size_mult(size_t a, size_t b, size_t *r)
81{
82 size_t t;
83
84#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_mul_overflow)
85 if (__builtin_mul_overflow(a, b, &t))
86 return AVERROR(EINVAL);
87#else
88 t = a * b;
89 /* Hack inspired from glibc: don't try the division if nelem and elsize
90 * are both less than sqrt(SIZE_MAX). */
91 if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b)
92 return AVERROR(EINVAL);
93#endif
94 *r = t;
95 return 0;
96}
97
98void *av_malloc(size_t size)
99{
100 void *ptr = NULL;
101
102 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
103 return NULL;
104
105#if HAVE_POSIX_MEMALIGN
106 if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
107 if (posix_memalign(&ptr, ALIGN, size))
108 ptr = NULL;
109#elif HAVE_ALIGNED_MALLOC
110 ptr = _aligned_malloc(size, ALIGN);
111#elif HAVE_MEMALIGN
112#ifndef __DJGPP__
113 ptr = memalign(ALIGN, size);
114#else
115 ptr = memalign(size, ALIGN);
116#endif
117 /* Why 64?
118 * Indeed, we should align it:
119 * on 4 for 386
120 * on 16 for 486
121 * on 32 for 586, PPro - K6-III
122 * on 64 for K7 (maybe for P3 too).
123 * Because L1 and L2 caches are aligned on those values.
124 * But I don't want to code such logic here!
125 */
126 /* Why 32?
127 * For AVX ASM. SSE / NEON needs only 16.
128 * Why not larger? Because I did not see a difference in benchmarks ...
129 */
130 /* benchmarks with P3
131 * memalign(64) + 1 3071, 3051, 3032
132 * memalign(64) + 2 3051, 3032, 3041
133 * memalign(64) + 4 2911, 2896, 2915
134 * memalign(64) + 8 2545, 2554, 2550
135 * memalign(64) + 16 2543, 2572, 2563
136 * memalign(64) + 32 2546, 2545, 2571
137 * memalign(64) + 64 2570, 2533, 2558
138 *
139 * BTW, malloc seems to do 8-byte alignment by default here.
140 */
141#else
142 ptr = malloc(size);
143#endif
144 if(!ptr && !size) {
145 size = 1;
146 ptr= av_malloc(1);
147 }
148#if CONFIG_MEMORY_POISONING
149 if (ptr)
150 memset(ptr, FF_MEMORY_POISON, size);
151#endif
152 return ptr;
153}
154
155void *av_realloc(void *ptr, size_t size)
156{
157 void *ret;
158 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
159 return NULL;
160
161#if HAVE_ALIGNED_MALLOC
162 ret = _aligned_realloc(ptr, size + !size, ALIGN);
163#else
164 ret = realloc(ptr, size + !size);
165#endif
166#if CONFIG_MEMORY_POISONING
167 if (ret && !ptr)
168 memset(ret, FF_MEMORY_POISON, size);
169#endif
170 return ret;
171}
172
173void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
174{
175 size_t size;
176 void *r;
177
178 if (size_mult(elsize, nelem, &size)) {
179 av_free(ptr);
180 return NULL;
181 }
182 r = av_realloc(ptr, size);
183 if (!r)
184 av_free(ptr);
185 return r;
186}
187
188int av_reallocp(void *ptr, size_t size)
189{
190 void *val;
191
192 if (!size) {
193 av_freep(ptr);
194 return 0;
195 }
196
197 memcpy(&val, ptr, sizeof(val));
199
200 if (!val) {
201 av_freep(ptr);
202 return AVERROR(ENOMEM);
203 }
204
205 memcpy(ptr, &val, sizeof(val));
206 return 0;
207}
208
209void *av_malloc_array(size_t nmemb, size_t size)
210{
211 size_t result;
212 if (size_mult(nmemb, size, &result) < 0)
213 return NULL;
214 return av_malloc(result);
215}
216
217void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
218{
219 size_t result;
220 if (size_mult(nmemb, size, &result) < 0)
221 return NULL;
222 return av_realloc(ptr, result);
223}
224
225int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
226{
227 void *val;
228
229 memcpy(&val, ptr, sizeof(val));
230 val = av_realloc_f(val, nmemb, size);
231 memcpy(ptr, &val, sizeof(val));
232 if (!val && nmemb && size)
233 return AVERROR(ENOMEM);
234
235 return 0;
236}
237
238void av_free(void *ptr)
239{
240#if HAVE_ALIGNED_MALLOC
241 _aligned_free(ptr);
242#else
243 free(ptr);
244#endif
245}
246
247void av_freep(void *arg)
248{
249 void *val;
250
251 memcpy(&val, arg, sizeof(val));
252 memcpy(arg, &(void *){ NULL }, sizeof(val));
253 av_free(val);
254}
255
256void *av_mallocz(size_t size)
257{
258 void *ptr = av_malloc(size);
259 if (ptr)
260 memset(ptr, 0, size);
261 return ptr;
262}
263
264void *av_calloc(size_t nmemb, size_t size)
265{
266 size_t result;
267 if (size_mult(nmemb, size, &result) < 0)
268 return NULL;
269 return av_mallocz(result);
270}
271
272char *av_strdup(const char *s)
273{
274 char *ptr = NULL;
275 if (s) {
276 size_t len = strlen(s) + 1;
277 ptr = av_realloc(NULL, len);
278 if (ptr)
279 memcpy(ptr, s, len);
280 }
281 return ptr;
282}
283
284char *av_strndup(const char *s, size_t len)
285{
286 if (!s)
287 return NULL;
288
289 const char *end = memchr(s, 0, len);
290 if (end)
291 len = end - s;
292
293 char *ret = av_realloc(NULL, len + 1);
294 if (!ret)
295 return NULL;
296
297 memcpy(ret, s, len);
298 ret[len] = 0;
299 return ret;
300}
301
302void *av_memdup(const void *p, size_t size)
303{
304 void *ptr = NULL;
305 if (p) {
306 ptr = av_malloc(size);
307 if (ptr)
308 memcpy(ptr, p, size);
309 }
310 return ptr;
311}
312
313int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
314{
315 void **tab;
316 memcpy(&tab, tab_ptr, sizeof(tab));
317
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);
323 });
324 return 0;
325}
326
327void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
328{
329 void **tab;
330 memcpy(&tab, tab_ptr, sizeof(tab));
331
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);
338 });
339}
340
341void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
342 const uint8_t *elem_data)
343{
344 uint8_t *tab_elem_data = NULL;
345
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;
355 });
356 return tab_elem_data;
357}
358
359static void fill16(uint8_t *dst, int len)
360{
361 uint32_t v = AV_RN16(dst - 2);
362
363 v |= v << 16;
364
365 while (len >= 4) {
366 AV_WN32(dst, v);
367 dst += 4;
368 len -= 4;
369 }
370
371 while (len--) {
372 *dst = dst[-2];
373 dst++;
374 }
375}
376
377static void fill24(uint8_t *dst, int len)
378{
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
390
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;
397 }
398
399 if (len >= 4) {
400 AV_WN32(dst, a);
401 dst += 4;
402 len -= 4;
403 }
404
405 if (len >= 4) {
406 AV_WN32(dst, b);
407 dst += 4;
408 len -= 4;
409 }
410
411 while (len--) {
412 *dst = dst[-3];
413 dst++;
414 }
415}
416
417static void fill32(uint8_t *dst, int len)
418{
419 uint32_t v = AV_RN32(dst - 4);
420
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;
430 }
431#endif
432
433 while (len >= 4) {
434 AV_WN32(dst, v);
435 dst += 4;
436 len -= 4;
437 }
438
439 while (len--) {
440 *dst = dst[-4];
441 dst++;
442 }
443}
444
445void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
446{
447 const uint8_t *src = &dst[-back];
448 if (!back)
449 return;
450
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;
467 }
468 memcpy(dst, src, cnt);
469 return;
470 }
471 if (cnt >= 8) {
473 AV_COPY32U(dst + 4, src + 4);
474 src += 8;
475 dst += 8;
476 cnt -= 8;
477 }
478 if (cnt >= 4) {
480 src += 4;
481 dst += 4;
482 cnt -= 4;
483 }
484 if (cnt >= 2) {
486 src += 2;
487 dst += 2;
488 cnt -= 2;
489 }
490 if (cnt)
491 *dst = *src;
492 }
493}
494
495void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
496{
497 size_t max_size;
498
499 if (min_size <= *size)
500 return ptr;
501
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);
505
506 if (min_size > max_size) {
507 *size = 0;
508 return NULL;
509 }
510
511 min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
512
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
516 */
517 if (!ptr)
518 min_size = 0;
519
520 *size = min_size;
521
522 return ptr;
523}
524
525static inline void fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
526{
527 size_t max_size;
528 void *val;
529
530 memcpy(&val, ptr, sizeof(val));
531 if (min_size <= *size) {
532 av_assert0(val || !min_size);
533 return;
534 }
535
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);
539
540 if (min_size > max_size) {
541 av_freep(ptr);
542 *size = 0;
543 return;
544 }
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;
553}
554
555void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
556{
557 fast_malloc(ptr, size, min_size, 0);
558}
559
560void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
561{
562 fast_malloc(ptr, size, min_size, 1);
563}
564
565int av_size_mult(size_t a, size_t b, size_t *r)
566{
567 return size_mult(a, b, r);
568}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static double val(void *priv, double ch)
Definition aeval.c:77
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
static const uint8_t *BS_FUNC align(BSCTX *bc)
Skip bits to a byte boundary.
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
#define max(a, b)
#define atomic_load_explicit(object, order)
Definition stdatomic.h:96
#define atomic_store_explicit(object, desired, order)
Definition stdatomic.h:90
intptr_t atomic_size_t
Definition stdatomic.h:80
#define FF_DYNARRAY_ADD(av_size_max, av_elt_size, av_array, av_size, av_success, av_failure)
Add an element to a dynamic array.
Definition dynarray.h:45
error code definitions
#define AVERROR(e)
Definition error.h:45
void * av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data)
Add an element of size elem_size to a dynamic array.
Definition mem.c:341
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
Add the pointer to an element to a dynamic array.
Definition mem.c:327
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
Definition mem.c:313
void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
Allocate and clear a buffer, reusing the given one if large enough.
Definition mem.c:560
void * av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
Reallocate the given buffer if it is not large enough, otherwise do nothing.
Definition mem.c:495
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
Definition mem.c:284
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
Allocate a buffer, reusing the given one if large enough.
Definition mem.c:555
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition mem.c:217
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
Overlapping memcpy() implementation.
Definition mem.c:445
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition mem.c:188
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition mem.c:302
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
Allocate, reallocate an array through a pointer to a pointer.
Definition mem.c:225
void av_max_alloc(size_t max)
Set the maximum size that may be allocated in one block.
Definition mem.c:76
int av_size_mult(size_t a, size_t b, size_t *r)
Multiply two size_t values checking for overflow.
Definition mem.c:565
int a
#define ALIGN
Definition hashtable.c:32
#define r
Definition input.c:42
#define b
Definition input.c:43
#define AV_COPY16U(d, s)
#define AV_RL24(x)
#define AV_WN32(p, v)
#define AV_RN32(p)
#define AV_COPY32U(d, s)
#define AV_WN64(p, v)
#define AV_RN16(p)
#define AV_RB24(x)
const char * arg
Definition jacosubdec.c:65
Macro definitions for various function/variable attributes.
common internal API header
Utility Preprocessor macros.
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
#define FF_MEMORY_POISON
Definition mem.c:67
static atomic_size_t max_alloc_size
Definition mem.c:74
static void fill32(uint8_t *dst, int len)
Definition mem.c:417
static int size_mult(size_t a, size_t b, size_t *r)
Definition mem.c:80
static void fill16(uint8_t *dst, int len)
Definition mem.c:359
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
static void fill24(uint8_t *dst, int len)
Definition mem.c:377
static void fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
Definition mem.c:525
Memory handling functions.
#define av_strdup(s)
Definition ops_static.c:55
#define av_realloc(p, s)
Definition ops_static.c:54
#define av_malloc(s)
Definition ops_static.c:52
#define av_free(p)
#define av_malloc_array(a, b)
#define av_mallocz(s)
#define av_realloc_f(p, o, n)
#define av_freep(p)
#define src
Definition vp8dsp.c:248
int size
static const struct twinvq_data tab
int len
static double c[64]