mem.c 10.4 KB
Newer Older
1
/*
2
 * default memory allocator for libavutil
3
 * Copyright (c) 2002 Fabrice Bellard
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * 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 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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

Michael Niedermayer's avatar
Michael Niedermayer committed
22
/**
23
 * @file
24
 * default memory allocator for libavutil
Michael Niedermayer's avatar
Michael Niedermayer committed
25
 */
26

27 28
#define _XOPEN_SOURCE 600

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 37 38
#include <malloc.h>
#endif

39
#include "avassert.h"
40
#include "avutil.h"
41
#include "intreadwrite.h"
42 43
#include "mem.h"

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
#ifdef MALLOC_PREFIX

#define malloc         AV_JOIN(MALLOC_PREFIX, malloc)
#define memalign       AV_JOIN(MALLOC_PREFIX, memalign)
#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign)
#define realloc        AV_JOIN(MALLOC_PREFIX, realloc)
#define free           AV_JOIN(MALLOC_PREFIX, free)

void *malloc(size_t size);
void *memalign(size_t align, size_t size);
int   posix_memalign(void **ptr, size_t align, size_t size);
void *realloc(void *ptr, size_t size);
void  free(void *ptr);

#endif /* MALLOC_PREFIX */

60 61
#define ALIGN (HAVE_AVX ? 32 : 16)

62 63 64 65
/* NOTE: if you want to override these functions with your own
 * implementations (not recommended) you have to link libav* as
 * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags.
 * Note that this will cost performance. */
66

67 68 69 70 71
static size_t max_alloc_size= INT_MAX;

void av_max_alloc(size_t max){
    max_alloc_size = max;
}
72

73
void *av_malloc(size_t size)
74
{
75
    void *ptr = NULL;
76
#if CONFIG_MEMALIGN_HACK
77
    long diff;
78
#endif
79

80
    /* let's disallow possibly ambiguous cases */
81
    if (size > (max_alloc_size - 32))
82
        return NULL;
83

84
#if CONFIG_MEMALIGN_HACK
85
    ptr = malloc(size + ALIGN);
86
    if (!ptr)
87
        return ptr;
88
    diff              = ((~(long)ptr)&(ALIGN - 1)) + 1;
89 90
    ptr               = (char *)ptr + diff;
    ((char *)ptr)[-1] = diff;
91
#elif HAVE_POSIX_MEMALIGN
92
    if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
93
    if (posix_memalign(&ptr, ALIGN, size))
94
        ptr = NULL;
95
#elif HAVE_ALIGNED_MALLOC
96
    ptr = _aligned_malloc(size, ALIGN);
97
#elif HAVE_MEMALIGN
98
#ifndef __DJGPP__
99
    ptr = memalign(ALIGN, size);
100 101 102
#else
    ptr = memalign(size, ALIGN);
#endif
103
    /* Why 64?
104 105 106 107 108 109 110
     * Indeed, we should align it:
     *   on  4 for 386
     *   on 16 for 486
     *   on 32 for 586, PPro - K6-III
     *   on 64 for K7 (maybe for P3 too).
     * Because L1 and L2 caches are aligned on those values.
     * But I don't want to code such logic here!
111
     */
112 113 114
    /* Why 32?
     * For AVX ASM. SSE / NEON needs only 16.
     * Why not larger? Because I did not see a difference in benchmarks ...
Michael Niedermayer's avatar
Michael Niedermayer committed
115
     */
116 117 118 119 120 121 122 123 124 125
    /* benchmarks with P3
     * memalign(64) + 1          3071, 3051, 3032
     * memalign(64) + 2          3051, 3032, 3041
     * memalign(64) + 4          2911, 2896, 2915
     * memalign(64) + 8          2545, 2554, 2550
     * memalign(64) + 16         2543, 2572, 2563
     * memalign(64) + 32         2546, 2545, 2571
     * memalign(64) + 64         2570, 2533, 2558
     *
     * BTW, malloc seems to do 8-byte alignment by default here.
Michael Niedermayer's avatar
Michael Niedermayer committed
126
     */
127 128 129
#else
    ptr = malloc(size);
#endif
130 131
    if(!ptr && !size) {
        size = 1;
132
        ptr= av_malloc(1);
133 134 135
    }
#if CONFIG_MEMORY_POISONING
    if (ptr)
136
        memset(ptr, FF_MEMORY_POISON, size);
137
#endif
138 139 140
    return ptr;
}

141
void *av_realloc(void *ptr, size_t size)
142
{
143
#if CONFIG_MEMALIGN_HACK
144 145
    int diff;
#endif
146

147
    /* let's disallow possibly ambiguous cases */
148
    if (size > (max_alloc_size - 32))
149 150
        return NULL;

151
#if CONFIG_MEMALIGN_HACK
152
    //FIXME this isn't aligned correctly, though it probably isn't needed
153 154 155
    if (!ptr)
        return av_malloc(size);
    diff = ((char *)ptr)[-1];
156
    av_assert0(diff>0 && diff<=ALIGN);
157 158 159
    ptr = realloc((char *)ptr - diff, size + diff);
    if (ptr)
        ptr = (char *)ptr + diff;
160
    return ptr;
161
#elif HAVE_ALIGNED_MALLOC
162
    return _aligned_realloc(ptr, size + !size, ALIGN);
163
#else
164
    return realloc(ptr, size + !size);
165
#endif
Michael Niedermayer's avatar
Michael Niedermayer committed
166 167
}

Nicolas George's avatar
Nicolas George committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
{
    size_t size;
    void *r;

    if (av_size_mult(elsize, nelem, &size)) {
        av_free(ptr);
        return NULL;
    }
    r = av_realloc(ptr, size);
    if (!r && size)
        av_free(ptr);
    return r;
}

183 184 185 186 187
int av_reallocp(void *ptr, size_t size)
{
    void **ptrptr = ptr;
    void *ret;

188 189 190 191
    if (!size) {
        av_freep(ptr);
        return 0;
    }
192 193 194 195 196 197 198 199 200 201 202
    ret = av_realloc(*ptrptr, size);

    if (!ret) {
        av_freep(ptr);
        return AVERROR(ENOMEM);
    }

    *ptrptr = ret;
    return 0;
}

203 204
void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
{
205
    if (!size || nmemb >= INT_MAX / size)
206 207 208 209 210 211 212
        return NULL;
    return av_realloc(ptr, nmemb * size);
}

int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
{
    void **ptrptr = ptr;
213
    *ptrptr = av_realloc_f(*ptrptr, nmemb, size);
214
    if (!*ptrptr && nmemb && size)
215 216 217 218
        return AVERROR(ENOMEM);
    return 0;
}

219 220
void av_free(void *ptr)
{
221
#if CONFIG_MEMALIGN_HACK
222 223 224 225 226
    if (ptr) {
        int v= ((char *)ptr)[-1];
        av_assert0(v>0 && v<=ALIGN);
        free((char *)ptr - v);
    }
227 228
#elif HAVE_ALIGNED_MALLOC
    _aligned_free(ptr);
229
#else
230
    free(ptr);
231
#endif
232 233
}

234 235
void av_freep(void *arg)
{
236
    void **ptr = (void **)arg;
237 238 239 240
    av_free(*ptr);
    *ptr = NULL;
}

241
void *av_mallocz(size_t size)
242
{
243
    void *ptr = av_malloc(size);
244 245 246 247 248
    if (ptr)
        memset(ptr, 0, size);
    return ptr;
}

Laurent Aimar's avatar
Laurent Aimar committed
249 250 251 252 253 254 255
void *av_calloc(size_t nmemb, size_t size)
{
    if (size <= 0 || nmemb >= INT_MAX / size)
        return NULL;
    return av_mallocz(nmemb * size);
}

256 257
char *av_strdup(const char *s)
{
258 259
    char *ptr = NULL;
    if (s) {
Michael Niedermayer's avatar
Michael Niedermayer committed
260
        int len = strlen(s) + 1;
261
        ptr = av_realloc(NULL, len);
Michael Niedermayer's avatar
Michael Niedermayer committed
262 263
        if (ptr)
            memcpy(ptr, s, len);
264
    }
265 266 267
    return ptr;
}

268 269 270 271 272 273 274 275 276 277 278
void *av_memdup(const void *p, size_t size)
{
    void *ptr = NULL;
    if (p) {
        ptr = av_malloc(size);
        if (ptr)
            memcpy(ptr, p, size);
    }
    return ptr;
}

279 280 281 282 283 284 285 286 287
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
{
    /* see similar ffmpeg.c:grow_array() */
    int nb, nb_alloc;
    intptr_t *tab;

    nb = *nb_ptr;
    tab = *(intptr_t**)tab_ptr;
    if ((nb & (nb - 1)) == 0) {
288
        if (nb == 0) {
289
            nb_alloc = 1;
290 291 292
        } else {
            if (nb > INT_MAX / (2 * sizeof(intptr_t)))
                goto fail;
293
            nb_alloc = nb * 2;
294
        }
295
        tab = av_realloc(tab, nb_alloc * sizeof(intptr_t));
296 297
        if (!tab)
            goto fail;
298 299 300 301
        *(intptr_t**)tab_ptr = tab;
    }
    tab[nb++] = (intptr_t)elem;
    *nb_ptr = nb;
302 303 304 305 306
    return;

fail:
    av_freep(tab_ptr);
    *nb_ptr = 0;
307
}
308

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
                       const uint8_t *elem_data)
{
    int nb = *nb_ptr, nb_alloc;
    uint8_t *tab = *tab_ptr, *tab_elem_data;

    if ((nb & (nb - 1)) == 0) {
        if (nb == 0) {
            nb_alloc = 1;
        } else {
            if (nb > INT_MAX / (2 * elem_size))
                goto fail;
            nb_alloc = nb * 2;
        }
        tab = av_realloc(tab, nb_alloc * elem_size);
        if (!tab)
            goto fail;
        *tab_ptr = tab;
    }
    *nb_ptr = nb + 1;
    tab_elem_data = tab + nb*elem_size;
    if (elem_data)
        memcpy(tab_elem_data, elem_data, elem_size);
    else if (CONFIG_MEMORY_POISONING)
        memset(tab_elem_data, FF_MEMORY_POISON, elem_size);
    return tab_elem_data;

fail:
    av_freep(tab_ptr);
    *nb_ptr = 0;
    return NULL;
}

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
static void fill16(uint8_t *dst, int len)
{
    uint32_t v = AV_RN16(dst - 2);

    v |= v << 16;

    while (len >= 4) {
        AV_WN32(dst, v);
        dst += 4;
        len -= 4;
    }

    while (len--) {
        *dst = dst[-2];
        dst++;
    }
}

static void fill24(uint8_t *dst, int len)
{
#if HAVE_BIGENDIAN
    uint32_t v = AV_RB24(dst - 3);
    uint32_t a = v << 8  | v >> 16;
    uint32_t b = v << 16 | v >> 8;
    uint32_t c = v << 24 | v;
#else
    uint32_t v = AV_RL24(dst - 3);
    uint32_t a = v       | v << 24;
    uint32_t b = v >> 8  | v << 16;
    uint32_t c = v >> 16 | v << 8;
#endif

    while (len >= 12) {
        AV_WN32(dst,     a);
        AV_WN32(dst + 4, b);
        AV_WN32(dst + 8, c);
        dst += 12;
        len -= 12;
    }

    if (len >= 4) {
        AV_WN32(dst, a);
        dst += 4;
        len -= 4;
    }

    if (len >= 4) {
        AV_WN32(dst, b);
        dst += 4;
        len -= 4;
    }

    while (len--) {
        *dst = dst[-3];
        dst++;
    }
}

static void fill32(uint8_t *dst, int len)
{
    uint32_t v = AV_RN32(dst - 4);

    while (len >= 4) {
        AV_WN32(dst, v);
        dst += 4;
        len -= 4;
    }

    while (len--) {
        *dst = dst[-4];
        dst++;
    }
}

416 417 418
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
{
    const uint8_t *src = &dst[-back];
419 420 421
    if (!back)
        return;

422 423
    if (back == 1) {
        memset(dst, *src, cnt);
424 425 426 427 428 429
    } else if (back == 2) {
        fill16(dst, cnt);
    } else if (back == 3) {
        fill24(dst, cnt);
    } else if (back == 4) {
        fill32(dst, cnt);
430
    } else {
431
        if (cnt >= 16) {
432 433 434 435 436 437 438 439
            int blocklen = back;
            while (cnt > blocklen) {
                memcpy(dst, src, blocklen);
                dst       += blocklen;
                cnt       -= blocklen;
                blocklen <<= 1;
            }
            memcpy(dst, src, cnt);
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
            return;
        }
        if (cnt >= 8) {
            AV_COPY32U(dst,     src);
            AV_COPY32U(dst + 4, src + 4);
            src += 8;
            dst += 8;
            cnt -= 8;
        }
        if (cnt >= 4) {
            AV_COPY32U(dst, src);
            src += 4;
            dst += 4;
            cnt -= 4;
        }
        if (cnt >= 2) {
            AV_COPY16U(dst, src);
            src += 2;
            dst += 2;
            cnt -= 2;
460
        }
461 462
        if (cnt)
            *dst = *src;
463 464
    }
}
465