LCOV - code coverage report
Current view: top level - src - memdbg.c (source / functions) Hit Total Coverage
Test: libdebug.info Lines: 53 53 100.0 %
Date: 2025-02-25 19:28:31 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-12-19 19:49
      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             : #define _XOPEN_SOURCE 500                       /* strdup */
      20             : #define _GNU_SOURCE                             /* vasprintf */
      21             : #include "libdebug/memdbg.h"
      22             : #include <string.h>                             /* memset, memcpy, memmove */
      23             : #include <stdio.h>                              /* asprintf */
      24             : #include <stdarg.h>                             /* va_list, va_start, va_arg, va_end */
      25             : 
      26             : /* Documented in header file */
      27         648 : void* dbg_malloc(
      28             :     const size_t Size,
      29             :     const char* File,
      30             :     const int Line,
      31             :     const char* CompilDate,
      32             :     const char* CompilTime,
      33             :     const char* Function
      34             : ) {
      35             :     /* Memory allocation */
      36         648 :     void* l_tmp = malloc(Size);
      37         648 :     if (NULL == l_tmp) return (l_tmp);
      38             : 
      39             :     /* If successful, track the memory block */
      40             : #pragma GCC diagnostic push                             /* save the actual diag context */
      41             : #ifdef __clang__
      42             : #elif __GNUC__
      43             : #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"  /* locally disable maybe warnings */
      44             : #elif _MSC_VER
      45             :     /*usually has the version number in _MSC_VER*/
      46             : #elif __BORLANDC__
      47             : #elif __MINGW32__
      48             : #endif
      49         648 :     if (0!=memtrack_addblock( l_tmp, Size, File,Line,CompilDate,CompilTime,Function)) {
      50             : #pragma GCC diagnostic pop                              /* restore previous diag context */
      51             :         /* If tracking fails, the whole allocation fails */
      52         138 :         free(l_tmp);
      53         138 :         l_tmp = NULL;
      54             :     };
      55             : 
      56         648 :     return l_tmp;
      57             : }
      58             : 
      59             : /* Documented in header file */
      60         578 : void dbg_free(
      61             :     void* Ptr,
      62             :     const char* File,
      63             :     const int Line,
      64             :     const char* CompilDate,
      65             :     const char* CompilTime,
      66             :     const char* Function
      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         578 :     if (NULL!=Ptr)
      75         512 :         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         570 :     free(Ptr);
      80         570 : }
      81             : 
      82             : /* Documented in header file */
      83          84 : 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             :     void* l_tmp;
      93             : 
      94             :     /* Use the dbg_malloc function to allocate the memory */
      95          84 :     l_tmp = dbg_malloc(
      96             :                 NMemb*Size,
      97             :                 File,Line,CompilDate,CompilTime,Function);
      98             : 
      99             :     /* Implement the calloc specific behavior compared to simple malloc:
     100             :      * it fills the allocated memory block with 0 */
     101          84 :     if (NULL != l_tmp)
     102          18 :         memset((char*)l_tmp, 0, NMemb*Size);
     103             : 
     104          84 :     return l_tmp;
     105             : }
     106             : 
     107             : /* Documented in header file */
     108         118 : void* dbg_realloc(
     109             :     void* Ptr,
     110             :     const size_t Size,
     111             :     const char* File,
     112             :     const int Line,
     113             :     const char* CompilDate,
     114             :     const char* CompilTime,
     115             :     const char* Function
     116             : ) {
     117             :     size_t l_oldsize; /**< Existing bloc size */
     118             :     char *newblk;                               /**< New block */
     119             : 
     120             :     /* NULL is not tracked but valid */
     121         118 :     if (NULL==Ptr) {
     122          30 :         l_oldsize=0;
     123             :     } else {
     124             :         /* Fetch existing block size */
     125          88 :         l_oldsize = memtrack_getblocksize(Ptr);
     126             : 
     127             :         /* This is probably a bug in the memory tracker.
     128             :          * It should not track zero sized blocks */
     129          88 :         if (0==l_oldsize)
     130          16 :             abort();
     131             :     }
     132             : 
     133             :     /* If new size is 0, then act as free, like realloc */
     134         102 :     if (0==Size) {
     135          18 :         dbg_free(Ptr,
     136             :                  File,Line,CompilDate,CompilTime,Function
     137             :                 );
     138          18 :         return Ptr;
     139             :     }
     140             : 
     141             :     /* New sized block allocation to simulate the worst case scenario and
     142             :      * test a pointer change, a data loss (in case of shrink) */
     143          84 :     newblk=(char*)dbg_malloc(
     144             :                Size,
     145             :                File,Line,CompilDate,CompilTime,Function
     146             :            );
     147             :     /* The new block can fail */
     148             :     /* The real realloc function could succeed here, in case of inplace
     149             :      * shrink in an OOM situation. */
     150          84 :     if (NULL == newblk) return (newblk);
     151             : 
     152             :     /* Copy only the relevant data from old block to new block, loosing extra
     153             :      * data in case of shrink, and not initializing new data in case of
     154             :      * increase */
     155          54 :     memcpy(newblk,(char*)Ptr,(l_oldsize<Size?l_oldsize:Size));
     156             : 
     157             :     /* Free old block */
     158          54 :     dbg_free(
     159             :         Ptr,
     160             :         File,Line,CompilDate,CompilTime,Function
     161             :     );
     162             : 
     163          54 :     return (void*) newblk;
     164             : }
     165             : 
     166             : 
     167             : /* Documented in header file */
     168          90 : char* dbg_strdup(
     169             :     const char* Ptr,
     170             :     const char* File,
     171             :     const int Line,
     172             :     const char* CompilDate,
     173             :     const char* CompilTime,
     174             :     const char* Function
     175             : ) {
     176             :     char* l_newblk;                             /** Copy address */
     177             : 
     178             :     /* Use strdup to actually copy the string with its own return values and
     179             :      * abort (SIGSEGV in case of NULL) */
     180          90 :     l_newblk=NULL;
     181          90 :     l_newblk=strdup(Ptr); /* cppcheck-suppress ctunullpointer */
     182             : 
     183             :     /* If the copy succeeded, try to track the memory allocation */
     184          78 :     if (NULL != l_newblk)
     185          78 :         if (0!=memtrack_addblock(
     186             :                     l_newblk,
     187          78 :                     strlen(l_newblk)+1,
     188             :                     File,Line,CompilDate,CompilTime,Function
     189             :                 )) {
     190             :             /* If tracking fails, the whole operation is reverted and fails */
     191          54 :             free(l_newblk);
     192          54 :             l_newblk=NULL;
     193             :         };
     194             : 
     195          78 :     return l_newblk;
     196             : }
     197             : 
     198             : 
     199             : /* Documented in header file */
     200         100 : int dbg_asprintf(char **p_Ptr,
     201             :                  const char* p_Format,
     202             :                  const char *File,
     203             :                  const int Line,
     204             :                  const char *CompilDate,
     205             :                  const char *CompilTime, const char *Function,
     206             :                  ...) {
     207             :     int l_returncode;
     208             : 
     209             :     /* NULL is not allowed, where would we store the result, then ? */
     210         100 :     if(NULL==p_Ptr)
     211           4 :         abort();
     212             : 
     213             :     /* Limit the scope of the variadic manipulation variables */
     214             :     {
     215             :         va_list l_ap;
     216          96 :         va_start (l_ap, Function);
     217             :         /* Use the original vasprintf to build the formatted string */
     218             :         /** @todo Implement a vasprintf wrapping function to catch allocation
     219             :          * and use it here */
     220          96 :         l_returncode = vasprintf(p_Ptr, p_Format, l_ap);
     221          96 :         va_end(l_ap);
     222             :     }
     223             : 
     224             :     /* If formatting succeeded, try to track the memory allocation */
     225          96 :     if (-1 != l_returncode)
     226          90 :         if (1==memtrack_addblock(
     227             :                     *p_Ptr,
     228          90 :                     strlen (*p_Ptr)+1,
     229             :                     File,Line,CompilDate,CompilTime,Function
     230             :                 )) {
     231             :             /* If tracking fails, the whole operation is reverted and fails */
     232          60 :             free(*p_Ptr);
     233          60 :             l_returncode=-2;
     234             :         };
     235             : 
     236          96 :     return l_returncode;
     237             : }
     238             : /* vim: set tw=80: */

Generated by: LCOV version 1.16