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