mem.c 11.1 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 "common.h"
42
#include "dynarray.h"
43
#include "intreadwrite.h"
44 45
#include "mem.h"

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
#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 */

62 63
#include "mem_internal.h"

64 65
#define ALIGN (HAVE_AVX ? 32 : 16)

66 67 68 69
/* 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. */
70

71 72 73 74 75
static size_t max_alloc_size= INT_MAX;

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

77
void *av_malloc(size_t size)
78
{
79
    void *ptr = NULL;
80
#if CONFIG_MEMALIGN_HACK
81
    long diff;
82
#endif
83

84
    /* let's disallow possibly ambiguous cases */
85
    if (size > (max_alloc_size - 32))
86
        return NULL;
87

88
#if CONFIG_MEMALIGN_HACK
89
    ptr = malloc(size + ALIGN);
90
    if (!ptr)
91
        return ptr;
92
    diff              = ((~(long)ptr)&(ALIGN - 1)) + 1;
93 94
    ptr               = (char *)ptr + diff;
    ((char *)ptr)[-1] = diff;
95
#elif HAVE_POSIX_MEMALIGN
96
    if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
97
    if (posix_memalign(&ptr, ALIGN, size))
98
        ptr = NULL;
99
#elif HAVE_ALIGNED_MALLOC
100
    ptr = _aligned_malloc(size, ALIGN);
101
#elif HAVE_MEMALIGN
102
#ifndef __DJGPP__
103
    ptr = memalign(ALIGN, size);
104 105 106
#else
    ptr = memalign(size, ALIGN);
#endif
107
    /* Why 64?
108 109 110 111 112 113 114
     * 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!
115
     */
116 117 118
    /* 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
119
     */
120 121 122 123 124 125 126 127 128 129
    /* 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
130
     */
131 132 133
#else
    ptr = malloc(size);
#endif
134 135
    if(!ptr && !size) {
        size = 1;
136
        ptr= av_malloc(1);
137 138 139
    }
#if CONFIG_MEMORY_POISONING
    if (ptr)
140
        memset(ptr, FF_MEMORY_POISON, size);
141
#endif
142 143 144
    return ptr;
}

145
void *av_realloc(void *ptr, size_t size)
146
{
147
#if CONFIG_MEMALIGN_HACK
148 149
    int diff;
#endif
150

151
    /* let's disallow possibly ambiguous cases */
152
    if (size > (max_alloc_size - 32))
153 154
        return NULL;

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

Nicolas George's avatar
Nicolas George committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
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;
}

187 188
int av_reallocp(void *ptr, size_t size)
{
189
    void *val;
190

191 192 193 194
    if (!size) {
        av_freep(ptr);
        return 0;
    }
195

196 197 198 199
    memcpy(&val, ptr, sizeof(val));
    val = av_realloc(val, size);

    if (!val) {
200 201 202 203
        av_freep(ptr);
        return AVERROR(ENOMEM);
    }

204
    memcpy(ptr, &val, sizeof(val));
205 206 207
    return 0;
}

208 209
void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
{
210
    if (!size || nmemb >= INT_MAX / size)
211 212 213 214 215 216
        return NULL;
    return av_realloc(ptr, nmemb * size);
}

int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
{
217 218 219
    void *val;

    memcpy(&val, ptr, sizeof(val));
220 221 222
    val = av_realloc_f(val, nmemb, size);
    memcpy(ptr, &val, sizeof(val));
    if (!val && nmemb && size)
223
        return AVERROR(ENOMEM);
224

225 226 227
    return 0;
}

228 229
void av_free(void *ptr)
{
230
#if CONFIG_MEMALIGN_HACK
231 232 233 234 235
    if (ptr) {
        int v= ((char *)ptr)[-1];
        av_assert0(v>0 && v<=ALIGN);
        free((char *)ptr - v);
    }
236 237
#elif HAVE_ALIGNED_MALLOC
    _aligned_free(ptr);
238
#else
239
    free(ptr);
240
#endif
241 242
}

243 244
void av_freep(void *arg)
{
245 246 247 248 249
    void *val;

    memcpy(&val, arg, sizeof(val));
    memcpy(arg, &(void *){ NULL }, sizeof(val));
    av_free(val);
250 251
}

252
void *av_mallocz(size_t size)
253
{
254
    void *ptr = av_malloc(size);
255 256 257 258 259
    if (ptr)
        memset(ptr, 0, size);
    return ptr;
}

Laurent Aimar's avatar
Laurent Aimar committed
260 261 262 263 264 265 266
void *av_calloc(size_t nmemb, size_t size)
{
    if (size <= 0 || nmemb >= INT_MAX / size)
        return NULL;
    return av_mallocz(nmemb * size);
}

267 268
char *av_strdup(const char *s)
{
269 270
    char *ptr = NULL;
    if (s) {
271
        size_t len = strlen(s) + 1;
272
        ptr = av_realloc(NULL, len);
Michael Niedermayer's avatar
Michael Niedermayer committed
273 274
        if (ptr)
            memcpy(ptr, s, len);
275
    }
276 277 278
    return ptr;
}

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
char *av_strndup(const char *s, size_t len)
{
    char *ret = NULL, *end;

    if (!s)
        return NULL;

    end = memchr(s, 0, len);
    if (end)
        len = end - s;

    ret = av_realloc(NULL, len + 1);
    if (!ret)
        return NULL;

    memcpy(ret, s, len);
    ret[len] = 0;
    return ret;
}

299 300 301 302 303 304 305 306 307 308 309
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;
}

310 311
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
{
312 313
    void **tab;
    memcpy(&tab, tab_ptr, sizeof(tab));
314 315 316

    AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
        tab[*nb_ptr] = elem;
317
        memcpy(tab_ptr, &tab, sizeof(tab));
318 319 320 321 322 323
    }, {
        return AVERROR(ENOMEM);
    });
    return 0;
}

324 325
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
{
326 327
    void **tab;
    memcpy(&tab, tab_ptr, sizeof(tab));
328 329

    AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
330
        tab[*nb_ptr] = elem;
331
        memcpy(tab_ptr, &tab, sizeof(tab));
332 333 334 335
    }, {
        *nb_ptr = 0;
        av_freep(tab_ptr);
    });
336
}
337

338 339 340
void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
                       const uint8_t *elem_data)
{
341 342 343 344 345 346 347 348 349 350 351 352
    uint8_t *tab_elem_data = NULL;

    AV_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
        tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * 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);
    }, {
        av_freep(tab_ptr);
        *nb_ptr = 0;
    });
353 354 355
    return tab_elem_data;
}

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 416 417 418 419 420 421 422 423 424 425 426 427 428 429
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++;
    }
}

430 431 432
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
{
    const uint8_t *src = &dst[-back];
433 434 435
    if (!back)
        return;

436 437
    if (back == 1) {
        memset(dst, *src, cnt);
438 439 440 441 442 443
    } else if (back == 2) {
        fill16(dst, cnt);
    } else if (back == 3) {
        fill24(dst, cnt);
    } else if (back == 4) {
        fill32(dst, cnt);
444
    } else {
445
        if (cnt >= 16) {
446 447 448 449 450 451 452 453
            int blocklen = back;
            while (cnt > blocklen) {
                memcpy(dst, src, blocklen);
                dst       += blocklen;
                cnt       -= blocklen;
                blocklen <<= 1;
            }
            memcpy(dst, src, cnt);
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
            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;
474
        }
475 476
        if (cnt)
            *dst = *src;
477 478
    }
}
479

480 481 482 483 484
void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
{
    if (min_size < *size)
        return ptr;

485
    min_size = FFMAX(min_size + min_size / 16 + 32, min_size);
486 487 488 489 490 491 492 493 494 495 496 497 498

    ptr = av_realloc(ptr, min_size);
    /* we could set this to the unmodified min_size but this is safer
     * if the user lost the ptr and uses NULL now
     */
    if (!ptr)
        min_size = 0;

    *size = min_size;

    return ptr;
}

499 500 501 502 503
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
{
    ff_fast_malloc(ptr, size, min_size, 0);
}