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-07-28 15:35
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 : #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" /* locally disable maybe warnings */
41 8943 : if (0!=memtrack_addblock( l_tmp, Size, File,Line,CompilDate,CompilTime,Function)) {
42 : #pragma GCC diagnostic pop /* restore previous diag context */
43 : /* If tracking fails, the whole allocation fails */
44 1618 : free(l_tmp);
45 1618 : l_tmp = NULL;
46 : };
47 :
48 8943 : return l_tmp;
49 : }
50 :
51 : /* Documented in header file */
52 5538 : void dbg_free(
53 : void* Ptr,
54 : const char* File,
55 : const int Line,
56 : const char* CompilDate,
57 : const char* CompilTime,
58 : const char* Function
59 : )
60 : {
61 : /* If the pointer was not NULL, it was tracked, remove it from the tracked
62 : * list. If it was not tracked, removing returns an error. Abort the
63 : * process as it should never have an untracked pointer. Either it was
64 : * allocated from a non instrumented binary, or it was allocated from
65 : * a non monitored function (see memory.h) or there is a bug in the
66 : * memory leak tracker. */
67 5538 : if (NULL!=Ptr)
68 4752 : if (0!=memtrack_delblock(Ptr,File,Line,CompilDate,CompilTime,Function))
69 8 : abort();
70 :
71 : /* If the pointer was NULL or tracked, forward it to the real free */
72 5530 : free(Ptr);
73 5530 : }
74 :
75 : /* Documented in header file */
76 924 : void* dbg_calloc(
77 : const size_t NMemb,
78 : const size_t Size,
79 : const char* File,
80 : const int Line,
81 : const char* CompilDate,
82 : const char* CompilTime,
83 : const char* Function
84 : )
85 : {
86 : void* l_tmp;
87 :
88 : /* Use the dbg_malloc function to allocate the memory */
89 924 : l_tmp = dbg_malloc(
90 : NMemb*Size,
91 : File,Line,CompilDate,CompilTime,Function);
92 :
93 : /* Implement the calloc specific behavior compared to simple malloc:
94 : * it fills the allocated memory block with 0 */
95 924 : if (NULL != l_tmp)
96 18 : memset((char*)l_tmp, 0, NMemb*Size);
97 :
98 924 : return l_tmp;
99 : }
100 :
101 : /* Documented in header file */
102 1558 : void* dbg_realloc(
103 : void* Ptr,
104 : const size_t Size,
105 : const char* File,
106 : const int Line,
107 : const char* CompilDate,
108 : const char* CompilTime,
109 : const char* Function
110 : )
111 : {
112 : size_t l_oldsize; /**< Existing bloc size */
113 : char *newblk; /**< New block */
114 :
115 : /* NULL is not tracked but valid */
116 1558 : if (NULL==Ptr) {
117 450 : l_oldsize=0;
118 : } else {
119 : /* Fetch existing block size */
120 1108 : l_oldsize = memtrack_getblocksize(Ptr);
121 :
122 : /* This is probably a bug in the memory tracker.
123 : * It should not track zero sized blocks */
124 1108 : if (0==l_oldsize)
125 16 : abort();
126 : }
127 :
128 : /* If new size is 0, then act as free, like realloc */
129 1542 : if (0==Size) {
130 198 : dbg_free(Ptr,
131 : File,Line,CompilDate,CompilTime,Function
132 : );
133 198 : return Ptr;
134 : }
135 :
136 : /* New sized block allocation to simulate the worst case scenario and
137 : * test a pointer change, a data loss (in case of shrink) */
138 1344 : newblk=(char*)dbg_malloc(
139 : Size,
140 : File,Line,CompilDate,CompilTime,Function
141 : );
142 : /* The new block can fail */
143 : /* The real realloc function could succeed here, in case of inplace
144 : * shrink in an OOM situation. */
145 1344 : if (NULL == newblk) return (newblk);
146 :
147 : /* Copy only the relevant data from old block to new block, loosing extra
148 : * data in case of shrink, and not initializing new data in case of
149 : * increase */
150 414 : memcpy(newblk,(char*)Ptr,(l_oldsize<Size?l_oldsize:Size));
151 :
152 : /* Free old block */
153 414 : dbg_free(
154 : Ptr,
155 : File,Line,CompilDate,CompilTime,Function
156 : );
157 :
158 414 : return (void*) newblk;
159 : }
160 :
161 :
162 : /* Documented in header file */
163 1803 : char* dbg_strdup(
164 : const char* Ptr,
165 : const char* File,
166 : const int Line,
167 : const char* CompilDate,
168 : const char* CompilTime,
169 : const char* Function
170 : )
171 : {
172 : char* l_newblk; /** Copy address */
173 :
174 : /* Use strdup to actually copy the string with its own return values and
175 : * abort (SIGSEGV in case of NULL) */
176 1803 : l_newblk=NULL;
177 1803 : l_newblk=strdup(Ptr);
178 :
179 : /* If the copy succeeded, try to track the memory allocation */
180 1791 : if (NULL != l_newblk)
181 1360 : if (0!=memtrack_addblock(
182 : l_newblk,
183 1360 : strlen(l_newblk)+1,
184 : File,Line,CompilDate,CompilTime,Function
185 : )) {
186 : /* If tracking fails, the whole operation is reverted and fails */
187 1270 : free(l_newblk);
188 1270 : l_newblk=NULL;
189 : };
190 :
191 1791 : return l_newblk;
192 : }
193 :
194 :
195 : /* Documented in header file */
196 1060 : int dbg_asprintf(char **p_Ptr,
197 : const char* p_Format,
198 : const char *File,
199 : const int Line,
200 : const char *CompilDate,
201 : const char *CompilTime, const char *Function,
202 : ...)
203 : {
204 : int l_returncode;
205 :
206 : /* NULL is not allowed, where would we store the result, then ? */
207 1060 : if(NULL==p_Ptr)
208 4 : abort();
209 :
210 : /* Limit the scope of the variadic manipulation variables */
211 : {
212 : va_list l_ap;
213 1056 : va_start (l_ap, Function);
214 : /* Use the original vasprintf to build the formatted string */
215 : /** @todo Implement a vasprintf wrapping function to catch allocation
216 : * and use it here */
217 1056 : l_returncode = vasprintf(p_Ptr, p_Format, l_ap);
218 1056 : va_end(l_ap);
219 : }
220 :
221 : /* If formatting succeeded, try to track the memory allocation */
222 1056 : if (-1 != l_returncode)
223 558 : if (1==memtrack_addblock(
224 : *p_Ptr,
225 558 : strlen (*p_Ptr)+1,
226 : File,Line,CompilDate,CompilTime,Function
227 : )) {
228 : /* If tracking fails, the whole operation is reverted and fails */
229 528 : free(*p_Ptr);
230 528 : l_returncode=-2;
231 : };
232 :
233 1056 : return l_returncode;
234 : }
235 :
|