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 :
|