FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/mem.c
Date: 2026-09-28 11:37:26
Exec Total Coverage
Lines: 232 254 91.3%
Functions: 29 29 100.0%
Branches: 107 146 73.3%

Line Branch Exec 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 #define ALIGN (HAVE_SIMD_ALIGN_64 ? 64 : (HAVE_SIMD_ALIGN_32 ? 32 : 16))
67
68 #define FF_MEMORY_POISON 0x2a
69
70 87082312 static void poison_memory(void *ptr, size_t size)
71 {
72 #if CONFIG_MEMORY_POISONING
73 87082312 memset(ptr, FF_MEMORY_POISON, size);
74 #endif
75 87082312 FF_MEM_UNDEFINED(ptr, size);
76 87082312 }
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 32 void av_max_alloc(size_t max){
172 32 atomic_store_explicit(&max_alloc_size, max, memory_order_relaxed);
173 32 }
174
175 12244502 static int size_mult(size_t a, size_t b, size_t *r)
176 {
177 size_t t;
178
179 #if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_mul_overflow)
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12244502 times.
12244502 if (__builtin_mul_overflow(a, b, &t))
181 ✗ 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 12244502 *r = t;
190 12244502 return 0;
191 }
192
193 63235043 void *av_malloc(size_t size)
194 {
195 63235043 void *ptr = NULL;
196
197
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 63235019 times.
63235043 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
198 24 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
2/2
✓ Branch 0 taken 63215379 times.
✓ Branch 1 taken 19640 times.
63235019 if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
207
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 63215379 times.
63215379 if (posix_memalign(&ptr, ALIGN, size))
208 ✗ 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
3/4
✓ Branch 0 taken 19640 times.
✓ Branch 1 taken 63215379 times.
✓ Branch 2 taken 19640 times.
✗ Branch 3 not taken.
63235019 if(!ptr && !size) {
245 19640 size = 1;
246 19640 ptr= av_malloc(1);
247 }
248
1/2
✓ Branch 0 taken 63235019 times.
✗ Branch 1 not taken.
63235019 if (ptr)
249 63235019 poison_memory(ptr, size);
250 63235019 return ptr;
251 }
252
253 25680404 void *av_realloc(void *ptr, size_t size)
254 {
255 void *ret;
256
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 25680403 times.
25680404 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
257 1 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 25680403 ret = realloc(ptr, size + !size);
268 #endif
269
3/4
✓ Branch 0 taken 25680403 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10407000 times.
✓ Branch 3 taken 15273403 times.
25680403 if (ret && !ptr)
270 10407000 poison_memory(ret, size);
271 25680403 return ret;
272 }
273
274 69297 void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
275 {
276 size_t size;
277 void *r;
278
279
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 69297 times.
69297 if (size_mult(elsize, nelem, &size)) {
280 ✗ av_free(ptr);
281 ✗ return NULL;
282 }
283 69297 r = av_realloc(ptr, size);
284
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69297 times.
69297 if (!r)
285 ✗ av_free(ptr);
286 69297 return r;
287 }
288
289 22239 int av_reallocp(void *ptr, size_t size)
290 {
291 void *val;
292
293
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 22230 times.
22239 if (!size) {
294 9 av_freep(ptr);
295 9 return 0;
296 }
297
298 22230 memcpy(&val, ptr, sizeof(val));
299 22230 val = av_realloc(val, size);
300
301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22230 times.
22230 if (!val) {
302 ✗ av_freep(ptr);
303 ✗ return AVERROR(ENOMEM);
304 }
305
306 22230 memcpy(ptr, &val, sizeof(val));
307 22230 return 0;
308 }
309
310 794921 void *av_malloc_array(size_t nmemb, size_t size)
311 {
312 size_t result;
313
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 794921 times.
794921 if (size_mult(nmemb, size, &result) < 0)
314 ✗ return NULL;
315 794921 return av_malloc(result);
316 }
317
318 7079847 void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
319 {
320 size_t result;
321
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7079847 times.
7079847 if (size_mult(nmemb, size, &result) < 0)
322 ✗ return NULL;
323 7079847 return av_realloc(ptr, result);
324 }
325
326 7740 int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
327 {
328 void *val;
329
330 7740 memcpy(&val, ptr, sizeof(val));
331 7740 val = av_realloc_f(val, nmemb, size);
332 7740 memcpy(ptr, &val, sizeof(val));
333
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 7740 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
7740 if (!val && nmemb && size)
334 ✗ return AVERROR(ENOMEM);
335
336 7740 return 0;
337 }
338
339 129671632 void av_free(void *ptr)
340 {
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 129671632 free(ptr);
350 #endif
351 129671632 }
352
353 83567288 void av_freep(void *arg)
354 {
355 void *val;
356
357 83567288 memcpy(&val, arg, sizeof(val));
358 83567288 memcpy(arg, &(void *){ NULL }, sizeof(val));
359 83567288 av_free(val);
360 83567288 }
361
362 39400897 void *av_mallocz(size_t size)
363 {
364 39400897 void *ptr = av_malloc(size);
365
2/2
✓ Branch 0 taken 39400881 times.
✓ Branch 1 taken 16 times.
39400897 if (ptr)
366 39400881 memset(ptr, 0, size);
367 39400897 return ptr;
368 }
369
370 4287690 void *av_calloc(size_t nmemb, size_t size)
371 {
372 size_t result;
373
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4287690 times.
4287690 if (size_mult(nmemb, size, &result) < 0)
374 ✗ return NULL;
375 4287690 return av_mallocz(result);
376 }
377
378 2443054 char *av_strdup(const char *s)
379 {
380 2443054 char *ptr = NULL;
381
2/2
✓ Branch 0 taken 2443053 times.
✓ Branch 1 taken 1 times.
2443054 if (s) {
382 2443053 size_t len = strlen(s) + 1;
383 2443053 ptr = av_realloc(NULL, len);
384
1/2
✓ Branch 0 taken 2443053 times.
✗ Branch 1 not taken.
2443053 if (ptr)
385 2443053 memcpy(ptr, s, len);
386 }
387 2443054 return ptr;
388 }
389
390 11 char *av_strndup(const char *s, size_t len)
391 {
392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!s)
393 ✗ return NULL;
394
395 11 const char *end = memchr(s, 0, len);
396
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (end)
397 ✗ len = end - s;
398
399 11 char *ret = av_realloc(NULL, len + 1);
400
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!ret)
401 ✗ return NULL;
402
403 11 memcpy(ret, s, len);
404 11 ret[len] = 0;
405 11 return ret;
406 }
407
408 11725793 void *av_memdup(const void *p, size_t size)
409 {
410 11725793 void *ptr = NULL;
411
1/2
✓ Branch 0 taken 11725793 times.
✗ Branch 1 not taken.
11725793 if (p) {
412 11725793 ptr = av_malloc(size);
413
1/2
✓ Branch 0 taken 11725793 times.
✗ Branch 1 not taken.
11725793 if (ptr)
414 11725793 memcpy(ptr, p, size);
415 }
416 11725793 return ptr;
417 }
418
419 238183 int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
420 {
421 void **tab;
422 238183 memcpy(&tab, tab_ptr, sizeof(tab));
423
424
7/10
✓ Branch 0 taken 231173 times.
✓ Branch 1 taken 7010 times.
✓ Branch 2 taken 60050 times.
✓ Branch 3 taken 171123 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 231173 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 231173 times.
✓ Branch 9 taken 238183 times.
✗ Branch 10 not taken.
238183 FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
425 tab[*nb_ptr] = elem;
426 memcpy(tab_ptr, &tab, sizeof(tab));
427 }, {
428 return AVERROR(ENOMEM);
429 });
430 238183 return 0;
431 }
432
433 1373 void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
434 {
435 void **tab;
436 1373 memcpy(&tab, tab_ptr, sizeof(tab));
437
438
7/10
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 1105 times.
✓ Branch 2 taken 160 times.
✓ Branch 3 taken 108 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 268 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 268 times.
✓ Branch 9 taken 1373 times.
✗ Branch 10 not taken.
1373 FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
439 tab[*nb_ptr] = elem;
440 memcpy(tab_ptr, &tab, sizeof(tab));
441 }, {
442 *nb_ptr = 0;
443 av_freep(tab_ptr);
444 });
445 1373 }
446
447 24234569 void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
448 const uint8_t *elem_data)
449 {
450 24234569 uint8_t *tab_elem_data = NULL;
451
452
9/12
✓ Branch 0 taken 12038945 times.
✓ Branch 1 taken 12195624 times.
✓ Branch 2 taken 8831227 times.
✓ Branch 3 taken 3207718 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12038945 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12038945 times.
✓ Branch 9 taken 24234569 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 10794276 times.
✓ Branch 12 taken 13440293 times.
24234569 FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
453 tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
454 if (elem_data)
455 memcpy(tab_elem_data, elem_data, elem_size);
456 else
457 poison_memory(tab_elem_data, elem_size);
458 }, {
459 av_freep(tab_ptr);
460 *nb_ptr = 0;
461 });
462 24234569 return tab_elem_data;
463 }
464
465 111420 static void fill16(uint8_t *dst, int len)
466 {
467 111420 uint32_t v = AV_RN16(dst - 2);
468
469 111420 v |= v << 16;
470
471
2/2
✓ Branch 0 taken 43489578 times.
✓ Branch 1 taken 111420 times.
43600998 while (len >= 4) {
472 43489578 AV_WN32(dst, v);
473 43489578 dst += 4;
474 43489578 len -= 4;
475 }
476
477
2/2
✓ Branch 0 taken 210669 times.
✓ Branch 1 taken 111420 times.
322089 while (len--) {
478 210669 *dst = dst[-2];
479 210669 dst++;
480 }
481 111420 }
482
483 738 static void fill24(uint8_t *dst, int len)
484 {
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 738 uint32_t v = AV_RL24(dst - 3);
492 738 uint32_t a = v | v << 24;
493 738 uint32_t b = v >> 8 | v << 16;
494 738 uint32_t c = v >> 16 | v << 8;
495 #endif
496
497
2/2
✓ Branch 0 taken 2508 times.
✓ Branch 1 taken 738 times.
3246 while (len >= 12) {
498 2508 AV_WN32(dst, a);
499 2508 AV_WN32(dst + 4, b);
500 2508 AV_WN32(dst + 8, c);
501 2508 dst += 12;
502 2508 len -= 12;
503 }
504
505
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 455 times.
738 if (len >= 4) {
506 283 AV_WN32(dst, a);
507 283 dst += 4;
508 283 len -= 4;
509 }
510
511
2/2
✓ Branch 0 taken 157 times.
✓ Branch 1 taken 581 times.
738 if (len >= 4) {
512 157 AV_WN32(dst, b);
513 157 dst += 4;
514 157 len -= 4;
515 }
516
517
2/2
✓ Branch 0 taken 1580 times.
✓ Branch 1 taken 738 times.
2318 while (len--) {
518 1580 *dst = dst[-3];
519 1580 dst++;
520 }
521 738 }
522
523 15472 static void fill32(uint8_t *dst, int len)
524 {
525 15472 uint32_t v = AV_RN32(dst - 4);
526
527 #if HAVE_FAST_64BIT
528 15472 uint64_t v2= v + ((uint64_t)v<<32);
529
2/2
✓ Branch 0 taken 105234 times.
✓ Branch 1 taken 15472 times.
120706 while (len >= 32) {
530 105234 AV_WN64(dst , v2);
531 105234 AV_WN64(dst+ 8, v2);
532 105234 AV_WN64(dst+16, v2);
533 105234 AV_WN64(dst+24, v2);
534 105234 dst += 32;
535 105234 len -= 32;
536 }
537 #endif
538
539
2/2
✓ Branch 0 taken 60901 times.
✓ Branch 1 taken 15472 times.
76373 while (len >= 4) {
540 60901 AV_WN32(dst, v);
541 60901 dst += 4;
542 60901 len -= 4;
543 }
544
545
2/2
✓ Branch 0 taken 2266 times.
✓ Branch 1 taken 15472 times.
17738 while (len--) {
546 2266 *dst = dst[-4];
547 2266 dst++;
548 }
549 15472 }
550
551 772507 void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
552 {
553 772507 const uint8_t *src = &dst[-back];
554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 772507 times.
772507 if (!back)
555 ✗ return;
556
557
2/2
✓ Branch 0 taken 5265 times.
✓ Branch 1 taken 767242 times.
772507 if (back == 1) {
558 5265 memset(dst, *src, cnt);
559
2/2
✓ Branch 0 taken 111420 times.
✓ Branch 1 taken 655822 times.
767242 } else if (back == 2) {
560 111420 fill16(dst, cnt);
561
2/2
✓ Branch 0 taken 738 times.
✓ Branch 1 taken 655084 times.
655822 } else if (back == 3) {
562 738 fill24(dst, cnt);
563
2/2
✓ Branch 0 taken 15472 times.
✓ Branch 1 taken 639612 times.
655084 } else if (back == 4) {
564 15472 fill32(dst, cnt);
565 } else {
566
2/2
✓ Branch 0 taken 104834 times.
✓ Branch 1 taken 534778 times.
639612 if (cnt >= 16) {
567 104834 int blocklen = back;
568
2/2
✓ Branch 0 taken 37416 times.
✓ Branch 1 taken 104834 times.
142250 while (cnt > blocklen) {
569 37416 memcpy(dst, src, blocklen);
570 37416 dst += blocklen;
571 37416 cnt -= blocklen;
572 37416 blocklen <<= 1;
573 }
574 104834 memcpy(dst, src, cnt);
575 104834 return;
576 }
577
2/2
✓ Branch 0 taken 116277 times.
✓ Branch 1 taken 418501 times.
534778 if (cnt >= 8) {
578 116277 AV_COPY32U(dst, src);
579 116277 AV_COPY32U(dst + 4, src + 4);
580 116277 src += 8;
581 116277 dst += 8;
582 116277 cnt -= 8;
583 }
584
2/2
✓ Branch 0 taken 383459 times.
✓ Branch 1 taken 151319 times.
534778 if (cnt >= 4) {
585 383459 AV_COPY32U(dst, src);
586 383459 src += 4;
587 383459 dst += 4;
588 383459 cnt -= 4;
589 }
590
2/2
✓ Branch 0 taken 192819 times.
✓ Branch 1 taken 341959 times.
534778 if (cnt >= 2) {
591 192819 AV_COPY16U(dst, src);
592 192819 src += 2;
593 192819 dst += 2;
594 192819 cnt -= 2;
595 }
596
2/2
✓ Branch 0 taken 118885 times.
✓ Branch 1 taken 415893 times.
534778 if (cnt)
597 118885 *dst = *src;
598 }
599 }
600
601 1950775 void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
602 {
603 size_t max_size;
604
605
2/2
✓ Branch 0 taken 1828597 times.
✓ Branch 1 taken 122178 times.
1950775 if (min_size <= *size)
606 1828597 return ptr;
607
608 122178 max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
609 /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
610 122178 max_size = FFMIN(max_size, UINT_MAX);
611
612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122178 times.
122178 if (min_size > max_size) {
613 ✗ *size = 0;
614 ✗ return NULL;
615 }
616
617 122178 min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
618
619 122178 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122178 times.
122178 if (!ptr)
624 ✗ min_size = 0;
625
626 122178 *size = min_size;
627
628 122178 return ptr;
629 }
630
631 373233 static inline void fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
632 {
633 size_t max_size;
634 void *val;
635
636 373233 memcpy(&val, ptr, sizeof(val));
637
2/2
✓ Branch 0 taken 317540 times.
✓ Branch 1 taken 55693 times.
373233 if (min_size <= *size) {
638
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 317540 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
317540 av_assert0(val || !min_size);
639 317540 return;
640 }
641
642 55693 max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed);
643 /* *size is an unsigned, so the real maximum is <= UINT_MAX. */
644 55693 max_size = FFMIN(max_size, UINT_MAX);
645
646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55693 times.
55693 if (min_size > max_size) {
647 ✗ av_freep(ptr);
648 ✗ *size = 0;
649 ✗ return;
650 }
651 55693 min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size));
652 55693 av_freep(ptr);
653
2/2
✓ Branch 0 taken 53300 times.
✓ Branch 1 taken 2393 times.
55693 val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
654 55693 memcpy(ptr, &val, sizeof(val));
655
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55693 times.
55693 if (!val)
656 ✗ min_size = 0;
657 55693 *size = min_size;
658 55693 return;
659 }
660
661 97835 void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
662 {
663 97835 fast_malloc(ptr, size, min_size, 0);
664 97835 }
665
666 275398 void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
667 {
668 275398 fast_malloc(ptr, size, min_size, 1);
669 275398 }
670
671 12747 int av_size_mult(size_t a, size_t b, size_t *r)
672 {
673 12747 return size_mult(a, b, r);
674 }
675