mem_track.h 13 KB

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