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