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
270void *av_memdup(const void *p, size_t size)
271{
272    void *ptr = NULL;
273    if (p) {
274        ptr = av_malloc(size);
275        if (ptr)
276            memcpy(ptr, p, size);
277    }
278    return ptr;
279}
280
281int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
282{
283    void **tab = *(void ***)tab_ptr;
284
285    AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
286        tab[*nb_ptr] = elem;
287        *(void ***)tab_ptr = tab;
288    }, {
289        return AVERROR(ENOMEM);
290    });
291    return 0;
292}
293
294void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
295{
296    void **tab = *(void ***)tab_ptr;
297
298    AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
299        tab[*nb_ptr] = elem;
300        *(void ***)tab_ptr = tab;
301    }, {
302        *nb_ptr = 0;
303        av_freep(tab_ptr);
304    });
305}
306
307void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
308                       const uint8_t *elem_data)
309{
310    uint8_t *tab_elem_data = NULL;
311
312    AV_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
313        tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
314        if (elem_data)
315            memcpy(tab_elem_data, elem_data, elem_size);
316        else if (CONFIG_MEMORY_POISONING)
317            memset(tab_elem_data, FF_MEMORY_POISON, elem_size);
318    }, {
319        av_freep(tab_ptr);
320        *nb_ptr = 0;
321    });
322    return tab_elem_data;
323}
324
325static void fill16(uint8_t *dst, int len)
326{
327    uint32_t v = AV_RN16(dst - 2);
328
329    v |= v << 16;
330
331    while (len >= 4) {
332        AV_WN32(dst, v);
333        dst += 4;
334        len -= 4;
335    }
336
337    while (len--) {
338        *dst = dst[-2];
339        dst++;
340    }
341}
342
343static void fill24(uint8_t *dst, int len)
344{
345#if HAVE_BIGENDIAN
346    uint32_t v = AV_RB24(dst - 3);
347    uint32_t a = v << 8  | v >> 16;
348    uint32_t b = v << 16 | v >> 8;
349    uint32_t c = v << 24 | v;
350#else
351    uint32_t v = AV_RL24(dst - 3);
352    uint32_t a = v       | v << 24;
353    uint32_t b = v >> 8  | v << 16;
354    uint32_t c = v >> 16 | v << 8;
355#endif
356
357    while (len >= 12) {
358        AV_WN32(dst,     a);
359        AV_WN32(dst + 4, b);
360        AV_WN32(dst + 8, c);
361        dst += 12;
362        len -= 12;
363    }
364
365    if (len >= 4) {
366        AV_WN32(dst, a);
367        dst += 4;
368        len -= 4;
369    }
370
371    if (len >= 4) {
372        AV_WN32(dst, b);
373        dst += 4;
374        len -= 4;
375    }
376
377    while (len--) {
378        *dst = dst[-3];
379        dst++;
380    }
381}
382
383static void fill32(uint8_t *dst, int len)
384{
385    uint32_t v = AV_RN32(dst - 4);
386
387    while (len >= 4) {
388        AV_WN32(dst, v);
389        dst += 4;
390        len -= 4;
391    }
392
393    while (len--) {
394        *dst = dst[-4];
395        dst++;
396    }
397}
398
399void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
400{
401    const uint8_t *src = &dst[-back];
402    if (!back)
403        return;
404
405    if (back == 1) {
406        memset(dst, *src, cnt);
407    } else if (back == 2) {
408        fill16(dst, cnt);
409    } else if (back == 3) {
410        fill24(dst, cnt);
411    } else if (back == 4) {
412        fill32(dst, cnt);
413    } else {
414        if (cnt >= 16) {
415            int blocklen = back;
416            while (cnt > blocklen) {
417                memcpy(dst, src, blocklen);
418                dst       += blocklen;
419                cnt       -= blocklen;
420                blocklen <<= 1;
421            }
422            memcpy(dst, src, cnt);
423            return;
424        }
425        if (cnt >= 8) {
426            AV_COPY32U(dst,     src);
427            AV_COPY32U(dst + 4, src + 4);
428            src += 8;
429            dst += 8;
430            cnt -= 8;
431        }
432        if (cnt >= 4) {
433            AV_COPY32U(dst, src);
434            src += 4;
435            dst += 4;
436            cnt -= 4;
437        }
438        if (cnt >= 2) {
439            AV_COPY16U(dst, src);
440            src += 2;
441            dst += 2;
442            cnt -= 2;
443        }
444        if (cnt)
445            *dst = *src;
446    }
447}
448
449void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
450{
451    if (min_size < *size)
452        return ptr;
453
454    min_size = FFMAX(17 * min_size / 16 + 32, min_size);
455
456    ptr = av_realloc(ptr, min_size);
457    /* we could set this to the unmodified min_size but this is safer
458     * if the user lost the ptr and uses NULL now
459     */
460    if (!ptr)
461        min_size = 0;
462
463    *size = min_size;
464
465    return ptr;
466}
467
468static inline int ff_fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
469{
470    void **p = ptr;
471    if (min_size < *size)
472        return 0;
473    min_size = FFMAX(17 * min_size / 16 + 32, min_size);
474    av_free(*p);
475    *p = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
476    if (!*p)
477        min_size = 0;
478    *size = min_size;
479    return 1;
480}
481
482void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
483{
484    ff_fast_malloc(ptr, size, min_size, 0);
485}
486
487