/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 | } |