LCOV - code coverage report
Current view: top level - src/debug - memdbg.c (source / functions) Hit Total Coverage
Test: mkernel.info Lines: 53 53 100.0 %
Date: 2024-08-25 14:31:25 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /**         @file  memdbg.c
       2             :  *         @brief  Memory leak tracker implementation
       3             :  *          @date  25/09/2006
       4             :  *        @author  François Cerbelle (Fanfan), francois@cerbelle.net
       5             :  *     @copyright  Copyright (c) 1997-2024, François Cerbelle
       6             :  *
       7             :  *  Originally inspired by "L'art du code", Steve Maguire, Microsoft Press
       8             :  *
       9             :  *   @internal
      10             :  *       Compiler  gcc
      11             :  *  Last modified  2024-08-21 19:31
      12             :  *   Organization  Cerbelle.net
      13             :  *        Company  Home
      14             :  *
      15             :  *   This source code is released for free distribution under the terms of the
      16             :  *   GNU General Public License as published by the Free Software Foundation.
      17             :  */
      18             : 
      19             : #include "memdbg.h"
      20             : #include <string.h> /* memset, memcpy, memmove */
      21             : #include <stdio.h> /* asprintf */
      22             : #include <stdarg.h> /* va_list, va_start, va_arg, va_end */
      23             : 
      24             : /* Documented in header file */
      25        9995 : void* dbg_malloc(
      26             :     const size_t Size,
      27             :     const char* File,
      28             :     const int Line,
      29             :     const char* CompilDate,
      30             :     const char* CompilTime,
      31             :     const char* Function
      32             : )
      33             : {
      34             :     /* Memory allocation */
      35        9995 :     void* l_tmp = malloc(Size);
      36        9995 :     if (NULL == l_tmp) return (l_tmp);
      37             : 
      38             :     /* If successful, track the memory block */
      39             : #pragma GCC diagnostic push                             /* save the actual diag context */
      40             : #ifdef __clang__
      41             : #elif __GNUC__
      42             : #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"  /* locally disable maybe warnings */
      43             : #elif _MSC_VER
      44             :     /*usually has the version number in _MSC_VER*/
      45             : #elif __BORLANDC__
      46             : #elif __MINGW32__
      47             : #endif
      48        8943 :     if (0!=memtrack_addblock( l_tmp, Size, File,Line,CompilDate,CompilTime,Function)) {
      49             : #pragma GCC diagnostic pop                              /* restore previous diag context */
      50             :         /* If tracking fails, the whole allocation fails */
      51        1618 :         free(l_tmp);
      52        1618 :         l_tmp = NULL;
      53             :     };
      54             : 
      55        8943 :     return l_tmp;
      56             : }
      57             : 
      58             : /* Documented in header file */
      59        5542 : void dbg_free(
      60             :     void* Ptr,
      61             :     const char* File,
      62             :     const int Line,
      63             :     const char* CompilDate,
      64             :     const char* CompilTime,
      65             :     const char* Function
      66             : )
      67             : {
      68             :     /* If the pointer was not NULL, it was tracked, remove it from the tracked
      69             :      * list. If it was not tracked, removing returns an error. Abort the
      70             :      * process as it should never have an untracked pointer. Either it was
      71             :      * allocated from a non instrumented binary, or it was allocated from
      72             :      * a non monitored function (see memory.h) or there is a bug in the
      73             :      * memory leak tracker. */
      74        5542 :     if (NULL!=Ptr)
      75        4756 :         if (0!=memtrack_delblock(Ptr,File,Line,CompilDate,CompilTime,Function))
      76           8 :             abort();
      77             : 
      78             :     /* If the pointer was NULL or tracked, forward it to the real free */
      79        5534 :     free(Ptr);
      80        5534 : }
      81             : 
      82             : /* Documented in header file */
      83         924 : void* dbg_calloc(
      84             :     const size_t NMemb,
      85             :     const size_t Size,
      86             :     const char* File,
      87             :     const int Line,
      88             :     const char* CompilDate,
      89             :     const char* CompilTime,
      90             :     const char* Function
      91             : )
      92             : {
      93             :     void* l_tmp;
      94             : 
      95             :     /* Use the dbg_malloc function to allocate the memory */
      96         924 :     l_tmp = dbg_malloc(
      97             :                 NMemb*Size,
      98             :                 File,Line,CompilDate,CompilTime,Function);
      99             : 
     100             :     /* Implement the calloc specific behavior compared to simple malloc:
     101             :      * it fills the allocated memory block with 0 */
     102         924 :     if (NULL != l_tmp)
     103          18 :         memset((char*)l_tmp, 0, NMemb*Size);
     104             : 
     105         924 :     return l_tmp;
     106             : }
     107             : 
     108             : /* Documented in header file */
     109        1558 : void* dbg_realloc(
     110             :     void* Ptr,
     111             :     const size_t Size,
     112             :     const char* File,
     113             :     const int Line,
     114             :     const char* CompilDate,
     115             :     const char* CompilTime,
     116             :     const char* Function
     117             : )
     118             : {
     119             :     size_t l_oldsize; /**< Existing bloc size */
     120             :     char *newblk;                               /**< New block */
     121             : 
     122             :     /* NULL is not tracked but valid */
     123        1558 :     if (NULL==Ptr) {
     124         450 :         l_oldsize=0;
     125             :     } else {
     126             :         /* Fetch existing block size */
     127        1108 :         l_oldsize = memtrack_getblocksize(Ptr);
     128             : 
     129             :         /* This is probably a bug in the memory tracker.
     130             :          * It should not track zero sized blocks */
     131        1108 :         if (0==l_oldsize)
     132          16 :             abort();
     133             :     }
     134             : 
     135             :     /* If new size is 0, then act as free, like realloc */
     136        1542 :     if (0==Size) {
     137         198 :         dbg_free(Ptr,
     138             :                  File,Line,CompilDate,CompilTime,Function
     139             :                 );
     140         198 :         return Ptr;
     141             :     }
     142             : 
     143             :     /* New sized block allocation to simulate the worst case scenario and
     144             :      * test a pointer change, a data loss (in case of shrink) */
     145        1344 :     newblk=(char*)dbg_malloc(
     146             :                Size,
     147             :                File,Line,CompilDate,CompilTime,Function
     148             :            );
     149             :     /* The new block can fail */
     150             :     /* The real realloc function could succeed here, in case of inplace
     151             :      * shrink in an OOM situation. */
     152        1344 :     if (NULL == newblk) return (newblk);
     153             : 
     154             :     /* Copy only the relevant data from old block to new block, loosing extra
     155             :      * data in case of shrink, and not initializing new data in case of
     156             :      * increase */
     157         414 :     memcpy(newblk,(char*)Ptr,(l_oldsize<Size?l_oldsize:Size));
     158             : 
     159             :     /* Free old block */
     160         414 :     dbg_free(
     161             :         Ptr,
     162             :         File,Line,CompilDate,CompilTime,Function
     163             :     );
     164             : 
     165         414 :     return (void*) newblk;
     166             : }
     167             : 
     168             : 
     169             : /* Documented in header file */
     170        1807 : char* dbg_strdup(
     171             :     const char* Ptr,
     172             :     const char* File,
     173             :     const int Line,
     174             :     const char* CompilDate,
     175             :     const char* CompilTime,
     176             :     const char* Function
     177             : )
     178             : {
     179             :     char* l_newblk;                             /** Copy address */
     180             : 
     181             :     /* Use strdup to actually copy the string with its own return values and
     182             :      * abort (SIGSEGV in case of NULL) */
     183        1807 :     l_newblk=NULL;
     184        1807 :     l_newblk=strdup(Ptr);
     185             : 
     186             :     /* If the copy succeeded, try to track the memory allocation */
     187        1795 :     if (NULL != l_newblk)
     188        1364 :         if (0!=memtrack_addblock(
     189             :                 l_newblk,
     190        1364 :                 strlen(l_newblk)+1,
     191             :                 File,Line,CompilDate,CompilTime,Function
     192             :             )) {
     193             :             /* If tracking fails, the whole operation is reverted and fails */
     194        1270 :             free(l_newblk);
     195        1270 :             l_newblk=NULL;
     196             :         };
     197             : 
     198        1795 :     return l_newblk;
     199             : }
     200             : 
     201             : 
     202             : /* Documented in header file */
     203        1060 : int dbg_asprintf(char **p_Ptr,
     204             :                  const char* p_Format,
     205             :                  const char *File,
     206             :                  const int Line,
     207             :                  const char *CompilDate,
     208             :                  const char *CompilTime, const char *Function,
     209             :                  ...)
     210             : {
     211             :     int l_returncode;
     212             : 
     213             :     /* NULL is not allowed, where would we store the result, then ? */
     214        1060 :     if(NULL==p_Ptr)
     215           4 :         abort();
     216             : 
     217             :     /* Limit the scope of the variadic manipulation variables */
     218             :     {
     219             :         va_list l_ap;
     220        1056 :         va_start (l_ap, Function);
     221             :         /* Use the original vasprintf to build the formatted string */
     222             :         /** @todo Implement a vasprintf wrapping function to catch allocation
     223             :          * and use it here */
     224        1056 :         l_returncode = vasprintf(p_Ptr, p_Format, l_ap);
     225        1056 :         va_end(l_ap);
     226             :     }
     227             : 
     228             :     /* If formatting succeeded, try to track the memory allocation */
     229        1056 :     if (-1 != l_returncode)
     230         558 :         if (1==memtrack_addblock(
     231             :                 *p_Ptr,
     232         558 :                 strlen (*p_Ptr)+1,
     233             :                 File,Line,CompilDate,CompilTime,Function
     234             :             )) {
     235             :             /* If tracking fails, the whole operation is reverted and fails */
     236         528 :             free(*p_Ptr);
     237         528 :             l_returncode=-2;
     238             :         };
     239             : 
     240        1056 :     return l_returncode;
     241             : }
     242             : 

Generated by: LCOV version 1.16