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