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