LCOV - code coverage report
Current view: top level - src/libavutil - mem.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 176 205 85.9 %
Date: 2017-01-21 09:32:20 Functions: 22 24 91.7 %

          Line data    Source code
       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             : 
      54             : void *malloc(size_t size);
      55             : void *memalign(size_t align, size_t size);
      56             : int   posix_memalign(void **ptr, size_t align, size_t size);
      57             : void *realloc(void *ptr, size_t size);
      58             : void  free(void *ptr);
      59             : 
      60             : #endif /* MALLOC_PREFIX */
      61             : 
      62             : #include "mem_internal.h"
      63             : 
      64             : #define ALIGN (HAVE_AVX ? 32 : 16)
      65             : 
      66             : /* NOTE: if you want to override these functions with your own
      67             :  * implementations (not recommended) you have to link libav* as
      68             :  * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags.
      69             :  * Note that this will cost performance. */
      70             : 
      71             : static size_t max_alloc_size= INT_MAX;
      72             : 
      73           0 : void av_max_alloc(size_t max){
      74           0 :     max_alloc_size = max;
      75           0 : }
      76             : 
      77    53038431 : void *av_malloc(size_t size)
      78             : {
      79    53038431 :     void *ptr = NULL;
      80             : #if CONFIG_MEMALIGN_HACK
      81             :     long diff;
      82             : #endif
      83             : 
      84             :     /* let's disallow possibly ambiguous cases */
      85    53038431 :     if (size > (max_alloc_size - 32))
      86           0 :         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             :     ptr               = (char *)ptr + diff;
      94             :     ((char *)ptr)[-1] = diff;
      95             : #elif HAVE_POSIX_MEMALIGN
      96    53038431 :     if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
      97    53036225 :     if (posix_memalign(&ptr, ALIGN, size))
      98           0 :         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             : #else
     105             :     ptr = memalign(size, ALIGN);
     106             : #endif
     107             :     /* Why 64?
     108             :      * Indeed, we should align it:
     109             :      *   on  4 for 386
     110             :      *   on 16 for 486
     111             :      *   on 32 for 586, PPro - K6-III
     112             :      *   on 64 for K7 (maybe for P3 too).
     113             :      * Because L1 and L2 caches are aligned on those values.
     114             :      * But I don't want to code such logic here!
     115             :      */
     116             :     /* Why 32?
     117             :      * For AVX ASM. SSE / NEON needs only 16.
     118             :      * Why not larger? Because I did not see a difference in benchmarks ...
     119             :      */
     120             :     /* benchmarks with P3
     121             :      * memalign(64) + 1          3071, 3051, 3032
     122             :      * memalign(64) + 2          3051, 3032, 3041
     123             :      * memalign(64) + 4          2911, 2896, 2915
     124             :      * memalign(64) + 8          2545, 2554, 2550
     125             :      * memalign(64) + 16         2543, 2572, 2563
     126             :      * memalign(64) + 32         2546, 2545, 2571
     127             :      * memalign(64) + 64         2570, 2533, 2558
     128             :      *
     129             :      * BTW, malloc seems to do 8-byte alignment by default here.
     130             :      */
     131             : #else
     132             :     ptr = malloc(size);
     133             : #endif
     134    53038437 :     if(!ptr && !size) {
     135        2205 :         size = 1;
     136        2205 :         ptr= av_malloc(1);
     137             :     }
     138             : #if CONFIG_MEMORY_POISONING
     139    53038437 :     if (ptr)
     140    53038437 :         memset(ptr, FF_MEMORY_POISON, size);
     141             : #endif
     142    53038437 :     return ptr;
     143             : }
     144             : 
     145     9829183 : void *av_realloc(void *ptr, size_t size)
     146             : {
     147             : #if CONFIG_MEMALIGN_HACK
     148             :     int diff;
     149             : #endif
     150             : 
     151             :     /* let's disallow possibly ambiguous cases */
     152     9829183 :     if (size > (max_alloc_size - 32))
     153           0 :         return NULL;
     154             : 
     155             : #if CONFIG_MEMALIGN_HACK
     156             :     //FIXME this isn't aligned correctly, though it probably isn't needed
     157             :     if (!ptr)
     158             :         return av_malloc(size);
     159             :     diff = ((char *)ptr)[-1];
     160             :     av_assert0(diff>0 && diff<=ALIGN);
     161             :     ptr = realloc((char *)ptr - diff, size + diff);
     162             :     if (ptr)
     163             :         ptr = (char *)ptr + diff;
     164             :     return ptr;
     165             : #elif HAVE_ALIGNED_MALLOC
     166             :     return _aligned_realloc(ptr, size + !size, ALIGN);
     167             : #else
     168     9829183 :     return realloc(ptr, size + !size);
     169             : #endif
     170             : }
     171             : 
     172       50935 : void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
     173             : {
     174             :     size_t size;
     175             :     void *r;
     176             : 
     177       50935 :     if (av_size_mult(elsize, nelem, &size)) {
     178           0 :         av_free(ptr);
     179           0 :         return NULL;
     180             :     }
     181       50935 :     r = av_realloc(ptr, size);
     182       50935 :     if (!r)
     183           0 :         av_free(ptr);
     184       50935 :     return r;
     185             : }
     186             : 
     187       32877 : int av_reallocp(void *ptr, size_t size)
     188             : {
     189             :     void *val;
     190             : 
     191       32877 :     if (!size) {
     192           9 :         av_freep(ptr);
     193           9 :         return 0;
     194             :     }
     195             : 
     196       32868 :     memcpy(&val, ptr, sizeof(val));
     197       32868 :     val = av_realloc(val, size);
     198             : 
     199       32868 :     if (!val) {
     200           0 :         av_freep(ptr);
     201           0 :         return AVERROR(ENOMEM);
     202             :     }
     203             : 
     204       32868 :     memcpy(ptr, &val, sizeof(val));
     205       32868 :     return 0;
     206             : }
     207             : 
     208     5840906 : void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
     209             : {
     210     5840906 :     if (!size || nmemb >= INT_MAX / size)
     211           0 :         return NULL;
     212     5840906 :     return av_realloc(ptr, nmemb * size);
     213             : }
     214             : 
     215        3478 : int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
     216             : {
     217             :     void *val;
     218             : 
     219        3478 :     memcpy(&val, ptr, sizeof(val));
     220        3478 :     val = av_realloc_f(val, nmemb, size);
     221        3478 :     memcpy(ptr, &val, sizeof(val));
     222        3478 :     if (!val && nmemb && size)
     223           0 :         return AVERROR(ENOMEM);
     224             : 
     225        3478 :     return 0;
     226             : }
     227             : 
     228    77415785 : void av_free(void *ptr)
     229             : {
     230             : #if CONFIG_MEMALIGN_HACK
     231             :     if (ptr) {
     232             :         int v= ((char *)ptr)[-1];
     233             :         av_assert0(v>0 && v<=ALIGN);
     234             :         free((char *)ptr - v);
     235             :     }
     236             : #elif HAVE_ALIGNED_MALLOC
     237             :     _aligned_free(ptr);
     238             : #else
     239    77415785 :     free(ptr);
     240             : #endif
     241    77415785 : }
     242             : 
     243    34628579 : void av_freep(void *arg)
     244             : {
     245             :     void *val;
     246             : 
     247    34628579 :     memcpy(&val, arg, sizeof(val));
     248    34628579 :     memcpy(arg, &(void *){ NULL }, sizeof(val));
     249    34628579 :     av_free(val);
     250    34628583 : }
     251             : 
     252    11881563 : void *av_mallocz(size_t size)
     253             : {
     254    11881563 :     void *ptr = av_malloc(size);
     255    11881563 :     if (ptr)
     256    11881563 :         memset(ptr, 0, size);
     257    11881563 :     return ptr;
     258             : }
     259             : 
     260       13272 : void *av_calloc(size_t nmemb, size_t size)
     261             : {
     262       13272 :     if (size <= 0 || nmemb >= INT_MAX / size)
     263           0 :         return NULL;
     264       13272 :     return av_mallocz(nmemb * size);
     265             : }
     266             : 
     267     2563333 : char *av_strdup(const char *s)
     268             : {
     269     2563333 :     char *ptr = NULL;
     270     2563333 :     if (s) {
     271     1730016 :         size_t len = strlen(s) + 1;
     272     1730016 :         ptr = av_realloc(NULL, len);
     273     1730016 :         if (ptr)
     274     1730016 :             memcpy(ptr, s, len);
     275             :     }
     276     2563333 :     return ptr;
     277             : }
     278             : 
     279           0 : char *av_strndup(const char *s, size_t len)
     280             : {
     281           0 :     char *ret = NULL, *end;
     282             : 
     283           0 :     if (!s)
     284           0 :         return NULL;
     285             : 
     286           0 :     end = memchr(s, 0, len);
     287           0 :     if (end)
     288           0 :         len = end - s;
     289             : 
     290           0 :     ret = av_realloc(NULL, len + 1);
     291           0 :     if (!ret)
     292           0 :         return NULL;
     293             : 
     294           0 :     memcpy(ret, s, len);
     295           0 :     ret[len] = 0;
     296           0 :     return ret;
     297             : }
     298             : 
     299       86276 : void *av_memdup(const void *p, size_t size)
     300             : {
     301       86276 :     void *ptr = NULL;
     302       86276 :     if (p) {
     303       81402 :         ptr = av_malloc(size);
     304       81402 :         if (ptr)
     305       81402 :             memcpy(ptr, p, size);
     306             :     }
     307       86276 :     return ptr;
     308             : }
     309             : 
     310          22 : int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
     311             : {
     312             :     void **tab;
     313          22 :     memcpy(&tab, tab_ptr, sizeof(tab));
     314             : 
     315          22 :     FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
     316             :         tab[*nb_ptr] = elem;
     317             :         memcpy(tab_ptr, &tab, sizeof(tab));
     318             :     }, {
     319             :         return AVERROR(ENOMEM);
     320             :     });
     321          22 :     return 0;
     322             : }
     323             : 
     324       27399 : void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
     325             : {
     326             :     void **tab;
     327       27399 :     memcpy(&tab, tab_ptr, sizeof(tab));
     328             : 
     329       27399 :     FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
     330             :         tab[*nb_ptr] = elem;
     331             :         memcpy(tab_ptr, &tab, sizeof(tab));
     332             :     }, {
     333             :         *nb_ptr = 0;
     334             :         av_freep(tab_ptr);
     335             :     });
     336       27399 : }
     337             : 
     338      431233 : void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
     339             :                        const uint8_t *elem_data)
     340             : {
     341      431233 :     uint8_t *tab_elem_data = NULL;
     342             : 
     343      431233 :     FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
     344             :         tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
     345             :         if (elem_data)
     346             :             memcpy(tab_elem_data, elem_data, elem_size);
     347             :         else if (CONFIG_MEMORY_POISONING)
     348             :             memset(tab_elem_data, FF_MEMORY_POISON, elem_size);
     349             :     }, {
     350             :         av_freep(tab_ptr);
     351             :         *nb_ptr = 0;
     352             :     });
     353      431233 :     return tab_elem_data;
     354             : }
     355             : 
     356       37823 : static void fill16(uint8_t *dst, int len)
     357             : {
     358       37823 :     uint32_t v = AV_RN16(dst - 2);
     359             : 
     360       37823 :     v |= v << 16;
     361             : 
     362      978047 :     while (len >= 4) {
     363      902401 :         AV_WN32(dst, v);
     364      902401 :         dst += 4;
     365      902401 :         len -= 4;
     366             :     }
     367             : 
     368      138880 :     while (len--) {
     369       63234 :         *dst = dst[-2];
     370       63234 :         dst++;
     371             :     }
     372       37823 : }
     373             : 
     374         502 : static void fill24(uint8_t *dst, int len)
     375             : {
     376             : #if HAVE_BIGENDIAN
     377             :     uint32_t v = AV_RB24(dst - 3);
     378             :     uint32_t a = v << 8  | v >> 16;
     379             :     uint32_t b = v << 16 | v >> 8;
     380             :     uint32_t c = v << 24 | v;
     381             : #else
     382         502 :     uint32_t v = AV_RL24(dst - 3);
     383         502 :     uint32_t a = v       | v << 24;
     384         502 :     uint32_t b = v >> 8  | v << 16;
     385         502 :     uint32_t c = v >> 16 | v << 8;
     386             : #endif
     387             : 
     388        1352 :     while (len >= 12) {
     389         348 :         AV_WN32(dst,     a);
     390         348 :         AV_WN32(dst + 4, b);
     391         348 :         AV_WN32(dst + 8, c);
     392         348 :         dst += 12;
     393         348 :         len -= 12;
     394             :     }
     395             : 
     396         502 :     if (len >= 4) {
     397         139 :         AV_WN32(dst, a);
     398         139 :         dst += 4;
     399         139 :         len -= 4;
     400             :     }
     401             : 
     402         502 :     if (len >= 4) {
     403          13 :         AV_WN32(dst, b);
     404          13 :         dst += 4;
     405          13 :         len -= 4;
     406             :     }
     407             : 
     408        2164 :     while (len--) {
     409        1160 :         *dst = dst[-3];
     410        1160 :         dst++;
     411             :     }
     412         502 : }
     413             : 
     414        9904 : static void fill32(uint8_t *dst, int len)
     415             : {
     416        9904 :     uint32_t v = AV_RN32(dst - 4);
     417             : 
     418      636309 :     while (len >= 4) {
     419      616501 :         AV_WN32(dst, v);
     420      616501 :         dst += 4;
     421      616501 :         len -= 4;
     422             :     }
     423             : 
     424       22074 :     while (len--) {
     425        2266 :         *dst = dst[-4];
     426        2266 :         dst++;
     427             :     }
     428        9904 : }
     429             : 
     430      653750 : void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
     431             : {
     432      653750 :     const uint8_t *src = &dst[-back];
     433      653750 :     if (!back)
     434           0 :         return;
     435             : 
     436      653750 :     if (back == 1) {
     437        4422 :         memset(dst, *src, cnt);
     438      649328 :     } else if (back == 2) {
     439       37823 :         fill16(dst, cnt);
     440      611505 :     } else if (back == 3) {
     441         502 :         fill24(dst, cnt);
     442      611003 :     } else if (back == 4) {
     443        9904 :         fill32(dst, cnt);
     444             :     } else {
     445      601099 :         if (cnt >= 16) {
     446       85275 :             int blocklen = back;
     447      185662 :             while (cnt > blocklen) {
     448       15112 :                 memcpy(dst, src, blocklen);
     449       15112 :                 dst       += blocklen;
     450       15112 :                 cnt       -= blocklen;
     451       15112 :                 blocklen <<= 1;
     452             :             }
     453       85275 :             memcpy(dst, src, cnt);
     454       85275 :             return;
     455             :         }
     456      515824 :         if (cnt >= 8) {
     457      107412 :             AV_COPY32U(dst,     src);
     458      107412 :             AV_COPY32U(dst + 4, src + 4);
     459      107412 :             src += 8;
     460      107412 :             dst += 8;
     461      107412 :             cnt -= 8;
     462             :         }
     463      515824 :         if (cnt >= 4) {
     464      376931 :             AV_COPY32U(dst, src);
     465      376931 :             src += 4;
     466      376931 :             dst += 4;
     467      376931 :             cnt -= 4;
     468             :         }
     469      515824 :         if (cnt >= 2) {
     470      184318 :             AV_COPY16U(dst, src);
     471      184318 :             src += 2;
     472      184318 :             dst += 2;
     473      184318 :             cnt -= 2;
     474             :         }
     475      515824 :         if (cnt)
     476      107745 :             *dst = *src;
     477             :     }
     478             : }
     479             : 
     480     1203378 : void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
     481             : {
     482     1203378 :     if (min_size < *size)
     483     1139841 :         return ptr;
     484             : 
     485       63537 :     min_size = FFMAX(min_size + min_size / 16 + 32, min_size);
     486             : 
     487       63537 :     ptr = av_realloc(ptr, min_size);
     488             :     /* we could set this to the unmodified min_size but this is safer
     489             :      * if the user lost the ptr and uses NULL now
     490             :      */
     491       63537 :     if (!ptr)
     492           0 :         min_size = 0;
     493             : 
     494       63537 :     *size = min_size;
     495             : 
     496       63537 :     return ptr;
     497             : }
     498             : 
     499       68972 : void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
     500             : {
     501       68972 :     ff_fast_malloc(ptr, size, min_size, 0);
     502       68972 : }
     503             : 
     504       63338 : void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
     505             : {
     506       63338 :     ff_fast_malloc(ptr, size, min_size, 1);
     507       63338 : }

Generated by: LCOV version 1.12