Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavutil/mem.c
Line
Count
Source
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
#include "sanitizer.h"
49
50
#ifdef MALLOC_PREFIX
51
52
#define malloc         AV_JOIN(MALLOC_PREFIX, malloc)
53
#define memalign       AV_JOIN(MALLOC_PREFIX, memalign)
54
#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign)
55
#define realloc        AV_JOIN(MALLOC_PREFIX, realloc)
56
#define free           AV_JOIN(MALLOC_PREFIX, free)
57
58
void *malloc(size_t size);
59
void *memalign(size_t align, size_t size);
60
int   posix_memalign(void **ptr, size_t align, size_t size);
61
void *realloc(void *ptr, size_t size);
62
void  free(void *ptr);
63
64
#endif /* MALLOC_PREFIX */
65
66
5.74k
#define ALIGN (HAVE_SIMD_ALIGN_64 ? 64 : (HAVE_SIMD_ALIGN_32 ? 32 : 16))
67
68
#define FF_MEMORY_POISON 0x2a
69
70
static void poison_memory(void *ptr, size_t size)
71
8.61k
{
72
#if CONFIG_MEMORY_POISONING
73
    memset(ptr, FF_MEMORY_POISON, size);
74
#endif
75
8.61k
    FF_MEM_UNDEFINED(ptr, size);
76
8.61k
}
77
78
/* The LLVM ASan runtime for Windows does not intercept the _aligned_malloc
79
 * family, so the alignment slack around a block stays addressable and small
80
 * overflows go unnoticed, while the runtime shipped with Visual Studio does
81
 * intercept it. Which one is linked cannot be told at compile time, so probe
82
 * once whether the byte after an aligned allocation is poisoned and align by
83
 * hand only when it is not. */
84
#if HAVE_ASAN && HAVE_ALIGNED_MALLOC && !HAVE_POSIX_MEMALIGN && !HAVE_MEMALIGN
85
#define ASAN_ALIGNED_ALLOC 1
86
87
static int asan_aligned_alloc_needed(void)
88
{
89
    static atomic_int needed = -1;
90
    int ret = atomic_load_explicit(&needed, memory_order_relaxed);
91
92
    if (ret < 0) {
93
        uint8_t *p = _aligned_malloc(16, ALIGN);
94
        int probed = !p || !__asan_address_is_poisoned(p + 16);
95
        _aligned_free(p);
96
        /* Every block must be freed by the allocator that made it, so the
97
         * first probe to finish decides for all callers. */
98
        if (atomic_compare_exchange_strong_explicit(&needed, &ret, probed,
99
                                                    memory_order_relaxed,
100
                                                    memory_order_relaxed))
101
            ret = probed;
102
    }
103
    return ret;
104
}
105
106
typedef struct AsanAlignedHeader {
107
    void  *base;
108
    size_t size;
109
} AsanAlignedHeader;
110
111
static void *asan_aligned_malloc(size_t size)
112
{
113
    AsanAlignedHeader *hdr;
114
    uint8_t *base, *ptr;
115
    size_t total;
116
117
    if (size > SIZE_MAX - ALIGN - sizeof(*hdr))
118
        return NULL;
119
    total = size + ALIGN + sizeof(*hdr);
120
    base  = malloc(total);
121
    if (!base)
122
        return NULL;
123
    ptr = (uint8_t *)FFALIGN((uintptr_t)base + sizeof(*hdr), ALIGN);
124
    hdr = (AsanAlignedHeader *)ptr - 1;
125
    hdr->base = base;
126
    hdr->size = size;
127
    FF_ASAN_POISON(base, ptr - base);
128
    FF_ASAN_POISON(ptr + size, base + total - (ptr + size));
129
    return ptr;
130
}
131
132
static AsanAlignedHeader *asan_aligned_header(void *ptr)
133
{
134
    AsanAlignedHeader *hdr = (AsanAlignedHeader *)ptr - 1;
135
    FF_ASAN_UNPOISON(hdr, sizeof(*hdr));
136
    return hdr;
137
}
138
139
static void asan_aligned_free(void *ptr)
140
{
141
    if (ptr)
142
        free(asan_aligned_header(ptr)->base);
143
}
144
145
static void *asan_aligned_realloc(void *ptr, size_t size)
146
{
147
    AsanAlignedHeader *hdr;
148
    void *ret;
149
150
    if (!ptr)
151
        return asan_aligned_malloc(size);
152
    ret = asan_aligned_malloc(size);
153
    if (!ret)
154
        return NULL;
155
    hdr = asan_aligned_header(ptr);
156
    memcpy(ret, ptr, FFMIN(size, hdr->size));
157
    free(hdr->base);
158
    return ret;
159
}
160
#else
161
#define ASAN_ALIGNED_ALLOC 0
162
#endif
163
164
/* NOTE: if you want to override these functions with your own
165
 * implementations (not recommended) you have to link libav* as
166
 * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags.
167
 * Note that this will cost performance. */
168
169
static atomic_size_t max_alloc_size = INT_MAX;
170
171
0
void av_max_alloc(size_t max){
172
0
    atomic_store_explicit(&max_alloc_size, max, memory_order_relaxed);
173
0
}
174
175
static int size_mult(size_t a, size_t b, size_t *r)
176
1.43k
{
177
1.43k
    size_t t;
178
179
1.43k
#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_mul_overflow)
180
1.43k
    if (__builtin_mul_overflow(a, b, &t))
181
0
        return AVERROR(EINVAL);
182
#else
183
    t = a * b;
184
    /* Hack inspired from glibc: don't try the division if nelem and elsize
185
     * are both less than sqrt(SIZE_MAX). */
186
    if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b)
187
        return AVERROR(EINVAL);
188
#endif
189
1.43k
    *r = t;
190
1.43k
    return 0;
191
1.43k
}
192
193
void *av_malloc(size_t size)
194
5.74k
{
195
5.74k
    void *ptr = NULL;
196
197
5.74k
    if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
198
0
        return NULL;
199
200
#if ASAN_ALIGNED_ALLOC
201
    if (asan_aligned_alloc_needed())
202
        ptr = asan_aligned_malloc(size);
203
    else
204
        ptr = _aligned_malloc(size, ALIGN);
205
#elif HAVE_POSIX_MEMALIGN
206
5.74k
    if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
207
5.74k
    if (posix_memalign(&ptr, ALIGN, size))
208
0
        ptr = NULL;
209
#elif HAVE_ALIGNED_MALLOC
210
    ptr = _aligned_malloc(size, ALIGN);
211
#elif HAVE_MEMALIGN
212
#ifndef __DJGPP__
213
    ptr = memalign(ALIGN, size);
214
#else
215
    ptr = memalign(size, ALIGN);
216
#endif
217
    /* Why 64?
218
     * Indeed, we should align it:
219
     *   on  4 for 386
220
     *   on 16 for 486
221
     *   on 32 for 586, PPro - K6-III
222
     *   on 64 for K7 (maybe for P3 too).
223
     * Because L1 and L2 caches are aligned on those values.
224
     * But I don't want to code such logic here!
225
     */
226
    /* Why 32?
227
     * For AVX ASM. SSE / NEON needs only 16.
228
     * Why not larger? Because I did not see a difference in benchmarks ...
229
     */
230
    /* benchmarks with P3
231
     * memalign(64) + 1          3071, 3051, 3032
232
     * memalign(64) + 2          3051, 3032, 3041
233
     * memalign(64) + 4          2911, 2896, 2915
234
     * memalign(64) + 8          2545, 2554, 2550
235
     * memalign(64) + 16         2543, 2572, 2563
236
     * memalign(64) + 32         2546, 2545, 2571
237
     * memalign(64) + 64         2570, 2533, 2558
238
     *
239
     * BTW, malloc seems to do 8-byte alignment by default here.
240
     */
241
#else
242
    ptr = malloc(size);
243
#endif
244
5.74k
    if(!ptr && !size) {
245
0
        size = 1;
246
0
        ptr= av_malloc(1);
247
0
    }
248
5.74k
    if (ptr)
249
5.74k
        poison_memory(ptr, size);
250
5.74k
    return ptr;
251
5.74k
}
252
253
void *av_realloc(void *ptr, size_t size)
254
2.87k
{
255
2.87k
    void *ret;
256
2.87k
    if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
257
0
        return NULL;
258
259
#if ASAN_ALIGNED_ALLOC
260
    if (asan_aligned_alloc_needed())
261
        ret = asan_aligned_realloc(ptr, size + !size);
262
    else
263
        ret = _aligned_realloc(ptr, size + !size, ALIGN);
264
#elif HAVE_ALIGNED_MALLOC
265
    ret = _aligned_realloc(ptr, size + !size, ALIGN);
266
#else
267
2.87k
    ret = realloc(ptr, size + !size);
268
2.87k
#endif
269
2.87k
    if (ret && !ptr)
270
2.87k
        poison_memory(ret, size);
271
2.87k
    return ret;
272
2.87k
}
273
274
void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
275
0
{
276
0
    size_t size;
277
0
    void *r;
278
279
0
    if (size_mult(elsize, nelem, &size)) {
280
0
        av_free(ptr);
281
0
        return NULL;
282
0
    }
283
0
    r = av_realloc(ptr, size);
284
0
    if (!r)
285
0
        av_free(ptr);
286
0
    return r;
287
0
}
288
289
int av_reallocp(void *ptr, size_t size)
290
0
{
291
0
    void *val;
292
293
0
    if (!size) {
294
0
        av_freep(ptr);
295
0
        return 0;
296
0
    }
297
298
0
    memcpy(&val, ptr, sizeof(val));
299
0
    val = av_realloc(val, size);
300
301
0
    if (!val) {
302
0
        av_freep(ptr);
303
0
        return AVERROR(ENOMEM);
304
0
    }
305
306
0
    memcpy(ptr, &val, sizeof(val));
307
0
    return 0;
308
0
}
309
310
void *av_malloc_array(size_t nmemb, size_t size)
311
0
{
312
0
    size_t result;
313
0
    if (size_mult(nmemb, size, &result) < 0)
314
0
        return NULL;
315
0
    return av_malloc(result);
316
0
}
317
318
void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
319
0
{
320
0
    size_t result;
321
0
    if (size_mult(nmemb, size, &result) < 0)
322
0
        return NULL;
323
0
    return av_realloc(ptr, result);
324
0
}
325
326
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
327
0
{
328
0
    void *val;
329
330
0
    memcpy(&val, ptr, sizeof(val));
331
0
    val = av_realloc_f(val, nmemb, size);
332
0
    memcpy(ptr, &val, sizeof(val));
333
0
    if (!val && nmemb && size)
334
0
        return AVERROR(ENOMEM);
335
336
0
    return 0;
337
0
}
338
339
void av_free(void *ptr)
340
41.6k
{
341
#if ASAN_ALIGNED_ALLOC
342
    if (asan_aligned_alloc_needed())
343
        asan_aligned_free(ptr);
344
    else
345
        _aligned_free(ptr);
346
#elif HAVE_ALIGNED_MALLOC
347
    _aligned_free(ptr);
348
#else
349
41.6k
    free(ptr);
350
41.6k
#endif
351
41.6k
}
352
353
void av_freep(void *arg)
354
40.2k
{
355
40.2k
    void *val;
356
357
40.2k
    memcpy(&val, arg, sizeof(val));
358
40.2k
    memcpy(arg, &(void *){ NULL }, sizeof(val));
359
40.2k
    av_free(val);
360
40.2k
}
361
362
void *av_mallocz(size_t size)
363
2.87k
{
364
2.87k
    void *ptr = av_malloc(size);
365
2.87k
    if (ptr)
366
2.87k
        memset(ptr, 0, size);
367
2.87k
    return ptr;
368
2.87k
}
369
370
void *av_calloc(size_t nmemb, size_t size)
371
1.43k
{
372
1.43k
    size_t result;
373
1.43k
    if (size_mult(nmemb, size, &result) < 0)
374
0
        return NULL;
375
1.43k
    return av_mallocz(result);
376
1.43k
}
377
378
char *av_strdup(const char *s)
379
2.87k
{
380
2.87k
    char *ptr = NULL;
381
2.87k
    if (s) {
382
2.87k
        size_t len = strlen(s) + 1;
383
2.87k
        ptr = av_realloc(NULL, len);
384
2.87k
        if (ptr)
385
2.87k
            memcpy(ptr, s, len);
386
2.87k
    }
387
2.87k
    return ptr;
388
2.87k
}
389
390
char *av_strndup(const char *s, size_t len)
391
0
{
392
0
    if (!s)
393
0
        return NULL;
394
395
0
    const char *end = memchr(s, 0, len);
396
0
    if (end)
397
0
        len = end - s;
398
399
0
    char *ret = av_realloc(NULL, len + 1);
400
0
    if (!ret)
401
0
        return NULL;
402
403
0
    memcpy(ret, s, len);
404
0
    ret[len] = 0;
405
0
    return ret;
406
0
}
407
408
void *av_memdup(const void *p, size_t size)
409
0
{
410
0
    void *ptr = NULL;
411
0
    if (p) {
412
0
        ptr = av_malloc(size);
413
0
        if (ptr)
414
0
            memcpy(ptr, p, size);
415
0
    }
416
0
    return ptr;
417
0
}
418
419
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
420
0
{
421
0
    void **tab;
422
0
    memcpy(&tab, tab_ptr, sizeof(tab));
423
424
0
    FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
425
0
        tab[*nb_ptr] = elem;
426
0
        memcpy(tab_ptr, &tab, sizeof(tab));
427
0
    }, {
428
0
        return AVERROR(ENOMEM);
429
0
    });
430
0
    return 0;
431
0
}
432
433
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
434
0
{
435
0
    void **tab;
436
0
    memcpy(&tab, tab_ptr, sizeof(tab));
437
438
0
    FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
439
0
        tab[*nb_ptr] = elem;
440
0
        memcpy(tab_ptr, &tab, sizeof(tab));
441
0
    }, {
442
0
        *nb_ptr = 0;
443
0
        av_freep(tab_ptr);
444
0
    });
445
0
}
446
447
void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
448
                       const uint8_t *elem_data)
449
0
{
450
0
    uint8_t *tab_elem_data = NULL;
451
452
0
    FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
453
0
        tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
454
0
        if (elem_data)
455
0
            memcpy(tab_elem_data, elem_data, elem_size);
456
0
        else
457
0
            poison_memory(tab_elem_data, elem_size);
458
0
    }, {
459
0
        av_freep(tab_ptr);
460
0
        *nb_ptr = 0;
461
0
    });
462
0
    return tab_elem_data;
463
0
}
464
465
static void fill16(uint8_t *dst, int len)
466
0
{
467
0
    uint32_t v = AV_RN16(dst - 2);
468
469
0
    v |= v << 16;
470
471
0
    while (len >= 4) {
472
0
        AV_WN32(dst, v);
473
0
        dst += 4;
474
0
        len -= 4;
475
0
    }
476
477
0
    while (len--) {
478
0
        *dst = dst[-2];
479
0
        dst++;
480
0
    }
481
0
}
482
483
static void fill24(uint8_t *dst, int len)
484
0
{
485
#if HAVE_BIGENDIAN
486
    uint32_t v = AV_RB24(dst - 3);
487
    uint32_t a = v << 8  | v >> 16;
488
    uint32_t b = v << 16 | v >> 8;
489
    uint32_t c = v << 24 | v;
490
#else
491
0
    uint32_t v = AV_RL24(dst - 3);
492
0
    uint32_t a = v       | v << 24;
493
0
    uint32_t b = v >> 8  | v << 16;
494
0
    uint32_t c = v >> 16 | v << 8;
495
0
#endif
496
497
0
    while (len >= 12) {
498
0
        AV_WN32(dst,     a);
499
0
        AV_WN32(dst + 4, b);
500
0
        AV_WN32(dst + 8, c);
501
0
        dst += 12;
502
0
        len -= 12;
503
0
    }
504
505
0
    if (len >= 4) {
506
0
        AV_WN32(dst, a);
507
0
        dst += 4;
508
0
        len -= 4;
509
0
    }
510
511
0
    if (len >= 4) {
512
0
        AV_WN32(dst, b);
513
0
        dst += 4;
514
0
        len -= 4;
515
0
    }
516
517
0
    while (len--) {
518
0
        *dst = dst[-3];
519
0
        dst++;
520
0
    }
521
0
}
522
523
static void fill32(uint8_t *dst, int len)
524
0
{
525
0
    uint32_t v = AV_RN32(dst - 4);
526
527
#if HAVE_FAST_64BIT
528
    uint64_t v2= v + ((uint64_t)v<<32);
529
    while (len >= 32) {
530
        AV_WN64(dst   , v2);
531
        AV_WN64(dst+ 8, v2);
532
        AV_WN64(dst+16, v2);
533
        AV_WN64(dst+24, v2);
534
        dst += 32;
535
        len -= 32;
536
    }
537
#endif
538
539
0
    while (len >= 4) {
540
0
        AV_WN32(dst, v);
541
0
        dst += 4;
542
0
        len -= 4;
543
0
    }
544
545
0
    while (len--) {
546
0
        *dst = dst[-4];
547
0
        dst++;
548
0
    }
549
0
}
550
551
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
552
0
{
553
0
    const uint8_t *src = &dst[-back];
554
0
    if (!back)
555
0
        return;
556
557
0
    if (back == 1) {
558
0
        memset(dst, *src, cnt);
559
0
    } else if (back == 2) {
560
0
        fill16(dst, cnt);
561
0
    } else if (back == 3) {
562
0
        fill24(dst, cnt);
563
0
    } else if (back == 4) {
564
0
        fill32(dst, cnt);
565
0
    } else {
566
0
        if (cnt >= 16) {
567
0
            int blocklen = back;
568
0
            while (cnt > blocklen) {
569
0
                memcpy(dst, src, blocklen);
570
0
                dst       += blocklen;
571
0
                cnt       -= blocklen;
572
0
                blocklen <<= 1;
573
0
            }
574
0
            memcpy(dst, src, cnt);
575
0
            return;
576
0
        }
577
0
        if (cnt >= 8) {
578
0
            AV_COPY32U(dst,     src);
579
0
            AV_COPY32U(dst + 4, src + 4);
580
0
            src += 8;
581
0
            dst += 8;
582
0
            cnt -= 8;
583
0
        }
584
0
        if (cnt >= 4) {
585
0
            AV_COPY32U(dst, src);
586
0
            src += 4;
587
0
            dst += 4;
588
0
            cnt -= 4;
589
0
        }
590
0
        if (cnt >= 2) {
591
0
            AV_COPY16U(dst, src);
592
0
            src += 2;
593
0
            dst += 2;
594
0
            cnt -= 2;
595
0
        }
596
0
        if (cnt)
597
0
            *dst = *src;
598
0
    }
599
0
}
600
601
void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
602
0
{
603
0
    size_t max_size;
604
605
0
    if (min_size <= *size)
606
0
        return ptr;
607
608
0
    max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
609
    /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
610
0
    max_size = FFMIN(max_size, UINT_MAX);
611
612
0
    if (min_size > max_size) {
613
0
        *size = 0;
614
0
        return NULL;
615
0
    }
616
617
0
    min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
618
619
0
    ptr = av_realloc(ptr, min_size);
620
    /* we could set this to the unmodified min_size but this is safer
621
     * if the user lost the ptr and uses NULL now
622
     */
623
0
    if (!ptr)
624
0
        min_size = 0;
625
626
0
    *size = min_size;
627
628
0
    return ptr;
629
0
}
630
631
static inline void fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
632
0
{
633
0
    size_t max_size;
634
0
    void *val;
635
636
0
    memcpy(&val, ptr, sizeof(val));
637
0
    if (min_size <= *size) {
638
0
        av_assert0(val || !min_size);
639
0
        return;
640
0
    }
641
642
0
    max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
643
    /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
644
0
    max_size = FFMIN(max_size, UINT_MAX);
645
646
0
    if (min_size > max_size) {
647
0
        av_freep(ptr);
648
0
        *size = 0;
649
0
        return;
650
0
    }
651
0
    min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
652
0
    av_freep(ptr);
653
0
    val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
654
0
    memcpy(ptr, &val, sizeof(val));
655
0
    if (!val)
656
0
        min_size = 0;
657
0
    *size = min_size;
658
0
    return;
659
0
}
660
661
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
662
0
{
663
0
    fast_malloc(ptr, size, min_size, 0);
664
0
}
665
666
void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
667
0
{
668
0
    fast_malloc(ptr, size, min_size, 1);
669
0
}
670
671
int av_size_mult(size_t a, size_t b, size_t *r)
672
0
{
673
0
    return size_mult(a, b, r);
674
0
}