mem_track.h
1 /* mem_track.h
2  *
3  * Copyright (C) 2006-2020 wolfSSL Inc.
4  *
5  * This file is part of wolfSSL.
6  *
7  * wolfSSL is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * wolfSSL is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20  */
21 
22 
23 /* The memory tracker overrides the wolfSSL memory callback system and uses a
24  * static to track the total, peak and currently allocated bytes.
25  *
26  * If you are already using the memory callbacks then enabling this will
27  * override the memory callbacks and prevent your memory callbacks from
28  * working. This assumes malloc() and free() are available. Feel free to
29  * customize this for your needs.
30 
31  * The enable this feature define the following:
32  * #define USE_WOLFSSL_MEMORY
33  * #define WOLFSSL_TRACK_MEMORY
34  *
35  * On startup call:
36  * InitMemoryTracker();
37  *
38  * When ready to dump the memory report call:
39  * ShowMemoryTracker();
40  *
41  * Report example:
42  * total Allocs = 228
43  * total Bytes = 93442
44  * peak Bytes = 8840
45  * current Bytes = 0
46  *
47  *
48  * You can also:
49  * #define WOLFSSL_DEBUG_MEMORY
50  *
51  * To print every alloc/free along with the function and line number.
52  * Example output:
53  * Alloc: 0x7fa14a500010 -> 120 at wc_InitRng:496
54  * Free: 0x7fa14a500010 -> 120 at wc_FreeRng:606
55  */
56 
57 
58 #ifndef WOLFSSL_MEM_TRACK_H
59 #define WOLFSSL_MEM_TRACK_H
60 
61 #if defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_STATIC_MEMORY)
62 
64 
65  #if defined(WOLFSSL_TRACK_MEMORY)
66  #define DO_MEM_STATS
67  #if defined(__linux__) || defined(__MACH__)
68  #define DO_MEM_LIST
69  #endif
70  #endif
71 
72 
73  typedef struct memoryStats {
74  long totalAllocs; /* number of allocations */
75  long totalDeallocs; /* number of deallocations */
76  long totalBytes; /* total number of bytes allocated */
77  long peakBytes; /* concurrent max bytes */
78  long currentBytes; /* total current bytes in use */
79  } memoryStats;
80 
81  typedef struct memHint {
82  size_t thisSize; /* size of this memory */
83 
84  #ifdef DO_MEM_LIST
85  struct memHint* next;
86  struct memHint* prev;
87  #ifdef WOLFSSL_DEBUG_MEMORY
88  const char* func;
89  unsigned int line;
90  #endif
91  #endif
92  void* thisMemory; /* actual memory for user */
93  } memHint;
94 
95  typedef struct memoryTrack {
96  union {
97  memHint hint;
98  byte alignit[sizeof(memHint) + ((16-1) & ~(16-1))]; /* make sure we have strong alignment */
99  } u;
100  } memoryTrack;
101 
102 #ifdef DO_MEM_LIST
103  /* track allocations and report at end */
104  typedef struct memoryList {
105  memHint* head;
106  memHint* tail;
107  word32 count;
108  } memoryList;
109 #endif
110 
111 #if defined(WOLFSSL_TRACK_MEMORY)
112  static memoryStats ourMemStats;
113 
114  #ifdef DO_MEM_LIST
115  #include <pthread.h>
116  static memoryList ourMemList;
117  static pthread_mutex_t memLock = PTHREAD_MUTEX_INITIALIZER;
118  #endif
119 #endif
120 
121 
122  /* if defined to not using inline then declare function prototypes */
123  #ifdef NO_INLINE
124  #define WC_STATIC
125  #ifdef WOLFSSL_DEBUG_MEMORY
126  WOLFSSL_LOCAL void* TrackMalloc(size_t sz, const char* func, unsigned int line);
127  WOLFSSL_LOCAL void TrackFree(void* ptr, const char* func, unsigned int line);
128  WOLFSSL_LOCAL void* TrackRealloc(void* ptr, size_t sz, const char* func, unsigned int line);
129  #else
130  WOLFSSL_LOCAL void* TrackMalloc(size_t sz);
131  WOLFSSL_LOCAL void TrackFree(void* ptr);
132  WOLFSSL_LOCAL void* TrackRealloc(void* ptr, size_t sz);
133  #endif
134  WOLFSSL_LOCAL int InitMemoryTracker(void);
135  WOLFSSL_LOCAL void ShowMemoryTracker(void);
136  #else
137  #define WC_STATIC static
138  #endif
139 
140 #ifdef WOLFSSL_DEBUG_MEMORY
141  WC_STATIC WC_INLINE void* TrackMalloc(size_t sz, const char* func, unsigned int line)
142 #else
143  WC_STATIC WC_INLINE void* TrackMalloc(size_t sz)
144 #endif
145  {
146  memoryTrack* mt;
147  memHint* header;
148 
149  if (sz == 0)
150  return NULL;
151 
152  mt = (memoryTrack*)malloc(sizeof(memoryTrack) + sz);
153  if (mt == NULL)
154  return NULL;
155 
156  header = &mt->u.hint;
157  header->thisSize = sz;
158  header->thisMemory = (byte*)mt + sizeof(memoryTrack);
159 
160  #ifdef WOLFSSL_DEBUG_MEMORY
161  #ifdef WOLFSSL_DEBUG_MEMORY_PRINT
162  printf("Alloc: %p -> %u at %s:%d\n", header->thisMemory, (word32)sz, func, line);
163  #else
164  (void)func;
165  (void)line;
166  #endif
167  #endif
168 
169  #ifdef DO_MEM_STATS
170  ourMemStats.totalAllocs++;
171  ourMemStats.totalBytes += sz;
172  ourMemStats.currentBytes += sz;
173  if (ourMemStats.currentBytes > ourMemStats.peakBytes)
174  ourMemStats.peakBytes = ourMemStats.currentBytes;
175  #endif
176  #ifdef DO_MEM_LIST
177  if (pthread_mutex_lock(&memLock) == 0) {
178  #ifdef WOLFSSL_DEBUG_MEMORY
179  header->func = func;
180  header->line = line;
181  #endif
182 
183  /* Setup event */
184  header->next = NULL;
185  if (ourMemList.tail == NULL) {
186  ourMemList.head = header;
187  header->prev = NULL;
188  }
189  else {
190  ourMemList.tail->next = header;
191  header->prev = ourMemList.tail;
192  }
193  ourMemList.tail = header; /* add to the end either way */
194  ourMemList.count++;
195 
196  pthread_mutex_unlock(&memLock);
197  }
198  #endif
199 
200  return header->thisMemory;
201  }
202 
203 
204 #ifdef WOLFSSL_DEBUG_MEMORY
205  WC_STATIC WC_INLINE void TrackFree(void* ptr, const char* func, unsigned int line)
206 #else
207  WC_STATIC WC_INLINE void TrackFree(void* ptr)
208 #endif
209  {
210  memoryTrack* mt;
211  memHint* header;
212  size_t sz;
213 
214  if (ptr == NULL) {
215  return;
216  }
217 
218  mt = (memoryTrack*)((byte*)ptr - sizeof(memoryTrack));
219  header = &mt->u.hint;
220  sz = header->thisSize;
221 
222  #ifdef DO_MEM_LIST
223  if (pthread_mutex_lock(&memLock) == 0)
224  {
225  #endif
226 
227  #ifdef DO_MEM_STATS
228  ourMemStats.currentBytes -= header->thisSize;
229  ourMemStats.totalDeallocs++;
230  #endif
231 
232  #ifdef DO_MEM_LIST
233  if (header == ourMemList.head && header == ourMemList.tail) {
234  ourMemList.head = NULL;
235  ourMemList.tail = NULL;
236  }
237  else if (header == ourMemList.head) {
238  ourMemList.head = header->next;
239  ourMemList.head->prev = NULL;
240  }
241  else if (header == ourMemList.tail) {
242  ourMemList.tail = header->prev;
243  ourMemList.tail->next = NULL;
244  }
245  else {
246  memHint* next = header->next;
247  memHint* prev = header->prev;
248  if (next)
249  next->prev = prev;
250  if (prev)
251  prev->next = next;
252  }
253  ourMemList.count--;
254 
255  pthread_mutex_unlock(&memLock);
256  }
257  #endif
258 
259 #ifdef WOLFSSL_DEBUG_MEMORY
260 #ifdef WOLFSSL_DEBUG_MEMORY_PRINT
261  printf("Free: %p -> %u at %s:%d\n", ptr, (word32)sz, func, line);
262 #else
263  (void)func;
264  (void)line;
265 #endif
266 #endif
267  (void)sz;
268 
269  free(mt);
270  }
271 
272 
273 #ifdef WOLFSSL_DEBUG_MEMORY
274  WC_STATIC WC_INLINE void* TrackRealloc(void* ptr, size_t sz, const char* func, unsigned int line)
275 #else
276  WC_STATIC WC_INLINE void* TrackRealloc(void* ptr, size_t sz)
277 #endif
278  {
279  #ifdef WOLFSSL_DEBUG_MEMORY
280  void* ret = TrackMalloc(sz, func, line);
281  #else
282  void* ret = TrackMalloc(sz);
283  #endif
284 
285  if (ptr) {
286  /* if realloc is bigger, don't overread old ptr */
287  memoryTrack* mt;
288  memHint* header;
289 
290  mt = (memoryTrack*)((byte*)ptr - sizeof(memoryTrack));
291  header = &mt->u.hint;
292 
293  if (header->thisSize < sz)
294  sz = header->thisSize;
295  }
296 
297  if (ret && ptr)
298  XMEMCPY(ret, ptr, sz);
299 
300  if (ret) {
301  #ifdef WOLFSSL_DEBUG_MEMORY
302  TrackFree(ptr, func, line);
303  #else
304  TrackFree(ptr);
305  #endif
306  }
307 
308  return ret;
309  }
310 
311 #ifdef WOLFSSL_TRACK_MEMORY
312  static wolfSSL_Malloc_cb mfDefault = NULL;
313  static wolfSSL_Free_cb ffDefault = NULL;
314  static wolfSSL_Realloc_cb rfDefault = NULL;
315 
316  WC_STATIC WC_INLINE int InitMemoryTracker(void)
317  {
318  int ret;
319 
320  ret = wolfSSL_GetAllocators(&mfDefault, &ffDefault, &rfDefault);
321  if (ret < 0) {
322  printf("wolfSSL GetAllocators failed to get the defaults\n");
323  }
324  ret = wolfSSL_SetAllocators(TrackMalloc, TrackFree, TrackRealloc);
325  if (ret < 0) {
326  printf("wolfSSL SetAllocators failed for track memory\n");
327  return ret;
328  }
329 
330  #ifdef DO_MEM_LIST
331  if (pthread_mutex_lock(&memLock) == 0)
332  {
333  #endif
334 
335  #ifdef DO_MEM_STATS
336  ourMemStats.totalAllocs = 0;
337  ourMemStats.totalDeallocs = 0;
338  ourMemStats.totalBytes = 0;
339  ourMemStats.peakBytes = 0;
340  ourMemStats.currentBytes = 0;
341  #endif
342 
343  #ifdef DO_MEM_LIST
344  XMEMSET(&ourMemList, 0, sizeof(ourMemList));
345 
346  pthread_mutex_unlock(&memLock);
347  }
348  #endif
349 
350  return ret;
351  }
352 
353  WC_STATIC WC_INLINE void ShowMemoryTracker(void)
354  {
355  #ifdef DO_MEM_LIST
356  if (pthread_mutex_lock(&memLock) == 0)
357  {
358  #endif
359 
360  #ifdef DO_MEM_STATS
361  printf("total Allocs = %9ld\n", ourMemStats.totalAllocs);
362  printf("total Deallocs = %9ld\n", ourMemStats.totalDeallocs);
363  printf("total Bytes = %9ld\n", ourMemStats.totalBytes);
364  printf("peak Bytes = %9ld\n", ourMemStats.peakBytes);
365  printf("current Bytes = %9ld\n", ourMemStats.currentBytes);
366  #endif
367 
368  #ifdef DO_MEM_LIST
369  if (ourMemList.count > 0) {
370  /* print list of allocations */
371  memHint* header;
372  for (header = ourMemList.head; header != NULL; header = header->next) {
373  printf("Leak: Ptr %p, Size %u"
374  #ifdef WOLFSSL_DEBUG_MEMORY
375  ", Func %s, Line %d"
376  #endif
377  "\n",
378  (byte*)header + sizeof(memHint), (unsigned int)header->thisSize
379  #ifdef WOLFSSL_DEBUG_MEMORY
380  , header->func, header->line
381  #endif
382  );
383  }
384  }
385 
386  pthread_mutex_unlock(&memLock);
387  }
388  #endif
389  }
390 
391  WC_STATIC WC_INLINE int CleanupMemoryTracker(void)
392  {
393  /* restore default allocators */
394  return wolfSSL_SetAllocators(mfDefault, ffDefault, rfDefault);
395  }
396 #endif
397 
398 #endif /* USE_WOLFSSL_MEMORY */
399 
400 #endif /* WOLFSSL_MEM_TRACK_H */
401 
Definition: mem_track.h:95
Definition: mem_track.h:81
Definition: mem_track.h:73
Definition: mem_track.h:104
WOLFSSL_API int wolfSSL_SetAllocators(wolfSSL_Malloc_cb, wolfSSL_Free_cb, wolfSSL_Realloc_cb)
This function registers the allocation functions used by wolfSSL. By default, if the system supports ...
Definition: memory.c:102