LCOV - code coverage report
Current view: top level - utils - alloc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 210 251 83.7 %
Date: 2021-04-29 23:48:07 Functions: 30 30 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *          Authors: Romain Bouqueau - Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2010-2018
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / common tools sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #if defined(__GNUC__) && __GNUC__ >= 4
      27             : #define _GNU_SOURCE
      28             : #endif
      29             : #include <stdio.h>
      30             : #include <stdarg.h>
      31             : #include <string.h>
      32             : 
      33             : 
      34             : #define STD_MALLOC      0
      35             : #define GOOGLE_MALLOC   1
      36             : #define INTEL_MALLOC    2
      37             : #define DL_MALLOC               3
      38             : 
      39             : #ifdef WIN32
      40             : #define USE_MALLOC      STD_MALLOC
      41             : #else
      42             : #define USE_MALLOC      STD_MALLOC
      43             : #endif
      44             : 
      45             : 
      46             : #if defined(_WIN32_WCE) && !defined(strdup)
      47             : #define strdup  _strdup
      48             : #endif
      49             : 
      50             : /*
      51             :         WARNING - you must enable C++ style compilation of this file (error.c) to be able to compile
      52             :         with google malloc. This is not set by default in the project settings.
      53             : */
      54             : #if (USE_MALLOC==GOOGLE_MALLOC)
      55             : #include <config.h>
      56             : #include <base/commandlineflags.h>
      57             : #include <google/malloc_extension.h>
      58             : 
      59             : #ifdef WIN32
      60             : #pragma comment(lib, "libtcmalloc_minimal")
      61             : #endif
      62             : 
      63             : #define MALLOC  malloc
      64             : #define CALLOC  calloc
      65             : #define REALLOC realloc
      66             : #define FREE    free
      67             : #define STRDUP(a) return strdup(a);
      68             : 
      69             : /*we must use c++ compiler for google malloc :( */
      70             : #define CDECL   extern "C"
      71             : #endif
      72             : 
      73             : #if (USE_MALLOC==INTEL_MALLOC)
      74             : #define CDECL
      75             : CDECL void * scalable_malloc(size_t size);
      76             : CDECL void * scalable_realloc(void* ptr, size_t size);
      77             : CDECL void * scalable_calloc(size_t num, size_t size);
      78             : CDECL void   scalable_free(void* ptr);
      79             : 
      80             : #ifdef WIN32
      81             : #pragma comment(lib, "tbbmalloc.lib")
      82             : #endif
      83             : 
      84             : #define MALLOC  scalable_malloc
      85             : #define CALLOC  scalable_calloc
      86             : #define REALLOC scalable_realloc
      87             : #define FREE    scalable_free
      88             : #define STRDUP(_a) if (_a) { unsigned int len = strlen(_a)+1; char *ptr = (char *) scalable_malloc(len); strcpy(ptr, _a); return ptr; } else { return NULL; }
      89             : 
      90             : #endif
      91             : 
      92             : #ifndef CDECL
      93             : #define CDECL
      94             : #endif
      95             : 
      96             : #ifndef SYMBOL_EXPORT
      97             : #if defined(__GNUC__) && __GNUC__ >= 4
      98             : #define SYMBOL_EXPORT __attribute__((visibility("default")))
      99             : #endif
     100             : #endif
     101             : 
     102             : #if (USE_MALLOC==DL_MALLOC)
     103             : 
     104             : CDECL void * dlmalloc(size_t size);
     105             : CDECL void * dlrealloc(void* ptr, size_t size);
     106             : CDECL void * dlcalloc(size_t num, size_t size);
     107             : CDECL void   dlfree(void* ptr);
     108             : 
     109             : #define MALLOC  dlmalloc
     110             : #define CALLOC  dlcalloc
     111             : #define REALLOC dlrealloc
     112             : #define FREE    dlfree
     113             : #define STRDUP(_a) if (_a) { unsigned int len = strlen(_a)+1; char *ptr = (char *) dlmalloc(len); strcpy(ptr, _a); return ptr; } else { return NULL; }
     114             : 
     115             : #endif
     116             : 
     117             : #if (USE_MALLOC==STD_MALLOC)
     118             : 
     119             : #include <stdlib.h>
     120             : 
     121             : #define MALLOC  malloc
     122             : #define CALLOC  calloc
     123             : #define REALLOC realloc
     124             : #define FREE    free
     125             : #define STRDUP(a) return strdup(a);
     126             : 
     127             : #endif
     128             : 
     129             : 
     130             : 
     131             : #ifndef _WIN32_WCE
     132             : #include <assert.h>
     133             : #endif
     134             : 
     135             : /*This is to handle cases where config.h is generated at the root of the gpac build tree (./configure)
     136             : This is only needed when building libgpac and modules when libgpac is not installed*/
     137             : #ifdef GPAC_HAVE_CONFIG_H
     138             : # include "config.h"
     139             : #else
     140             : # include <gpac/configuration.h>
     141             : #endif
     142             : 
     143             : /*GPAC memory tracking*/
     144             : #ifndef GPAC_MEMORY_TRACKING
     145             : 
     146             : #include <gpac/setup.h>
     147             : GF_EXPORT
     148             : void *gf_malloc(size_t size)
     149             : {
     150             :         return MALLOC(size);
     151             : }
     152             : GF_EXPORT
     153             : void *gf_calloc(size_t num, size_t size_of)
     154             : {
     155             :         return CALLOC(num, size_of);
     156             : }
     157             : GF_EXPORT
     158             : void *gf_realloc(void *ptr, size_t size)
     159             : {
     160             :         return REALLOC(ptr, size);
     161             : }
     162             : GF_EXPORT
     163             : void gf_free(void *ptr)
     164             : {
     165             :         FREE(ptr);
     166             : }
     167             : GF_EXPORT
     168             : char *gf_strdup(const char *str)
     169             : {
     170             :         STRDUP(str);
     171             : }
     172             : 
     173             : #else /*GPAC_MEMORY_TRACKING**/
     174             : 
     175             : 
     176             : static void gf_memory_log(unsigned int level, const char *fmt, ...);
     177             : enum
     178             : {
     179             :         /*! Disable all Log message*/
     180             :         GF_MEMORY_QUIET = 0,
     181             :         /*! Log message describes an error*/
     182             :         GF_MEMORY_ERROR = 1,
     183             :         /*! Log message describes a warning*/
     184             :         GF_MEMORY_WARNING,
     185             :         /*! Log message is informational (state, etc..)*/
     186             :         GF_MEMORY_INFO,
     187             :         /*! Log message is a debug info*/
     188             :         GF_MEMORY_DEBUG,
     189             : };
     190             : 
     191             : 
     192             : size_t gpac_allocated_memory = 0;
     193             : size_t gpac_nb_alloc_blocs = 0;
     194             : 
     195             : #ifdef _WIN32_WCE
     196             : #define assert(p)
     197             : #endif
     198             : 
     199             : //backtrace not supported on these platforms
     200             : #if defined(GPAC_CONFIG_IOS) || defined(GPAC_CONFIG_ANDROID)
     201             : #define GPAC_MEMORY_TRACKING_DISABLE_STACKTRACE
     202             : #endif
     203             : 
     204             : int gf_mem_track_enabled = 0;
     205             : 
     206             : #ifndef GPAC_MEMORY_TRACKING_DISABLE_STACKTRACE
     207             : static int gf_mem_backtrace_enabled = 0;
     208             : 
     209             : /*malloc dynamic storage needed for each alloc is STACK_PRINT_SIZE*SYMBOL_MAX_SIZE+1, keep them small!*/
     210             : #define STACK_FIRST_IDX  5 //remove the gpac memory allocator self trace
     211             : #define STACK_PRINT_SIZE 10
     212             : 
     213             : #ifdef WIN32
     214             : #define SYMBOL_MAX_SIZE  50
     215             : #include <windows.h>
     216             : /* on visual studio 2015 windows sdk 8.1 dbghelp has a typedef enum with no name that throws a warning */
     217             : #if     !defined(__GNUC__)
     218             : #pragma warning(disable: 4091)
     219             : #endif
     220             : #include <dbghelp.h>
     221             : #if     !defined(__GNUC__)
     222             : #pragma comment(lib, "dbghelp.lib")
     223             : #endif
     224             : /*memory ownership to the caller*/
     225             : static void store_backtrace(char *s_backtrace)
     226             : {
     227             :         void *stack[STACK_PRINT_SIZE];
     228             :         size_t i, frames, bt_idx = 0;
     229             :         SYMBOL_INFO *symbol;
     230             :         HANDLE process;
     231             : 
     232             :         process = GetCurrentProcess();
     233             :         SymInitialize(process, NULL, TRUE);
     234             : 
     235             :         symbol = (SYMBOL_INFO*)_alloca(sizeof(SYMBOL_INFO) + SYMBOL_MAX_SIZE);
     236             :         symbol->MaxNameLen = SYMBOL_MAX_SIZE-1;
     237             :         symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
     238             : 
     239             :         frames = CaptureStackBackTrace(STACK_FIRST_IDX, STACK_PRINT_SIZE, stack, NULL);
     240             : 
     241             :         for (i=0; i<frames; i++) {
     242             :                 int len;
     243             :                 int bt_len;
     244             :                 char *symbol_name = "unresolved";
     245             :                 SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
     246             :                 if (symbol->Name) symbol_name = (char*)symbol->Name;
     247             : 
     248             :                 bt_len = (int) strlen(symbol_name) + 10;
     249             :                 if (bt_idx + bt_len > STACK_PRINT_SIZE*SYMBOL_MAX_SIZE) {
     250             :                         gf_memory_log(GF_MEMORY_WARNING, "[MemoryInfo] Not enough space to hold backtrace - truncating\n");
     251             :                         break;
     252             :                 }
     253             : 
     254             :                 len = _snprintf(s_backtrace+bt_idx, SYMBOL_MAX_SIZE-1, "\t%02u 0x%I64X %s", (unsigned int) (frames-i-1), symbol->Address, symbol_name);
     255             :                 if (len<0) len = SYMBOL_MAX_SIZE-1;
     256             :                 s_backtrace[bt_idx+len]='\n';
     257             :                 bt_idx += (len+1);
     258             :         }
     259             :         assert(bt_idx < STACK_PRINT_SIZE*SYMBOL_MAX_SIZE);
     260             :         s_backtrace[bt_idx-1] = '\0';
     261             : }
     262             : 
     263             : #else /*WIN32*/
     264             : 
     265             : #define SYMBOL_MAX_SIZE  100
     266             : #include <execinfo.h>
     267             : 
     268             : /*memory ownership to the caller*/
     269         866 : static void store_backtrace(char *s_backtrace)
     270             : {
     271             :         size_t i, size, bt_idx=0;
     272             :         void *stack[STACK_PRINT_SIZE+STACK_FIRST_IDX];
     273             :         char **messages;
     274             : 
     275         866 :         size = backtrace(stack, STACK_PRINT_SIZE+STACK_FIRST_IDX);
     276         866 :         messages = backtrace_symbols(stack, size);
     277             : 
     278        6755 :         for (i=STACK_FIRST_IDX; i<size && messages!=NULL; ++i) {
     279        5889 :                 int bt_len = strlen(messages[i]) + 10;
     280             :                 int len;
     281             : 
     282        5889 :                 if (bt_idx + bt_len > STACK_PRINT_SIZE*SYMBOL_MAX_SIZE) {
     283           0 :                         gf_memory_log(GF_MEMORY_WARNING, "[MemoryInfo] Not enough space to hold backtrace - truncating\n");
     284           0 :                         break;
     285             :                 }
     286             : 
     287        5889 :                 len = snprintf(s_backtrace+bt_idx, SYMBOL_MAX_SIZE-1, "\t%02zu %s", i, messages[i]);
     288        5889 :                 if (len<0) len = SYMBOL_MAX_SIZE-1;
     289        5889 :                 s_backtrace[bt_idx+len]='\n';
     290        5889 :                 bt_idx += (len+1);
     291             : 
     292             :         }
     293             :         assert(bt_idx < STACK_PRINT_SIZE*SYMBOL_MAX_SIZE);
     294         866 :         s_backtrace[bt_idx-1] = '\0';
     295         866 :         free(messages);
     296         866 : }
     297             : #endif /*WIN32*/
     298             : 
     299             : 
     300             : #endif /*GPAC_MEMORY_TRACKING_DISABLE_STACKTRACE*/
     301             : 
     302             : 
     303             : static void register_address(void *ptr, size_t size, const char *filename, int line);
     304             : static int unregister_address(void *ptr, const char *filename, int line);
     305             : 
     306             : 
     307       37468 : static void *gf_mem_malloc_basic(size_t size, const char *filename, int line)
     308             : {
     309       37468 :         return MALLOC(size);
     310             : }
     311           1 : static void *gf_mem_calloc_basic(size_t num, size_t size_of, const char *filename, int line)
     312             : {
     313           1 :         return CALLOC(num, size_of);
     314             : }
     315       60269 : static void *gf_mem_realloc_basic(void *ptr, size_t size, const char *filename, int line)
     316             : {
     317       60269 :         return REALLOC(ptr, size);
     318             : }
     319      137261 : static void gf_mem_free_basic(void *ptr, const char *filename, int line)
     320             : {
     321      137261 :         FREE(ptr);
     322      137261 : }
     323       84797 : static char *gf_mem_strdup_basic(const char *str, const char *filename, int line)
     324             : {
     325       84797 :         STRDUP(str);
     326             : }
     327             : 
     328             : 
     329             : static unsigned int nb_calls_alloc = 0;
     330             : static unsigned int nb_calls_calloc = 0;
     331             : static unsigned int nb_calls_realloc = 0;
     332             : static unsigned int nb_calls_free = 0;
     333             : 
     334     9702281 : void *gf_mem_malloc_tracker(size_t size, const char *filename, int line)
     335             : {
     336     9702281 :         void *ptr = MALLOC(size);
     337     9702281 :         if (!ptr) {
     338           0 :                 gf_memory_log(GF_MEMORY_ERROR, "[MemTracker] malloc() has returned a NULL pointer\n");
     339             :                 assert(0);
     340             :         } else {
     341     9702281 :                 register_address(ptr, size, filename, line);
     342             :         }
     343     9702280 :         gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] malloc %3d bytes at %p in:\n", size, ptr);
     344     9702281 :         gf_memory_log(GF_MEMORY_DEBUG, "             file %s at line %d\n" , filename, line);
     345     9702282 :         nb_calls_alloc++;
     346     9702282 :         return ptr;
     347             : }
     348             : 
     349        4439 : void *gf_mem_calloc_tracker(size_t num, size_t size_of, const char *filename, int line)
     350             : {
     351        4439 :         size_t size = num*size_of;
     352        4439 :         void *ptr = CALLOC(num, size_of);
     353        4439 :         if (!ptr) {
     354           0 :                 gf_memory_log(GF_MEMORY_ERROR, "[MemTracker] calloc() has returned a NULL pointer\n");
     355             :                 assert(0);
     356             :         } else {
     357        4439 :                 register_address(ptr, size, filename, line);
     358             :         }
     359        4439 :         gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] calloc %3d bytes at %p in:\n", ptr, size);
     360        4439 :         gf_memory_log(GF_MEMORY_DEBUG, "             file %s at line %d\n" , filename, line);
     361        4439 :         nb_calls_calloc++;
     362        4439 :         return ptr;
     363             : }
     364             : 
     365    10141122 : void gf_mem_free_tracker(void *ptr, const char *filename, int line)
     366             : {
     367             :         int size_prev;
     368    10141122 :         if (ptr && (size_prev=unregister_address(ptr, filename, line))) {
     369     9690603 :                 gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] free   %3d bytes at %p in:\n", size_prev, ptr);
     370     9690603 :                 gf_memory_log(GF_MEMORY_DEBUG, "             file %s at line %d\n" , filename, line);
     371     9690601 :                 FREE(ptr);
     372             :         }
     373    10141122 :         nb_calls_free++;
     374    10141122 : }
     375             : 
     376     4181097 : void *gf_mem_realloc_tracker(void *ptr, size_t size, const char *filename, int line)
     377             : {
     378             :         void *ptr_g;
     379             :         int size_prev;
     380     4181097 :         if (!ptr) {
     381     1308145 :                 gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] realloc() from a null pointer: calling malloc() instead\n");
     382     1308145 :                 return gf_mem_malloc_tracker(size, filename, line);
     383             :         }
     384             :         /*a) The return value is NULL if the size is zero and the buffer argument is not NULL. In this case, the original block is freed.*/
     385     2872952 :         if (!size) {
     386           0 :                 gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] realloc() with a null size: calling free() instead\n");
     387           0 :                 gf_mem_free_tracker(ptr, filename, line);
     388           0 :                 return NULL;
     389             :         }
     390     2872952 :         size_prev = unregister_address(ptr, filename, line);
     391     2872952 :         ptr_g = REALLOC(ptr, size);
     392     2872952 :         if (!ptr_g) {
     393             :                 /*b) The return value is NULL if there is not enough available memory to expand the block to the given size. In this case, the original block is unchanged.*/
     394           0 :                 gf_memory_log(GF_MEMORY_ERROR, "[MemTracker] realloc() has returned a NULL pointer\n");
     395           0 :                 register_address(ptr, size_prev, filename, line);
     396             :                 assert(0);
     397             :         } else {
     398     2872952 :                 register_address(ptr_g, size, filename, line);
     399             : //              gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] realloc %3d (instead of %3d) bytes at %p (instead of %p)\n", size, size_prev, ptr_g, ptr);
     400     2872952 :                 gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] realloc %3d (instead of %3d) bytes at %p\n", size, size_prev, ptr_g);
     401     2872952 :                 gf_memory_log(GF_MEMORY_DEBUG, "             file %s at line %d\n" , filename, line);
     402             :         }
     403     2872952 :         nb_calls_realloc++;
     404     2872952 :         return ptr_g;
     405             : }
     406             : 
     407     1665909 : char *gf_mem_strdup_tracker(const char *str, const char *filename, int line)
     408             : {
     409             :         char *ptr;
     410     1665909 :         if (!str) return NULL;
     411     1665909 :         ptr = (char*)gf_mem_malloc_tracker(strlen(str)+1, filename, line);
     412             :         strcpy(ptr, str);
     413     1665909 :         return ptr;
     414             : }
     415             : 
     416             : 
     417             : static void *(*gf_mem_malloc_proto)(size_t size, const char *filename, int line) = gf_mem_malloc_basic;
     418             : static void *(*gf_mem_calloc_proto)(size_t num, size_t size_of, const char *filename, int line) = gf_mem_calloc_basic;
     419             : static void *(*gf_mem_realloc_proto)(void *ptr, size_t size, const char *filename, int line) = gf_mem_realloc_basic;
     420             : static void (*gf_mem_free_proto)(void *ptr, const char *filename, int line) = gf_mem_free_basic;
     421             : static char *(*gf_mem_strdup_proto)(const char *str, const char *filename, int line) = gf_mem_strdup_basic;
     422             : 
     423             : #ifndef MY_GF_EXPORT
     424             : #if defined(__GNUC__) && __GNUC__ >= 4
     425             : #define MY_GF_EXPORT __attribute__((visibility("default")))
     426             : #else
     427             : /*use def files for windows or let compiler decide*/
     428             : #define MY_GF_EXPORT
     429             : #endif
     430             : #endif
     431             : 
     432     6765687 : MY_GF_EXPORT void *gf_mem_malloc(size_t size, const char *filename, int line)
     433             : {
     434     6765687 :         return gf_mem_malloc_proto(size, filename, line);
     435             : }
     436             : 
     437        4440 : MY_GF_EXPORT void *gf_mem_calloc(size_t num, size_t size_of, const char *filename, int line)
     438             : {
     439        4440 :         return gf_mem_calloc_proto(num, size_of, filename, line);
     440             : }
     441             : 
     442             : MY_GF_EXPORT
     443     4241366 : void *gf_mem_realloc(void *ptr, size_t size, const char *filename, int line)
     444             : {
     445     4241366 :         return gf_mem_realloc_proto(ptr, size, filename, line);
     446             : }
     447             : 
     448             : MY_GF_EXPORT
     449    10278382 : void gf_mem_free(void *ptr, const char *filename, int line)
     450             : {
     451    10278382 :         gf_mem_free_proto(ptr, filename, line);
     452    10278382 : }
     453             : 
     454             : MY_GF_EXPORT
     455     1750706 : char *gf_mem_strdup(const char *str, const char *filename, int line)
     456             : {
     457     1750706 :         return gf_mem_strdup_proto(str, filename, line);
     458             : }
     459             : 
     460             : MY_GF_EXPORT
     461        6212 : void gf_mem_enable_tracker(unsigned int enable_backtrace)
     462             : {
     463             : #ifndef GPAC_MEMORY_TRACKING_DISABLE_STACKTRACE
     464        6212 :     gf_mem_backtrace_enabled = enable_backtrace ? 1 : 0;
     465             : #endif
     466        6212 :         gf_mem_track_enabled = 1;
     467        6212 :     gf_mem_malloc_proto = gf_mem_malloc_tracker;
     468        6212 :         gf_mem_calloc_proto = gf_mem_calloc_tracker;
     469        6212 :         gf_mem_realloc_proto = gf_mem_realloc_tracker;
     470        6212 :         gf_mem_free_proto = gf_mem_free_tracker;
     471        6212 :         gf_mem_strdup_proto = gf_mem_strdup_tracker;
     472        6212 : }
     473             : 
     474    67555661 : size_t gf_mem_get_stats(unsigned int *nb_allocs, unsigned int *nb_callocs, unsigned int *nb_reallocs, unsigned int *nb_free)
     475             : {
     476    67555661 :         if (nb_allocs) (*nb_allocs) = nb_calls_alloc;
     477    67555661 :         if (nb_callocs) (*nb_callocs) = nb_calls_calloc;
     478    67555661 :         if (nb_reallocs) (*nb_reallocs) = nb_calls_realloc;
     479    67555661 :         if (nb_free) (*nb_free) = nb_calls_free;
     480    67555661 :         return gpac_allocated_memory;
     481             : }
     482             : 
     483             : typedef struct s_memory_element
     484             : {
     485             :     void *ptr;
     486             :     unsigned int size;
     487             :     struct s_memory_element *next;
     488             : #ifndef GPAC_MEMORY_TRACKING_DISABLE_STACKTRACE
     489             :     char *backtrace_stack;
     490             : #endif
     491             :     int line;
     492             :     char *filename;
     493             : } memory_element;
     494             : 
     495             : /*pointer to the first element of the list*/
     496             : typedef memory_element** memory_list;
     497             : 
     498             : 
     499             : #define HASH_ENTRIES 4096
     500             : 
     501             : #if !defined(WIN32)
     502             : #include <stdint.h>
     503             : #endif
     504             : 
     505             : static unsigned int gf_memory_hash(void *ptr)
     506             : {
     507             : #if defined(WIN32)
     508             :         return (unsigned int) ( (((unsigned __int64)ptr>>4)+(unsigned __int64)ptr) % HASH_ENTRIES );
     509             : #else
     510    62830155 :         return (unsigned int) ( (((uint64_t) ((intptr_t) ptr)>>4) + (uint64_t) ((intptr_t)ptr) ) % HASH_ENTRIES );
     511             : #endif
     512             : }
     513             : 
     514             : 
     515             : /*base functions (add, find, del_item, del) are implemented upon a stack model*/
     516    25132468 : static void gf_memory_add_stack(memory_element **p, void *ptr, unsigned int size, const char *filename, int line)
     517             : {
     518    25132468 :         memory_element *element = (memory_element*)MALLOC(sizeof(memory_element));
     519    25132468 :         if (!element) {
     520           0 :                 gf_memory_log(GF_MEMORY_ERROR, ("[Mem] Fail to register stack for allocation\n"));
     521           0 :                 return;
     522             :         }
     523    25132468 :         element->ptr = ptr;
     524    25132468 :         element->size = size;
     525    25132468 :         element->line = line;
     526             : 
     527             : #ifndef GPAC_MEMORY_TRACKING_DISABLE_STACKTRACE
     528    25132468 :     if (gf_mem_backtrace_enabled) {
     529         866 :         element->backtrace_stack = MALLOC(sizeof(char) * STACK_PRINT_SIZE * SYMBOL_MAX_SIZE);
     530         866 :                 if (!element->backtrace_stack) {
     531           0 :                         gf_memory_log(GF_MEMORY_WARNING, ("[Mem] Fail to register backtrace of allocation\n"));
     532           0 :                         element->backtrace_stack = NULL;
     533             :                 } else {
     534         866 :                         store_backtrace(element->backtrace_stack);
     535             :                 }
     536             :     } else {
     537    25131602 :         element->backtrace_stack = NULL;
     538             :     }
     539             : #endif
     540             : 
     541    25132468 :         element->filename = MALLOC(strlen(filename) + 1);
     542    25132468 :         if (element->filename)
     543             :                 strcpy(element->filename, filename);
     544             : 
     545    25132468 :         element->next = *p;
     546    25132468 :         *p = element;
     547             : }
     548             : 
     549             : /*returns the position of a ptr from a memory_element, 0 if not found*/
     550             : static int gf_memory_find_stack(memory_element *p, void *ptr)
     551             : {
     552             :         int i = 1;
     553             :         memory_element *element = p;
     554    14524926 :         while (element) {
     555    14524926 :                 if (element->ptr == ptr) {
     556             :                         return i;
     557             :                 }
     558     1959707 :                 element = element->next;
     559     1959707 :                 i++;
     560             :         }
     561             :         return 0;
     562             : }
     563             : 
     564             : /*returns the size of the deleted item*/
     565    25132468 : static unsigned int gf_memory_del_item_stack(memory_element **p, void *ptr)
     566             : {
     567             :         unsigned int size;
     568    25132468 :         memory_element *curr_element=*p, *prev_element=NULL;
     569    59613014 :         while (curr_element) {
     570    26761233 :                 if (curr_element->ptr == ptr) {
     571    17413155 :                         if (prev_element) prev_element->next = curr_element->next;
     572    16733537 :                         else *p = curr_element->next;
     573    17413155 :                         size = curr_element->size;
     574             : #ifndef GPAC_MEMORY_TRACKING_DISABLE_STACKTRACE
     575    17413155 :             if (curr_element->backtrace_stack) {
     576         610 :                 FREE(curr_element->backtrace_stack);
     577             :             }
     578             : #endif
     579    17413155 :             FREE(curr_element);
     580    17413155 :                         return size;
     581             :                 }
     582             :                 prev_element = curr_element;
     583     9348078 :                 curr_element = curr_element->next;
     584             :         }
     585             :         return 0;
     586             : }
     587             : 
     588             : /*this list is implemented as a stack to minimise the cost of freeing recent allocations*/
     589    25132468 : static void gf_memory_add(memory_list *p, void *ptr, unsigned int size, const char *filename, int line)
     590             : {
     591             :         unsigned int hash;
     592    25132468 :         if (!*p) *p = (memory_list) CALLOC(HASH_ENTRIES, sizeof(memory_element*));
     593             :         assert(*p);
     594             : 
     595             :         hash = gf_memory_hash(ptr);
     596    25132468 :         gf_memory_add_stack(&((*p)[hash]), ptr, size, filename, line);
     597    25132468 : }
     598             : 
     599             : 
     600             : static int gf_memory_find(memory_list p, void *ptr)
     601             : {
     602             :         unsigned int hash;
     603             :         assert(p);
     604           0 :         if (!p) return 0;
     605             :         hash = gf_memory_hash(ptr);
     606    12565219 :         return gf_memory_find_stack(p[hash], ptr);
     607             : }
     608             : 
     609    25132468 : static unsigned int gf_memory_del_item(memory_list *p, void *ptr)
     610             : {
     611             :         unsigned int hash;
     612             :         unsigned int ret;
     613             :         memory_element **sub_list;
     614    25132468 :         if (!*p) *p = (memory_list) CALLOC(HASH_ENTRIES, sizeof(memory_element*));
     615             :         assert(*p);
     616             :         hash = gf_memory_hash(ptr);
     617    25132468 :         sub_list = &((*p)[hash]);
     618    25132468 :         if (!sub_list) return 0;
     619    25132468 :         ret = gf_memory_del_item_stack(sub_list, ptr);
     620    25132468 :         if (ret && !((*p)[hash])) {
     621             :                 /*check for deletion*/
     622             :                 int i;
     623           0 :                 for (i=0; i<HASH_ENTRIES; i++)
     624    12395005 :                         if (&((*p)[i])) break;
     625    12395005 :                 if (i==HASH_ENTRIES) {
     626           0 :                         FREE(*p);
     627             :                 }
     628             :         }
     629             :         return ret;
     630             : }
     631             : 
     632             : 
     633             : 
     634             : #endif /*GPAC_MEMORY_TRACKING*/
     635             : 
     636             : 
     637             : #include <gpac/tools.h>
     638             : 
     639             : 
     640             : /*GPAC memory tracking*/
     641             : #ifdef GPAC_MEMORY_TRACKING
     642             : 
     643             : #include <gpac/thread.h>
     644             : 
     645             : /*global lists of allocations and deallocations*/
     646             : memory_list memory_add = NULL, memory_rem = NULL;
     647             : GF_Mutex *gpac_allocations_lock = NULL;
     648             : 
     649    12579669 : static void register_address(void *ptr, size_t size, const char *filename, int line)
     650             : {
     651             :         /*mutex initialization*/
     652    12579669 :         if (gpac_allocations_lock == 0) {
     653             :                 assert(!memory_add);
     654             :                 assert(!memory_rem);
     655        6212 :                 gpac_allocations_lock = (GF_Mutex*)1; /*must be non-null to avoid a recursive infinite call*/
     656        6212 :                 gpac_allocations_lock = gf_mx_new("gpac_allocations_lock");
     657             :         }
     658    12573457 :         else if (gpac_allocations_lock == (void*)1) {
     659             :                 /*we're initializing the mutex (ie called by the gf_mx_new() above)*/
     660             :                 return;
     661             :         }
     662             : 
     663             :         /*lock*/
     664    12567246 :         gf_mx_p(gpac_allocations_lock);
     665             : 
     666    12567249 :         gf_memory_add(&memory_add, ptr, (unsigned int)size, filename, line);
     667    12567249 :         gf_memory_del_item(&memory_rem, ptr); /*the same block can be reallocated, so remove it from the deallocation list*/
     668             : 
     669             :         /*update stats*/
     670    12567249 :         gpac_allocated_memory += size;
     671    12567249 :         gpac_nb_alloc_blocs++;
     672             : 
     673             :         /*gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] register   %6d bytes at %p (%8d Bytes in %4d Blocks allocated)\n", size, ptr, gpac_allocated_memory, gpac_nb_alloc_blocs);*/
     674             : 
     675             :         /*unlock*/
     676    12567249 :         gf_mx_v(gpac_allocations_lock);
     677             : }
     678             : 
     679         140 : void log_backtrace(unsigned int log_level, memory_element *element)
     680             : {
     681             : #ifndef GPAC_MEMORY_TRACKING_DISABLE_STACKTRACE
     682         140 :     if (gf_mem_backtrace_enabled) {
     683         140 :         gf_memory_log(log_level, "file %s at line %d\n%s\n", element->filename, element->line, element->backtrace_stack);
     684             :     } else
     685             : #endif
     686             :     {
     687           0 :         gf_memory_log(log_level, "file %s at line %d\n", element->filename, element->line);
     688             :     }
     689         140 : }
     690             : 
     691             : 
     692             : #if 0 //unused
     693             : Bool gf_mem_check_address(void *ptr)
     694             : {
     695             :         Bool res = GF_TRUE;
     696             :         int pos;
     697             : 
     698             :         if (!gpac_allocations_lock) return res;
     699             : 
     700             :         /*lock*/
     701             :         gf_mx_p(gpac_allocations_lock);
     702             : 
     703             :         if ( (pos=gf_memory_find(memory_rem, ptr)) ) {
     704             :                 int i;
     705             :                 unsigned int hash = gf_memory_hash(ptr);
     706             :                 memory_element *element = memory_rem[hash];
     707             :                 assert(element);
     708             :                 for (i=1; i<pos; i++)
     709             :                         element = element->next;
     710             :                 assert(element);
     711             :                 gf_memory_log(GF_MEMORY_ERROR, "[MemTracker] the block %p was already freed in:\n", ptr);
     712             :                 res = GF_FALSE;
     713             :         log_backtrace(GF_MEMORY_ERROR, element);
     714             : //              assert(0);
     715             :         }
     716             :         /*unlock*/
     717             :         gf_mx_v(gpac_allocations_lock);
     718             :         return res;
     719             : }
     720             : #endif
     721             : 
     722             : /*returns the size of the unregistered block*/
     723    12565217 : static int unregister_address(void *ptr, const char *filename, int line)
     724             : {
     725             :         unsigned int size = 0; /*default: failure*/
     726             : 
     727             :         /*lock*/
     728    12565217 :         gf_mx_p(gpac_allocations_lock);
     729             : 
     730    12565219 :         if (!memory_add) {
     731           0 :                 if (!memory_rem) {
     732             :                         /*assume we're rather destroying the mutex (ie calling the gf_mx_del() below)
     733             :                           than being called by free() before the first allocation occured*/
     734             :                         return 1;
     735             :                         /*gf_memory_log(GF_MEMORY_ERROR, "[MemTracker] calling free() before the first allocation occured\n");
     736             :                            assert(0); */
     737             :                 }
     738             :         } else {
     739    12565219 :                 if (!gf_memory_find(memory_add, ptr)) {
     740             :                         int pos;
     741           0 :                         if (!(pos=gf_memory_find(memory_rem, ptr))) {
     742           0 :                                 gf_memory_log(GF_MEMORY_ERROR, "[MemTracker] trying to free a never allocated block (%p)\n", ptr);
     743             :                                 /* assert(0); */ /*don't assert since this is often due to allocations that occured out of gpac (fonts, etc.)*/
     744             :                         } else {
     745             :                                 int i;
     746             :                                 unsigned int hash = gf_memory_hash(ptr);
     747             :                                 memory_element *element = memory_rem[hash];
     748             : 
     749             :                                 assert(element);
     750           0 :                                 for (i=1; i<pos; i++)
     751           0 :                                         element = element->next;
     752             :                                 assert(element);
     753           0 :                                 gf_memory_log(GF_MEMORY_ERROR, "[MemTracker] the block %p trying to be deleted in:\n", ptr);
     754           0 :                                 gf_memory_log(GF_MEMORY_ERROR, "             file %s at line %d\n", filename, line);
     755           0 :                                 gf_memory_log(GF_MEMORY_ERROR, "             was already freed in:\n");
     756           0 :                                 log_backtrace(GF_MEMORY_ERROR, element);
     757             :                                 assert(0);
     758             :                         }
     759             :                 } else {
     760    12565219 :                         size = gf_memory_del_item(&memory_add, ptr);
     761             : 
     762             :                         /*update stats*/
     763    12565219 :                         gpac_allocated_memory -= size;
     764    12565219 :                         gpac_nb_alloc_blocs--;
     765             : 
     766             :                         /*gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] unregister %6d bytes at %p (%8d bytes in %4d blocks remaining)\n", size, ptr, gpac_allocated_memory, gpac_nb_alloc_blocs); */
     767             : 
     768             :                         /*the allocation list is empty: free the lists to avoid a leak (we should be exiting)*/
     769    12565219 :                         if (!memory_add) {
     770             :                                 assert(!gpac_allocated_memory);
     771             :                                 assert(!gpac_nb_alloc_blocs);
     772             : 
     773             :                                 /*we destroy the mutex we own, then we return*/
     774           0 :                                 gf_mx_del(gpac_allocations_lock);
     775           0 :                                 gpac_allocations_lock = NULL;
     776             : 
     777           0 :                                 gf_memory_log(GF_MEMORY_DEBUG, "[MemTracker] the allocated-blocks-list is empty: the freed-blocks-list will be emptied too.\n");
     778             : 
     779             :                                 //reset the freed block list
     780             :                                 memory_list *m_list = &memory_rem;
     781             :                                 int i;
     782           0 :                                 for (i=0; i<HASH_ENTRIES; i++) {
     783           0 :                                         memory_element **m_elt = &((*m_list)[i]) ;
     784             : 
     785           0 :                                         memory_element *curr_element=*m_elt, *next_element;
     786           0 :                                         while (curr_element) {
     787           0 :                                                 next_element = curr_element->next;
     788             : #ifndef GPAC_MEMORY_TRACKING_DISABLE_STACKTRACE
     789           0 :                                                 if (curr_element->backtrace_stack) {
     790           0 :                                                         FREE(curr_element->backtrace_stack);
     791             :                                                 }
     792             : #endif
     793           0 :                                                 FREE(curr_element);
     794             :                                                 curr_element = next_element;
     795             :                                         }
     796           0 :                                         *m_elt = NULL;
     797             :                                 }
     798             : 
     799           0 :                                 FREE(*m_list);
     800             : 
     801           0 :                                 return size;
     802             :                         } else {
     803    12565219 :                                 gf_memory_add(&memory_rem, ptr, size, filename, line);
     804             :                         }
     805             :                 }
     806             :         }
     807             : 
     808             :         /*unlock*/
     809    12565219 :         gf_mx_v(gpac_allocations_lock);
     810             : 
     811    12565218 :         return size;
     812             : }
     813             : 
     814    45849207 : static void gf_memory_log(unsigned int level, const char *fmt, ...)
     815             : {
     816             :         va_list vl;
     817             :         char msg[1024];
     818             :         assert(strlen(fmt) < 200);
     819    45849207 :         va_start(vl, fmt);
     820             :         vsnprintf(msg, 1024, fmt, vl);
     821    45849207 :         GF_LOG(level, GF_LOG_MEMORY, (msg));
     822    45849249 :         va_end(vl);
     823    45849249 : }
     824             : 
     825             : /*prints allocations sum-up*/
     826           1 : static void print_memory_size()
     827             : {
     828           1 :         GF_LOG(gpac_nb_alloc_blocs ? GF_MEMORY_ERROR : GF_MEMORY_INFO, GF_LOG_MEMORY, ("[MemTracker] Total: %d bytes allocated in %d blocks\n", (u32) gpac_allocated_memory,  (u32) gpac_nb_alloc_blocs ));
     829           1 : }
     830             : 
     831             : GF_EXPORT
     832        6145 : u64 gf_memory_size()
     833             : {
     834        6145 :         return (u64) gpac_allocated_memory;
     835             : }
     836             : 
     837             : /*prints the state of current allocations*/
     838             : GF_EXPORT
     839           1 : void gf_memory_print()
     840             : {
     841             :         /*if lists are empty, the mutex is also NULL*/
     842           1 :         if (!memory_add) {
     843             :                 assert(!gpac_allocations_lock);
     844           0 :                 gf_memory_log(GF_MEMORY_INFO, "[MemTracker] gf_memory_print(): the memory tracker is not initialized, some file handles are not closed.\n");
     845             :         } else {
     846           1 :                 int i=0;
     847             :                 assert(gpac_allocations_lock);
     848             :                 const char *enum_open_handles(u32 *idx);
     849           1 :                 u32 nb_handles = gf_file_handles_count();
     850             : 
     851             : 
     852           1 :                 gf_memory_log(GF_MEMORY_INFO, "\n[MemTracker] Printing the current state of allocations (%d open file handles) :\n", nb_handles);
     853             : 
     854             :                 /*lock*/
     855           1 :                 gf_mx_p(gpac_allocations_lock);
     856        4097 :                 for (i=0; i<HASH_ENTRIES; i++) {
     857        4096 :                         memory_element *curr_element = memory_add[i], *next_element;
     858        8332 :                         while (curr_element) {
     859             :                                 char szVal[51];
     860             :                                 char szHexVal[101];
     861             :                                 u32 size, j;
     862         140 :                                 next_element = curr_element->next;
     863         140 :                                 size = curr_element->size>=50 ? 50 : curr_element->size;
     864        3154 :                                 for (j=0 ; j<size ; j++) {
     865        3014 :                                         unsigned char byte = *((unsigned char*)(curr_element->ptr) + j);
     866        3014 :                                         szVal[j] = (byte > 31 && byte < 127) ? byte : '.';
     867        3014 :                                         sprintf(szHexVal+2*j, "%02X", byte);
     868             :                                 }
     869         140 :                                 szVal[size] = 0;
     870         140 :                                 szHexVal[2*size] = 0;
     871         140 :                                 gf_memory_log(GF_MEMORY_INFO, "[MemTracker] Memory Block %p (size %d) allocated in:\n", curr_element->ptr, curr_element->size);
     872         140 :                                 log_backtrace(GF_MEMORY_INFO, curr_element);
     873         140 :                                 gf_memory_log(GF_MEMORY_INFO, "             string dump: %s\n", szVal);
     874         140 :                                 gf_memory_log(GF_MEMORY_INFO, "             hex dump: %s\n", szHexVal);
     875             :                                 curr_element = next_element;
     876             :                         }
     877             :                 }
     878           1 :                 print_memory_size();
     879             :                 /*unlock*/
     880           1 :                 gf_mx_v(gpac_allocations_lock);
     881             : 
     882           1 :                 i=0;
     883           1 :                 while (1) {
     884           2 :                         const char *n = enum_open_handles(&i);
     885           2 :                         if (!n) break;
     886           1 :                         gf_memory_log(GF_MEMORY_ERROR, "[MemTracker] File %s was not closed\n", n);
     887             :                 }
     888             :         }
     889           1 : }
     890             : 
     891             : #endif /*GPAC_MEMORY_TRACKING*/
     892             : 
     893             : #if 0 //unused
     894             : 
     895             : /*gf_asprintf(): as_printf portable implementation*/
     896             : #if defined(WIN32) || defined(_WIN32_WCE) || (defined (__SVR4) && defined (__sun))
     897             : static GFINLINE int gf_vasprintf (char **strp, const char *fmt, va_list ap)
     898             : {
     899             :         int vsn_ret, size;
     900             :         char *buffer, *realloc_buffer;
     901             : 
     902             :         size = 2 * (u32) strlen(fmt); /*first guess for the size*/
     903             :         buffer = (char*)gf_malloc(size);
     904             :         if (buffer == NULL)
     905             :                 return -1;
     906             : 
     907             :         while (1) {
     908             : #if !defined(WIN32) && !defined(_WIN32_WCE)
     909             : #define _vsnprintf vsnprintf
     910             : #endif
     911             :                 vsn_ret = _vsnprintf(buffer, size, fmt, ap);
     912             : 
     913             :                 /* If that worked, return the string. */
     914             :                 if (vsn_ret>-1 && vsn_ret<size)   {
     915             :                         *strp = buffer;
     916             :                         return vsn_ret;
     917             :                 }
     918             : 
     919             :                 /*else double the allocated size*/
     920             :                 size *= 2;
     921             :                 realloc_buffer = (char*)gf_realloc(buffer, size);
     922             :                 if (!realloc_buffer)    {
     923             :                         gf_free(buffer);
     924             :                         return -1;
     925             :                 } else {
     926             :                         buffer = realloc_buffer;
     927             :                 }
     928             : 
     929             :         }
     930             : }
     931             : #endif
     932             : 
     933             : GF_EXPORT
     934             : int gf_asprintf(char **strp, const char *fmt, ...)
     935             : {
     936             :         s32 size;
     937             :         va_list args;
     938             :         va_start(args, fmt);
     939             : #if defined(WIN32) || defined(_WIN32_WCE) || (defined (__SVR4) && defined (__sun))
     940             :         size = gf_vasprintf(strp, fmt, args);
     941             : #else
     942             :         size = asprintf(strp, fmt, args);
     943             : #endif
     944             :         va_end(args);
     945             :         return size;
     946             : }
     947             : 
     948             : #endif //unused
     949             : 
     950             : /*
     951             :  * FROM: https://github.com/freebsd/freebsd-src/blob/master/sys/libkern/strlcpy.c
     952             :  *
     953             :  * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
     954             :  *
     955             :  * Permission to use, copy, modify, and distribute this software for any
     956             :  * purpose with or without fee is hereby granted, provided that the above
     957             :  * copyright notice and this permission notice appear in all copies.
     958             :  *
     959             :  */
     960             : /*
     961             :  * Copy string src to buffer dst of size dsize.  At most dsize-1
     962             :  * chars will be copied.  Always NUL terminates (unless dsize == 0).
     963             :  * Returns strlen(src); if retval >= dsize, truncation occurred.
     964             :  */
     965             : GF_EXPORT
     966        4189 : size_t gf_strlcpy(char * dst, const char * src, size_t dsize)
     967             : {
     968             :         const char *osrc = src;
     969             :         size_t nleft = dsize;
     970             : 
     971             :         /* Copy as many bytes as will fit. */
     972        4189 :         if (nleft != 0) {
     973       60421 :                 while (--nleft != 0) {
     974       60419 :                         if ((*dst++ = *src++) == '\0')
     975             :                                 break;
     976             :                 }
     977             :         }
     978             : 
     979             :         /* Not enough room in dst, add NUL and traverse rest of src. */
     980        4189 :         if (nleft == 0) {
     981           2 :                 if (dsize != 0)
     982           2 :                         *dst = '\0';            /* NUL-terminate dst */
     983          16 :                 while (*src++)
     984             :                         ;
     985             :         }
     986             : 
     987        4189 :         return(src - osrc - 1); /* count does not include NUL */
     988             : }

Generated by: LCOV version 1.13