Coverage Report

Created: 2026-08-14 07:16

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