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
#define ALIGN (HAVE_AVX512 ? 64 : (HAVE_AVX ? 32 : 16))
65

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

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

Diego Biurrun's avatar
Diego Biurrun committed
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 95 96
#else
    ptr = memalign(size, ALIGN);
#endif
97
    /* Why 64?
98 99 100 101 102 103 104
     * 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!
105
     */
106 107 108
    /* 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
109
     */
110 111 112 113 114 115 116 117 118 119
    /* 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
120
     */
121 122 123
#else
    ptr = malloc(size);
#endif
124 125
    if(!ptr && !size) {
        size = 1;
126
        ptr= av_malloc(1);
127 128 129
    }
#if CONFIG_MEMORY_POISONING
    if (ptr)
130
        memset(ptr, FF_MEMORY_POISON, size);
131
#endif
132 133 134
    return ptr;
}

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 140
        return NULL;

Diego Biurrun's avatar
Diego Biurrun committed
141
#if HAVE_ALIGNED_MALLOC
142
    return _aligned_realloc(ptr, size + !size, ALIGN);
143
#else
144
    return realloc(ptr, size + !size);
145
#endif
Michael Niedermayer's avatar
Michael Niedermayer committed
146 147
}

Nicolas George's avatar
Nicolas George committed
148 149 150 151 152 153 154 155 156 157
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);
Zhao Zhili's avatar
Zhao Zhili committed
158
    if (!r)
Nicolas George's avatar
Nicolas George committed
159 160 161 162
        av_free(ptr);
    return r;
}

163 164
int av_reallocp(void *ptr, size_t size)
{
165
    void *val;
166

167 168 169 170
    if (!size) {
        av_freep(ptr);
        return 0;
    }
171

172 173 174 175
    memcpy(&val, ptr, sizeof(val));
    val = av_realloc(val, size);

    if (!val) {
176 177 178 179
        av_freep(ptr);
        return AVERROR(ENOMEM);
    }

180
    memcpy(ptr, &val, sizeof(val));
181 182 183
    return 0;
}

184 185 186 187 188 189 190 191 192 193 194 195 196 197
void *av_malloc_array(size_t nmemb, size_t size)
{
    if (!size || nmemb >= INT_MAX / size)
        return NULL;
    return av_malloc(nmemb * size);
}

void *av_mallocz_array(size_t nmemb, size_t size)
{
    if (!size || nmemb >= INT_MAX / size)
        return NULL;
    return av_mallocz(nmemb * size);
}

198 199
void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
{
200
    if (!size || nmemb >= INT_MAX / size)
201 202 203 204 205 206
        return NULL;
    return av_realloc(ptr, nmemb * size);
}

int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
{
207 208 209
    void *val;

    memcpy(&val, ptr, sizeof(val));
210 211 212
    val = av_realloc_f(val, nmemb, size);
    memcpy(ptr, &val, sizeof(val));
    if (!val && nmemb && size)
213
        return AVERROR(ENOMEM);
214

215 216 217
    return 0;
}

218 219
void av_free(void *ptr)
{
Diego Biurrun's avatar
Diego Biurrun committed
220
#if HAVE_ALIGNED_MALLOC
221
    _aligned_free(ptr);
222
#else
223
    free(ptr);
224
#endif
225 226
}

227 228
void av_freep(void *arg)
{
229 230 231 232 233
    void *val;

    memcpy(&val, arg, sizeof(val));
    memcpy(arg, &(void *){ NULL }, sizeof(val));
    av_free(val);
234 235
}

236
void *av_mallocz(size_t size)
237
{
238
    void *ptr = av_malloc(size);
239 240 241 242 243
    if (ptr)
        memset(ptr, 0, size);
    return ptr;
}

Laurent Aimar's avatar
Laurent Aimar committed
244 245 246 247 248 249 250
void *av_calloc(size_t nmemb, size_t size)
{
    if (size <= 0 || nmemb >= INT_MAX / size)
        return NULL;
    return av_mallocz(nmemb * size);
}

251 252
char *av_strdup(const char *s)
{
253 254
    char *ptr = NULL;
    if (s) {
255
        size_t len = strlen(s) + 1;
256
        ptr = av_realloc(NULL, len);
Michael Niedermayer's avatar
Michael Niedermayer committed
257 258
        if (ptr)
            memcpy(ptr, s, len);
259
    }
260 261 262
    return ptr;
}

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
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;
}

283 284 285 286 287 288 289 290 291 292 293
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;
}

294 295
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
{
296 297
    void **tab;
    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 304 305 306 307
    }, {
        return AVERROR(ENOMEM);
    });
    return 0;
}

308 309
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
{
310 311
    void **tab;
    memcpy(&tab, tab_ptr, sizeof(tab));
312

313
    FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
314
        tab[*nb_ptr] = elem;
315
        memcpy(tab_ptr, &tab, sizeof(tab));
316 317 318 319
    }, {
        *nb_ptr = 0;
        av_freep(tab_ptr);
    });
320
}
321

322 323 324
void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
                       const uint8_t *elem_data)
{
325 326
    uint8_t *tab_elem_data = NULL;

327
    FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
328 329 330 331 332 333 334 335 336
        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;
    });
337 338 339
    return tab_elem_data;
}

340 341 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
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);

402 403 404 405 406 407 408 409 410 411 412 413
#if HAVE_FAST_64BIT
    uint64_t v2= v + ((uint64_t)v<<32);
    while (len >= 32) {
        AV_WN64(dst   , v2);
        AV_WN64(dst+ 8, v2);
        AV_WN64(dst+16, v2);
        AV_WN64(dst+24, v2);
        dst += 32;
        len -= 32;
    }
#endif

414 415 416 417 418 419 420 421 422 423 424 425
    while (len >= 4) {
        AV_WN32(dst, v);
        dst += 4;
        len -= 4;
    }

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

426 427 428
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
{
    const uint8_t *src = &dst[-back];
429 430 431
    if (!back)
        return;

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

476 477
void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
{
478
    if (min_size <= *size)
479 480
        return ptr;

481 482 483 484 485 486
    if (min_size > max_alloc_size - 32) {
        *size = 0;
        return NULL;
    }

    min_size = FFMIN(max_alloc_size - 32, FFMAX(min_size + min_size / 16 + 32, min_size));
487 488 489 490 491 492 493 494 495 496 497 498 499

    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;
}

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

505 506 507 508
void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
{
    ff_fast_malloc(ptr, size, min_size, 1);
}