Coverage Report

Created: 2024-09-06 07:53

/src/ffmpeg/libavutil/mem.c
Line
Count
Source (jump to first uncovered line)
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
2.11G
#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
74
static atomic_size_t max_alloc_size = INT_MAX;
75
76
0
void av_max_alloc(size_t max){
77
0
    atomic_store_explicit(&max_alloc_size, max, memory_order_relaxed);
78
0
}
79
80
static int size_mult(size_t a, size_t b, size_t *r)
81
79.8M
{
82
79.8M
    size_t t;
83
84
79.8M
#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_mul_overflow)
85
79.8M
    if (__builtin_mul_overflow(a, b, &t))
86
4
        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
79.8M
    *r = t;
95
79.8M
    return 0;
96
79.8M
}
97
98
void *av_malloc(size_t size)
99
2.11G
{
100
2.11G
    void *ptr = NULL;
101
102
2.11G
    if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
103
646
        return NULL;
104
105
2.11G
#if HAVE_POSIX_MEMALIGN
106
2.11G
    if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
107
2.11G
    if (posix_memalign(&ptr, ALIGN, size))
108
0
        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
2.11G
    if(!ptr && !size) {
145
1.85M
        size = 1;
146
1.85M
        ptr= av_malloc(1);
147
1.85M
    }
148
#if CONFIG_MEMORY_POISONING
149
    if (ptr)
150
        memset(ptr, FF_MEMORY_POISON, size);
151
#endif
152
2.11G
    return ptr;
153
2.11G
}
154
155
void *av_realloc(void *ptr, size_t size)
156
305M
{
157
305M
    void *ret;
158
305M
    if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
159
9
        return NULL;
160
161
#if HAVE_ALIGNED_MALLOC
162
    ret = _aligned_realloc(ptr, size + !size, ALIGN);
163
#else
164
305M
    ret = realloc(ptr, size + !size);
165
305M
#endif
166
#if CONFIG_MEMORY_POISONING
167
    if (ret && !ptr)
168
        memset(ret, FF_MEMORY_POISON, size);
169
#endif
170
305M
    return ret;
171
305M
}
172
173
void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
174
9.39M
{
175
9.39M
    size_t size;
176
9.39M
    void *r;
177
178
9.39M
    if (size_mult(elsize, nelem, &size)) {
179
0
        av_free(ptr);
180
0
        return NULL;
181
0
    }
182
9.39M
    r = av_realloc(ptr, size);
183
9.39M
    if (!r)
184
3
        av_free(ptr);
185
9.39M
    return r;
186
9.39M
}
187
188
int av_reallocp(void *ptr, size_t size)
189
11.8M
{
190
11.8M
    void *val;
191
192
11.8M
    if (!size) {
193
2.69k
        av_freep(ptr);
194
2.69k
        return 0;
195
2.69k
    }
196
197
11.8M
    memcpy(&val, ptr, sizeof(val));
198
11.8M
    val = av_realloc(val, size);
199
200
11.8M
    if (!val) {
201
0
        av_freep(ptr);
202
0
        return AVERROR(ENOMEM);
203
0
    }
204
205
11.8M
    memcpy(ptr, &val, sizeof(val));
206
11.8M
    return 0;
207
11.8M
}
208
209
void *av_malloc_array(size_t nmemb, size_t size)
210
33.0M
{
211
33.0M
    size_t result;
212
33.0M
    if (size_mult(nmemb, size, &result) < 0)
213
4
        return NULL;
214
33.0M
    return av_malloc(result);
215
33.0M
}
216
217
void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
218
17.0M
{
219
17.0M
    size_t result;
220
17.0M
    if (size_mult(nmemb, size, &result) < 0)
221
0
        return NULL;
222
17.0M
    return av_realloc(ptr, result);
223
17.0M
}
224
225
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
226
298k
{
227
298k
    void *val;
228
229
298k
    memcpy(&val, ptr, sizeof(val));
230
298k
    val = av_realloc_f(val, nmemb, size);
231
298k
    memcpy(ptr, &val, sizeof(val));
232
298k
    if (!val && nmemb && size)
233
3
        return AVERROR(ENOMEM);
234
235
298k
    return 0;
236
298k
}
237
238
void av_free(void *ptr)
239
6.21G
{
240
#if HAVE_ALIGNED_MALLOC
241
    _aligned_free(ptr);
242
#else
243
6.21G
    free(ptr);
244
6.21G
#endif
245
6.21G
}
246
247
void av_freep(void *arg)
248
4.23G
{
249
4.23G
    void *val;
250
251
4.23G
    memcpy(&val, arg, sizeof(val));
252
4.23G
    memcpy(arg, &(void *){ NULL }, sizeof(val));
253
4.23G
    av_free(val);
254
4.23G
}
255
256
void *av_mallocz(size_t size)
257
1.46G
{
258
1.46G
    void *ptr = av_malloc(size);
259
1.46G
    if (ptr)
260
1.46G
        memset(ptr, 0, size);
261
1.46G
    return ptr;
262
1.46G
}
263
264
void *av_calloc(size_t nmemb, size_t size)
265
19.8M
{
266
19.8M
    size_t result;
267
19.8M
    if (size_mult(nmemb, size, &result) < 0)
268
0
        return NULL;
269
19.8M
    return av_mallocz(result);
270
19.8M
}
271
272
char *av_strdup(const char *s)
273
33.0M
{
274
33.0M
    char *ptr = NULL;
275
33.0M
    if (s) {
276
33.0M
        size_t len = strlen(s) + 1;
277
33.0M
        ptr = av_realloc(NULL, len);
278
33.0M
        if (ptr)
279
33.0M
            memcpy(ptr, s, len);
280
33.0M
    }
281
33.0M
    return ptr;
282
33.0M
}
283
284
char *av_strndup(const char *s, size_t len)
285
0
{
286
0
    char *ret = NULL, *end;
287
288
0
    if (!s)
289
0
        return NULL;
290
291
0
    end = memchr(s, 0, len);
292
0
    if (end)
293
0
        len = end - s;
294
295
0
    ret = av_realloc(NULL, len + 1);
296
0
    if (!ret)
297
0
        return NULL;
298
299
0
    memcpy(ret, s, len);
300
0
    ret[len] = 0;
301
0
    return ret;
302
0
}
303
304
void *av_memdup(const void *p, size_t size)
305
1.39M
{
306
1.39M
    void *ptr = NULL;
307
1.39M
    if (p) {
308
1.39M
        ptr = av_malloc(size);
309
1.39M
        if (ptr)
310
1.39M
            memcpy(ptr, p, size);
311
1.39M
    }
312
1.39M
    return ptr;
313
1.39M
}
314
315
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
316
3.67M
{
317
3.67M
    void **tab;
318
3.67M
    memcpy(&tab, tab_ptr, sizeof(tab));
319
320
3.67M
    FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
321
3.67M
        tab[*nb_ptr] = elem;
322
3.67M
        memcpy(tab_ptr, &tab, sizeof(tab));
323
3.67M
    }, {
324
3.67M
        return AVERROR(ENOMEM);
325
3.67M
    });
326
3.67M
    return 0;
327
3.67M
}
328
329
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
330
743k
{
331
743k
    void **tab;
332
743k
    memcpy(&tab, tab_ptr, sizeof(tab));
333
334
743k
    FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
335
743k
        tab[*nb_ptr] = elem;
336
743k
        memcpy(tab_ptr, &tab, sizeof(tab));
337
743k
    }, {
338
743k
        *nb_ptr = 0;
339
743k
        av_freep(tab_ptr);
340
743k
    });
341
743k
}
342
343
void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
344
                       const uint8_t *elem_data)
345
316
{
346
316
    uint8_t *tab_elem_data = NULL;
347
348
316
    FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
349
316
        tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
350
316
        if (elem_data)
351
316
            memcpy(tab_elem_data, elem_data, elem_size);
352
316
        else if (CONFIG_MEMORY_POISONING)
353
316
            memset(tab_elem_data, FF_MEMORY_POISON, elem_size);
354
316
    }, {
355
316
        av_freep(tab_ptr);
356
316
        *nb_ptr = 0;
357
316
    });
358
316
    return tab_elem_data;
359
316
}
360
361
static void fill16(uint8_t *dst, int len)
362
53.2M
{
363
53.2M
    uint32_t v = AV_RN16(dst - 2);
364
365
53.2M
    v |= v << 16;
366
367
11.4G
    while (len >= 4) {
368
11.3G
        AV_WN32(dst, v);
369
11.3G
        dst += 4;
370
11.3G
        len -= 4;
371
11.3G
    }
372
373
159M
    while (len--) {
374
106M
        *dst = dst[-2];
375
106M
        dst++;
376
106M
    }
377
53.2M
}
378
379
static void fill24(uint8_t *dst, int len)
380
271k
{
381
#if HAVE_BIGENDIAN
382
    uint32_t v = AV_RB24(dst - 3);
383
    uint32_t a = v << 8  | v >> 16;
384
    uint32_t b = v << 16 | v >> 8;
385
    uint32_t c = v << 24 | v;
386
#else
387
271k
    uint32_t v = AV_RL24(dst - 3);
388
271k
    uint32_t a = v       | v << 24;
389
271k
    uint32_t b = v >> 8  | v << 16;
390
271k
    uint32_t c = v >> 16 | v << 8;
391
271k
#endif
392
393
10.0M
    while (len >= 12) {
394
9.76M
        AV_WN32(dst,     a);
395
9.76M
        AV_WN32(dst + 4, b);
396
9.76M
        AV_WN32(dst + 8, c);
397
9.76M
        dst += 12;
398
9.76M
        len -= 12;
399
9.76M
    }
400
401
271k
    if (len >= 4) {
402
68.8k
        AV_WN32(dst, a);
403
68.8k
        dst += 4;
404
68.8k
        len -= 4;
405
68.8k
    }
406
407
271k
    if (len >= 4) {
408
23.8k
        AV_WN32(dst, b);
409
23.8k
        dst += 4;
410
23.8k
        len -= 4;
411
23.8k
    }
412
413
525k
    while (len--) {
414
253k
        *dst = dst[-3];
415
253k
        dst++;
416
253k
    }
417
271k
}
418
419
static void fill32(uint8_t *dst, int len)
420
104M
{
421
104M
    uint32_t v = AV_RN32(dst - 4);
422
423
104M
#if HAVE_FAST_64BIT
424
104M
    uint64_t v2= v + ((uint64_t)v<<32);
425
2.03G
    while (len >= 32) {
426
1.92G
        AV_WN64(dst   , v2);
427
1.92G
        AV_WN64(dst+ 8, v2);
428
1.92G
        AV_WN64(dst+16, v2);
429
1.92G
        AV_WN64(dst+24, v2);
430
1.92G
        dst += 32;
431
1.92G
        len -= 32;
432
1.92G
    }
433
104M
#endif
434
435
480M
    while (len >= 4) {
436
375M
        AV_WN32(dst, v);
437
375M
        dst += 4;
438
375M
        len -= 4;
439
375M
    }
440
441
105M
    while (len--) {
442
839k
        *dst = dst[-4];
443
839k
        dst++;
444
839k
    }
445
104M
}
446
447
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
448
170M
{
449
170M
    const uint8_t *src = &dst[-back];
450
170M
    if (!back)
451
67.2k
        return;
452
453
170M
    if (back == 1) {
454
1.27M
        memset(dst, *src, cnt);
455
169M
    } else if (back == 2) {
456
53.2M
        fill16(dst, cnt);
457
116M
    } else if (back == 3) {
458
271k
        fill24(dst, cnt);
459
115M
    } else if (back == 4) {
460
104M
        fill32(dst, cnt);
461
104M
    } else {
462
11.5M
        if (cnt >= 16) {
463
9.29M
            int blocklen = back;
464
9.73M
            while (cnt > blocklen) {
465
438k
                memcpy(dst, src, blocklen);
466
438k
                dst       += blocklen;
467
438k
                cnt       -= blocklen;
468
438k
                blocklen <<= 1;
469
438k
            }
470
9.29M
            memcpy(dst, src, cnt);
471
9.29M
            return;
472
9.29M
        }
473
2.22M
        if (cnt >= 8) {
474
1.11M
            AV_COPY32U(dst,     src);
475
1.11M
            AV_COPY32U(dst + 4, src + 4);
476
1.11M
            src += 8;
477
1.11M
            dst += 8;
478
1.11M
            cnt -= 8;
479
1.11M
        }
480
2.22M
        if (cnt >= 4) {
481
873k
            AV_COPY32U(dst, src);
482
873k
            src += 4;
483
873k
            dst += 4;
484
873k
            cnt -= 4;
485
873k
        }
486
2.22M
        if (cnt >= 2) {
487
813k
            AV_COPY16U(dst, src);
488
813k
            src += 2;
489
813k
            dst += 2;
490
813k
            cnt -= 2;
491
813k
        }
492
2.22M
        if (cnt)
493
462k
            *dst = *src;
494
2.22M
    }
495
170M
}
496
497
void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
498
627M
{
499
627M
    size_t max_size;
500
501
627M
    if (min_size <= *size)
502
623M
        return ptr;
503
504
4.41M
    max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
505
    /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
506
4.41M
    max_size = FFMIN(max_size, UINT_MAX);
507
508
4.41M
    if (min_size > max_size) {
509
4
        *size = 0;
510
4
        return NULL;
511
4
    }
512
513
4.41M
    min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
514
515
4.41M
    ptr = av_realloc(ptr, min_size);
516
    /* we could set this to the unmodified min_size but this is safer
517
     * if the user lost the ptr and uses NULL now
518
     */
519
4.41M
    if (!ptr)
520
0
        min_size = 0;
521
522
4.41M
    *size = min_size;
523
524
4.41M
    return ptr;
525
4.41M
}
526
527
static inline void fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
528
43.3M
{
529
43.3M
    size_t max_size;
530
43.3M
    void *val;
531
532
43.3M
    memcpy(&val, ptr, sizeof(val));
533
43.3M
    if (min_size <= *size) {
534
39.4M
        av_assert0(val || !min_size);
535
39.4M
        return;
536
39.4M
    }
537
538
3.91M
    max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
539
    /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
540
3.91M
    max_size = FFMIN(max_size, UINT_MAX);
541
542
3.91M
    if (min_size > max_size) {
543
125k
        av_freep(ptr);
544
125k
        *size = 0;
545
125k
        return;
546
125k
    }
547
3.78M
    min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
548
3.78M
    av_freep(ptr);
549
3.78M
    val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
550
3.78M
    memcpy(ptr, &val, sizeof(val));
551
3.78M
    if (!val)
552
0
        min_size = 0;
553
3.78M
    *size = min_size;
554
3.78M
    return;
555
3.91M
}
556
557
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
558
19.6M
{
559
19.6M
    fast_malloc(ptr, size, min_size, 0);
560
19.6M
}
561
562
void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
563
23.6M
{
564
23.6M
    fast_malloc(ptr, size, min_size, 1);
565
23.6M
}
566
567
int av_size_mult(size_t a, size_t b, size_t *r)
568
514k
{
569
514k
    return size_mult(a, b, r);
570
514k
}