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 <stdatomic.h> 35#include <string.h> 36#if HAVE_MALLOC_H 37#include <malloc.h> 38#endif 39 40#include "attributes.h" 41#include "avassert.h" 42#include "dynarray.h" 43#include "error.h" 44#include "internal.h" 45#include "intreadwrite.h" 46#include "macros.h" 47#include "mem.h" 48 49#ifdef MALLOC_PREFIX 50 51#define malloc AV_JOIN(MALLOC_PREFIX, malloc) 52#define memalign AV_JOIN(MALLOC_PREFIX, memalign) 53#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign) 54#define realloc AV_JOIN(MALLOC_PREFIX, realloc) 55#define free AV_JOIN(MALLOC_PREFIX, free) 56 57void *malloc(size_t size); 58void *memalign(size_t align, size_t size); 59int posix_memalign(void **ptr, size_t align, size_t size); 60void *realloc(void *ptr, size_t size); 61void free(void *ptr); 62 63#endif /* MALLOC_PREFIX */ 64 65#define ALIGN (HAVE_AVX512 ? 64 : (HAVE_AVX ? 32 : 16)) 66 67/* NOTE: if you want to override these functions with your own 68 * implementations (not recommended) you have to link libav* as 69 * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags. 70 * Note that this will cost performance. */ 71 72static atomic_size_t max_alloc_size = ATOMIC_VAR_INIT(INT_MAX); 73 74void av_max_alloc(size_t max){ 75 atomic_store_explicit(&max_alloc_size, max, memory_order_relaxed); 76} 77 78static int size_mult(size_t a, size_t b, size_t *r) 79{ 80 size_t t; 81 82#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_mul_overflow) 83 if (__builtin_mul_overflow(a, b, &t)) 84 return AVERROR(EINVAL); 85#else 86 t = a * b; 87 /* Hack inspired from glibc: don't try the division if nelem and elsize 88 * are both less than sqrt(SIZE_MAX). */ 89 if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b) 90 return AVERROR(EINVAL); 91#endif 92 *r = t; 93 return 0; 94} 95 96void *av_malloc(size_t size) 97{ 98 void *ptr = NULL; 99 100 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed)) 101 return NULL; 102 103#if HAVE_POSIX_MEMALIGN 104 if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation 105 if (posix_memalign(&ptr, ALIGN, size)) 106 ptr = NULL; 107#elif HAVE_ALIGNED_MALLOC 108 ptr = _aligned_malloc(size, ALIGN); 109#elif HAVE_MEMALIGN 110#ifndef __DJGPP__ 111 ptr = memalign(ALIGN, size); 112#else 113 ptr = memalign(size, ALIGN); 114#endif 115 /* Why 64? 116 * Indeed, we should align it: 117 * on 4 for 386 118 * on 16 for 486 119 * on 32 for 586, PPro - K6-III 120 * on 64 for K7 (maybe for P3 too). 121 * Because L1 and L2 caches are aligned on those values. 122 * But I don't want to code such logic here! 123 */ 124 /* Why 32? 125 * For AVX ASM. SSE / NEON needs only 16. 126 * Why not larger? Because I did not see a difference in benchmarks ... 127 */ 128 /* benchmarks with P3 129 * memalign(64) + 1 3071, 3051, 3032 130 * memalign(64) + 2 3051, 3032, 3041 131 * memalign(64) + 4 2911, 2896, 2915 132 * memalign(64) + 8 2545, 2554, 2550 133 * memalign(64) + 16 2543, 2572, 2563 134 * memalign(64) + 32 2546, 2545, 2571 135 * memalign(64) + 64 2570, 2533, 2558 136 * 137 * BTW, malloc seems to do 8-byte alignment by default here. 138 */ 139#else 140 ptr = malloc(size); 141#endif 142 if(!ptr && !size) { 143 size = 1; 144 ptr= av_malloc(1); 145 } 146#if CONFIG_MEMORY_POISONING 147 if (ptr) 148 memset(ptr, FF_MEMORY_POISON, size); 149#endif 150 return ptr; 151} 152 153void *av_realloc(void *ptr, size_t size) 154{ 155 void *ret; 156 if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed)) 157 return NULL; 158 159#if HAVE_ALIGNED_MALLOC 160 ret = _aligned_realloc(ptr, size + !size, ALIGN); 161#else 162 ret = realloc(ptr, size + !size); 163#endif 164#if CONFIG_MEMORY_POISONING 165 if (ret && !ptr) 166 memset(ret, FF_MEMORY_POISON, size); 167#endif 168 return ret; 169} 170 171void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) 172{ 173 size_t size; 174 void *r; 175 176 if (size_mult(elsize, nelem, &size)) { 177 av_free(ptr); 178 return NULL; 179 } 180 r = av_realloc(ptr, size); 181 if (!r) 182 av_free(ptr); 183 return r; 184} 185 186int av_reallocp(void *ptr, size_t size) 187{ 188 void *val; 189 190 if (!size) { 191 av_freep(ptr); 192 return 0; 193 } 194 195 memcpy(&val, ptr, sizeof(val)); 196 val = av_realloc(val, size); 197 198 if (!val) { 199 av_freep(ptr); 200 return AVERROR(ENOMEM); 201 } 202 203 memcpy(ptr, &val, sizeof(val)); 204 return 0; 205} 206 207void *av_malloc_array(size_t nmemb, size_t size) 208{ 209 size_t result; 210 if (size_mult(nmemb, size, &result) < 0) 211 return NULL; 212 return av_malloc(result); 213} 214 215#if FF_API_AV_MALLOCZ_ARRAY 216void *av_mallocz_array(size_t nmemb, size_t size) 217{ 218 size_t result; 219 if (size_mult(nmemb, size, &result) < 0) 220 return NULL; 221 return av_mallocz(result); 222} 223#endif 224 225void *av_realloc_array(void *ptr, size_t nmemb, size_t size) 226{ 227 size_t result; 228 if (size_mult(nmemb, size, &result) < 0) 229 return NULL; 230 return av_realloc(ptr, result); 231} 232 233int av_reallocp_array(void *ptr, size_t nmemb, size_t size) 234{ 235 void *val; 236 237 memcpy(&val, ptr, sizeof(val)); 238 val = av_realloc_f(val, nmemb, size); 239 memcpy(ptr, &val, sizeof(val)); 240 if (!val && nmemb && size) 241 return AVERROR(ENOMEM); 242 243 return 0; 244} 245 246void av_free(void *ptr) 247{ 248#if HAVE_ALIGNED_MALLOC 249 _aligned_free(ptr); 250#else 251 free(ptr); 252#endif 253} 254 255void av_freep(void *arg) 256{ 257 void *val; 258 259 memcpy(&val, arg, sizeof(val)); 260 memcpy(arg, &(void *){ NULL }, sizeof(val)); 261 av_free(val); 262} 263 264void *av_mallocz(size_t size) 265{ 266 void *ptr = av_malloc(size); 267 if (ptr) 268 memset(ptr, 0, size); 269 return ptr; 270} 271 272void *av_calloc(size_t nmemb, size_t size) 273{ 274 size_t result; 275 if (size_mult(nmemb, size, &result) < 0) 276 return NULL; 277 return av_mallocz(result); 278} 279 280char *av_strdup(const char *s) 281{ 282 char *ptr = NULL; 283 if (s) { 284 size_t len = strlen(s) + 1; 285 ptr = av_realloc(NULL, len); 286 if (ptr) 287 memcpy(ptr, s, len); 288 } 289 return ptr; 290} 291 292char *av_strndup(const char *s, size_t len) 293{ 294 char *ret = NULL, *end; 295 296 if (!s) 297 return NULL; 298 299 end = memchr(s, 0, len); 300 if (end) 301 len = end - s; 302 303 ret = av_realloc(NULL, len + 1); 304 if (!ret) 305 return NULL; 306 307 memcpy(ret, s, len); 308 ret[len] = 0; 309 return ret; 310} 311 312void *av_memdup(const void *p, size_t size) 313{ 314 void *ptr = NULL; 315 if (p) { 316 ptr = av_malloc(size); 317 if (ptr) 318 memcpy(ptr, p, size); 319 } 320 return ptr; 321} 322 323int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem) 324{ 325 void **tab; 326 memcpy(&tab, tab_ptr, sizeof(tab)); 327 328 FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { 329 tab[*nb_ptr] = elem; 330 memcpy(tab_ptr, &tab, sizeof(tab)); 331 }, { 332 return AVERROR(ENOMEM); 333 }); 334 return 0; 335} 336 337void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem) 338{ 339 void **tab; 340 memcpy(&tab, tab_ptr, sizeof(tab)); 341 342 FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { 343 tab[*nb_ptr] = elem; 344 memcpy(tab_ptr, &tab, sizeof(tab)); 345 }, { 346 *nb_ptr = 0; 347 av_freep(tab_ptr); 348 }); 349} 350 351void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, 352 const uint8_t *elem_data) 353{ 354 uint8_t *tab_elem_data = NULL; 355 356 FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, { 357 tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size; 358 if (elem_data) 359 memcpy(tab_elem_data, elem_data, elem_size); 360 else if (CONFIG_MEMORY_POISONING) 361 memset(tab_elem_data, FF_MEMORY_POISON, elem_size); 362 }, { 363 av_freep(tab_ptr); 364 *nb_ptr = 0; 365 }); 366 return tab_elem_data; 367} 368 369static void fill16(uint8_t *dst, int len) 370{ 371 uint32_t v = AV_RN16(dst - 2); 372 373 v |= v << 16; 374 375 while (len >= 4) { 376 AV_WN32(dst, v); 377 dst += 4; 378 len -= 4; 379 } 380 381 while (len--) { 382 *dst = dst[-2]; 383 dst++; 384 } 385} 386 387static void fill24(uint8_t *dst, int len) 388{ 389#if HAVE_BIGENDIAN 390 uint32_t v = AV_RB24(dst - 3); 391 uint32_t a = v << 8 | v >> 16; 392 uint32_t b = v << 16 | v >> 8; 393 uint32_t c = v << 24 | v; 394#else 395 uint32_t v = AV_RL24(dst - 3); 396 uint32_t a = v | v << 24; 397 uint32_t b = v >> 8 | v << 16; 398 uint32_t c = v >> 16 | v << 8; 399#endif 400 401 while (len >= 12) { 402 AV_WN32(dst, a); 403 AV_WN32(dst + 4, b); 404 AV_WN32(dst + 8, c); 405 dst += 12; 406 len -= 12; 407 } 408 409 if (len >= 4) { 410 AV_WN32(dst, a); 411 dst += 4; 412 len -= 4; 413 } 414 415 if (len >= 4) { 416 AV_WN32(dst, b); 417 dst += 4; 418 len -= 4; 419 } 420 421 while (len--) { 422 *dst = dst[-3]; 423 dst++; 424 } 425} 426 427static void fill32(uint8_t *dst, int len) 428{ 429 uint32_t v = AV_RN32(dst - 4); 430 431#if HAVE_FAST_64BIT 432 uint64_t v2= v + ((uint64_t)v<<32); 433 while (len >= 32) { 434 AV_WN64(dst , v2); 435 AV_WN64(dst+ 8, v2); 436 AV_WN64(dst+16, v2); 437 AV_WN64(dst+24, v2); 438 dst += 32; 439 len -= 32; 440 } 441#endif 442 443 while (len >= 4) { 444 AV_WN32(dst, v); 445 dst += 4; 446 len -= 4; 447 } 448 449 while (len--) { 450 *dst = dst[-4]; 451 dst++; 452 } 453} 454 455void av_memcpy_backptr(uint8_t *dst, int back, int cnt) 456{ 457 const uint8_t *src = &dst[-back]; 458 if (!back) 459 return; 460 461 if (back == 1) { 462 memset(dst, *src, cnt); 463 } else if (back == 2) { 464 fill16(dst, cnt); 465 } else if (back == 3) { 466 fill24(dst, cnt); 467 } else if (back == 4) { 468 fill32(dst, cnt); 469 } else { 470 if (cnt >= 16) { 471 int blocklen = back; 472 while (cnt > blocklen) { 473 memcpy(dst, src, blocklen); 474 dst += blocklen; 475 cnt -= blocklen; 476 blocklen <<= 1; 477 } 478 memcpy(dst, src, cnt); 479 return; 480 } 481 if (cnt >= 8) { 482 AV_COPY32U(dst, src); 483 AV_COPY32U(dst + 4, src + 4); 484 src += 8; 485 dst += 8; 486 cnt -= 8; 487 } 488 if (cnt >= 4) { 489 AV_COPY32U(dst, src); 490 src += 4; 491 dst += 4; 492 cnt -= 4; 493 } 494 if (cnt >= 2) { 495 AV_COPY16U(dst, src); 496 src += 2; 497 dst += 2; 498 cnt -= 2; 499 } 500 if (cnt) 501 *dst = *src; 502 } 503} 504 505void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) 506{ 507 size_t max_size; 508 509 if (min_size <= *size) 510 return ptr; 511 512 max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed); 513 /* *size is an unsigned, so the real maximum is <= UINT_MAX. */ 514 max_size = FFMIN(max_size, UINT_MAX); 515 516 if (min_size > max_size) { 517 *size = 0; 518 return NULL; 519 } 520 521 min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size)); 522 523 ptr = av_realloc(ptr, min_size); 524 /* we could set this to the unmodified min_size but this is safer 525 * if the user lost the ptr and uses NULL now 526 */ 527 if (!ptr) 528 min_size = 0; 529 530 *size = min_size; 531 532 return ptr; 533} 534 535static inline void fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc) 536{ 537 size_t max_size; 538 void *val; 539 540 memcpy(&val, ptr, sizeof(val)); 541 if (min_size <= *size) { 542 av_assert0(val || !min_size); 543 return; 544 } 545 546 max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed); 547 /* *size is an unsigned, so the real maximum is <= UINT_MAX. */ 548 max_size = FFMIN(max_size, UINT_MAX); 549 550 if (min_size > max_size) { 551 av_freep(ptr); 552 *size = 0; 553 return; 554 } 555 min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size)); 556 av_freep(ptr); 557 val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size); 558 memcpy(ptr, &val, sizeof(val)); 559 if (!val) 560 min_size = 0; 561 *size = min_size; 562 return; 563} 564 565void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size) 566{ 567 fast_malloc(ptr, size, min_size, 0); 568} 569 570void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size) 571{ 572 fast_malloc(ptr, size, min_size, 1); 573} 574 575int av_size_mult(size_t a, size_t b, size_t *r) 576{ 577 return size_mult(a, b, r); 578} 579