mem_track.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. /* mem_track.h
  2. *
  3. * Copyright (C) 2006-2023 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. /* Memory and stack use tracking */
  22. #ifndef WOLFSSL_MEM_TRACK_H
  23. #define WOLFSSL_MEM_TRACK_H
  24. /* The memory tracker overrides the wolfSSL memory callback system and uses a
  25. * static to track the total, peak and currently allocated bytes.
  26. *
  27. * If you are already using the memory callbacks then enabling this will
  28. * override the memory callbacks and prevent your memory callbacks from
  29. * working. This assumes malloc() and free() are available. Feel free to
  30. * customize this for your needs.
  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. #include "wolfssl/wolfcrypt/settings.h"
  57. #include "wolfssl/wolfcrypt/types.h"
  58. #include "wolfssl/wolfcrypt/logging.h"
  59. #include "wolfssl/wolfcrypt/error-crypt.h"
  60. #include "wolfssl/wolfcrypt/memory.h"
  61. #if defined(WOLFSSL_TRACK_MEMORY) || defined(HAVE_STACK_SIZE) || \
  62. defined(HAVE_STACK_SIZE_VERBOSE)
  63. #ifdef NO_STDIO_FILESYSTEM
  64. /* if wc_port.h/linuxkm_wc_port.h doesn't define printf, then the user
  65. * needs to define it.
  66. */
  67. #define wc_mem_printf(...) printf(__VA_ARGS__)
  68. #else
  69. #include <stdio.h>
  70. #define wc_mem_printf(...) fprintf(stderr, __VA_ARGS__)
  71. #endif
  72. #endif
  73. /* Track Memory */
  74. #if defined(WOLFSSL_TRACK_MEMORY) && defined(USE_WOLFSSL_MEMORY) && \
  75. !defined(WOLFSSL_STATIC_MEMORY)
  76. #define DO_MEM_STATS
  77. #if (defined(__linux__) && !defined(WOLFSSL_LINUXKM)) || defined(__MACH__)
  78. #define DO_MEM_LIST
  79. #endif
  80. typedef struct memoryStats {
  81. long totalAllocs; /* number of allocations */
  82. long totalDeallocs; /* number of deallocations */
  83. long totalBytes; /* total number of bytes allocated */
  84. long peakBytes; /* concurrent max bytes */
  85. long currentBytes; /* total current bytes in use */
  86. #ifdef WOLFSSL_TRACK_MEMORY_VERBOSE
  87. long peakAllocsTripOdometer; /* peak number of concurrent allocations,
  88. * subject to reset by
  89. * wolfCrypt_heap_peak_checkpoint()
  90. */
  91. long peakBytesTripOdometer; /* peak concurrent bytes, subject to reset
  92. * by wolfCrypt_heap_peak_checkpoint()
  93. */
  94. #endif
  95. } memoryStats;
  96. typedef struct memHint {
  97. size_t thisSize; /* size of this memory */
  98. #ifdef DO_MEM_LIST
  99. struct memHint* next;
  100. struct memHint* prev;
  101. #ifdef WOLFSSL_DEBUG_MEMORY
  102. const char* func;
  103. unsigned int line;
  104. #endif
  105. #endif
  106. void* thisMemory; /* actual memory for user */
  107. } memHint;
  108. typedef struct memoryTrack {
  109. union {
  110. memHint hint;
  111. /* make sure we have strong alignment */
  112. byte alignit[sizeof(memHint) + ((16-1) & ~(16-1))];
  113. } u;
  114. } memoryTrack;
  115. #ifdef DO_MEM_LIST
  116. /* track allocations and report at end */
  117. typedef struct memoryList {
  118. memHint* head;
  119. memHint* tail;
  120. word32 count;
  121. } memoryList;
  122. #endif
  123. static memoryStats ourMemStats;
  124. #ifdef DO_MEM_LIST
  125. #include <pthread.h>
  126. static memoryList ourMemList;
  127. static pthread_mutex_t memLock = PTHREAD_MUTEX_INITIALIZER;
  128. #endif
  129. #ifdef WOLFSSL_DEBUG_MEMORY
  130. static WC_INLINE void* TrackMalloc(size_t sz, const char* func,
  131. unsigned int line)
  132. #else
  133. 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. wc_mem_printf("Alloc: %p -> %u at %s:%d\n",
  153. header->thisMemory, (word32)sz, func, line);
  154. #else
  155. (void)func;
  156. (void)line;
  157. #endif
  158. #endif
  159. #ifdef DO_MEM_STATS
  160. ourMemStats.totalAllocs++;
  161. ourMemStats.totalBytes += sz;
  162. ourMemStats.currentBytes += sz;
  163. #ifdef WOLFSSL_TRACK_MEMORY_VERBOSE
  164. if (ourMemStats.peakAllocsTripOdometer < ourMemStats.totalAllocs -
  165. ourMemStats.totalDeallocs) {
  166. ourMemStats.peakAllocsTripOdometer = ourMemStats.totalAllocs -
  167. ourMemStats.totalDeallocs;
  168. }
  169. if (ourMemStats.peakBytesTripOdometer < ourMemStats.currentBytes)
  170. #endif
  171. {
  172. #ifdef WOLFSSL_TRACK_MEMORY_VERBOSE
  173. ourMemStats.peakBytesTripOdometer = ourMemStats.currentBytes;
  174. #endif
  175. if (ourMemStats.currentBytes > ourMemStats.peakBytes)
  176. ourMemStats.peakBytes = ourMemStats.currentBytes;
  177. }
  178. #endif /* DO_MEM_STATS */
  179. #ifdef DO_MEM_LIST
  180. if (pthread_mutex_lock(&memLock) == 0) {
  181. #ifdef WOLFSSL_DEBUG_MEMORY
  182. header->func = func;
  183. header->line = line;
  184. #endif
  185. /* Setup event */
  186. header->next = NULL;
  187. if (ourMemList.tail == NULL) {
  188. ourMemList.head = header;
  189. header->prev = NULL;
  190. }
  191. else {
  192. ourMemList.tail->next = header;
  193. header->prev = ourMemList.tail;
  194. }
  195. ourMemList.tail = header; /* add to the end either way */
  196. ourMemList.count++;
  197. pthread_mutex_unlock(&memLock);
  198. }
  199. #endif /* DO_MEM_LIST */
  200. return header->thisMemory;
  201. }
  202. #ifdef WOLFSSL_DEBUG_MEMORY
  203. static WC_INLINE void TrackFree(void* ptr, const char* func, unsigned int line)
  204. #else
  205. static WC_INLINE void TrackFree(void* ptr)
  206. #endif
  207. {
  208. memoryTrack* mt;
  209. memHint* header;
  210. size_t sz;
  211. if (ptr == NULL) {
  212. return;
  213. }
  214. mt = (memoryTrack*)((byte*)ptr - sizeof(memoryTrack));
  215. header = &mt->u.hint;
  216. sz = header->thisSize;
  217. #ifdef DO_MEM_LIST
  218. if (pthread_mutex_lock(&memLock) == 0)
  219. {
  220. #endif
  221. #ifdef DO_MEM_STATS
  222. ourMemStats.currentBytes -= header->thisSize;
  223. ourMemStats.totalDeallocs++;
  224. #endif
  225. #ifdef DO_MEM_LIST
  226. if (header == ourMemList.head && header == ourMemList.tail) {
  227. ourMemList.head = NULL;
  228. ourMemList.tail = NULL;
  229. }
  230. else if (header == ourMemList.head) {
  231. ourMemList.head = header->next;
  232. ourMemList.head->prev = NULL;
  233. }
  234. else if (header == ourMemList.tail) {
  235. ourMemList.tail = header->prev;
  236. ourMemList.tail->next = NULL;
  237. }
  238. else {
  239. memHint* next = header->next;
  240. memHint* prev = header->prev;
  241. if (next)
  242. next->prev = prev;
  243. if (prev)
  244. prev->next = next;
  245. }
  246. ourMemList.count--;
  247. pthread_mutex_unlock(&memLock);
  248. }
  249. #endif
  250. #ifdef WOLFSSL_DEBUG_MEMORY
  251. #ifdef WOLFSSL_DEBUG_MEMORY_PRINT
  252. wc_mem_printf("Free: %p -> %u at %s:%d\n", ptr, (word32)sz, func, line);
  253. #else
  254. (void)func;
  255. (void)line;
  256. #endif
  257. #endif
  258. (void)sz;
  259. #ifdef FREERTOS
  260. vPortFree(mt);
  261. #else
  262. free(mt);
  263. #endif
  264. }
  265. #ifdef WOLFSSL_DEBUG_MEMORY
  266. static WC_INLINE void* TrackRealloc(void* ptr, size_t sz, const char* func,
  267. unsigned int line)
  268. #else
  269. static WC_INLINE void* TrackRealloc(void* ptr, size_t sz)
  270. #endif
  271. {
  272. #ifdef WOLFSSL_DEBUG_MEMORY
  273. void* ret = TrackMalloc(sz, func, line);
  274. #else
  275. void* ret = TrackMalloc(sz);
  276. #endif
  277. if (ptr) {
  278. /* if realloc is bigger, don't overread old ptr */
  279. memoryTrack* mt;
  280. memHint* header;
  281. mt = (memoryTrack*)((byte*)ptr - sizeof(memoryTrack));
  282. header = &mt->u.hint;
  283. if (header->thisSize < sz)
  284. sz = header->thisSize;
  285. }
  286. if (ret && ptr)
  287. XMEMCPY(ret, ptr, sz);
  288. if (ret) {
  289. #ifdef WOLFSSL_DEBUG_MEMORY
  290. TrackFree(ptr, func, line);
  291. #else
  292. TrackFree(ptr);
  293. #endif
  294. }
  295. return ret;
  296. }
  297. static wolfSSL_Malloc_cb mfDefault = NULL;
  298. static wolfSSL_Free_cb ffDefault = NULL;
  299. static wolfSSL_Realloc_cb rfDefault = NULL;
  300. static WC_INLINE int InitMemoryTracker(void)
  301. {
  302. int ret;
  303. ret = wolfSSL_GetAllocators(&mfDefault, &ffDefault, &rfDefault);
  304. if (ret < 0) {
  305. wc_mem_printf("wolfSSL GetAllocators failed to get the defaults\n");
  306. }
  307. ret = wolfSSL_SetAllocators(TrackMalloc, TrackFree, TrackRealloc);
  308. if (ret < 0) {
  309. wc_mem_printf("wolfSSL SetAllocators failed for track memory\n");
  310. return ret;
  311. }
  312. #ifdef DO_MEM_LIST
  313. if (pthread_mutex_lock(&memLock) == 0)
  314. #endif
  315. {
  316. #ifdef DO_MEM_STATS
  317. ourMemStats.totalAllocs = 0;
  318. ourMemStats.totalDeallocs = 0;
  319. ourMemStats.totalBytes = 0;
  320. ourMemStats.peakBytes = 0;
  321. ourMemStats.currentBytes = 0;
  322. #ifdef WOLFSSL_TRACK_MEMORY_VERBOSE
  323. ourMemStats.peakAllocsTripOdometer = 0;
  324. ourMemStats.peakBytesTripOdometer = 0;
  325. #endif
  326. #endif /* DO_MEM_STATS */
  327. #ifdef DO_MEM_LIST
  328. XMEMSET(&ourMemList, 0, sizeof(ourMemList));
  329. pthread_mutex_unlock(&memLock);
  330. #endif
  331. }
  332. return ret;
  333. }
  334. static WC_INLINE void ShowMemoryTracker(void)
  335. {
  336. #ifdef DO_MEM_LIST
  337. if (pthread_mutex_lock(&memLock) == 0)
  338. #endif
  339. {
  340. #ifdef DO_MEM_STATS
  341. wc_mem_printf("total Allocs = %9ld\n", ourMemStats.totalAllocs);
  342. wc_mem_printf("total Deallocs = %9ld\n", ourMemStats.totalDeallocs);
  343. wc_mem_printf("total Bytes = %9ld\n", ourMemStats.totalBytes);
  344. wc_mem_printf("peak Bytes = %9ld\n", ourMemStats.peakBytes);
  345. wc_mem_printf("current Bytes = %9ld\n", ourMemStats.currentBytes);
  346. #endif
  347. #ifdef DO_MEM_LIST
  348. if (ourMemList.count > 0) {
  349. /* print list of allocations */
  350. memHint* header;
  351. for (header = ourMemList.head;
  352. header != NULL;
  353. header = header->next) {
  354. #ifdef WOLFSSL_DEBUG_MEMORY
  355. wc_mem_printf("Leak: Ptr %p, Size %u, Func %s, Line %d\n",
  356. (byte*)header + sizeof(memHint),
  357. (unsigned int)header->thisSize, header->func, header->line);
  358. #else
  359. wc_mem_printf("Leak: Ptr %p, Size %u\n",
  360. (byte*)header + sizeof(memHint),
  361. (unsigned int)header->thisSize);
  362. #endif
  363. }
  364. }
  365. pthread_mutex_unlock(&memLock);
  366. #endif
  367. }
  368. }
  369. static WC_INLINE int CleanupMemoryTracker(void)
  370. {
  371. /* restore default allocators */
  372. return wolfSSL_SetAllocators(mfDefault, ffDefault, rfDefault);
  373. }
  374. #endif /* WOLFSSL_TRACK_MEMORY && USE_WOLFSSL_MEMORY && \
  375. !WOLFSSL_STATIC_MEMORY */
  376. #ifdef HAVE_STACK_SIZE
  377. #include <stdio.h>
  378. #include <pthread.h>
  379. #include <errno.h>
  380. #include <sched.h>
  381. #include <unistd.h>
  382. typedef void* (*thread_func)(void* args);
  383. #define STACK_CHECK_VAL 0x01
  384. struct stack_size_debug_context {
  385. unsigned char *myStack;
  386. size_t stackSize;
  387. #ifdef HAVE_STACK_SIZE_VERBOSE
  388. size_t *stackSizeHWM_ptr;
  389. thread_func fn;
  390. void *args;
  391. #endif
  392. };
  393. struct func_args; /* forward declaration */
  394. #ifdef HAVE_STACK_SIZE_VERBOSE
  395. /* per-subtest stack high water mark tracking.
  396. *
  397. * enable with
  398. *
  399. * ./configure --enable-stacksize=verbose [...]
  400. */
  401. static void* debug_stack_size_verbose_shim(
  402. struct stack_size_debug_context *shim_args)
  403. {
  404. StackSizeCheck_myStack = shim_args->myStack;
  405. StackSizeCheck_stackSize = shim_args->stackSize;
  406. StackSizeCheck_stackSizeHWM_ptr = shim_args->stackSizeHWM_ptr;
  407. return shim_args->fn(shim_args->args);
  408. }
  409. static WC_INLINE int StackSizeSetOffset(const char *funcname, void *p)
  410. {
  411. if (StackSizeCheck_myStack == NULL)
  412. return -BAD_FUNC_ARG;
  413. StackSizeCheck_stackOffsetPointer = p;
  414. printf("setting stack relative offset reference mark in %s to +%lu\n",
  415. funcname, (unsigned long)((char*)(StackSizeCheck_myStack +
  416. StackSizeCheck_stackSize) - (char *)p));
  417. return 0;
  418. }
  419. static WC_INLINE ssize_t StackSizeHWM(void)
  420. {
  421. size_t i;
  422. ssize_t used;
  423. if (StackSizeCheck_myStack == NULL)
  424. return -BAD_FUNC_ARG;
  425. for (i = 0; i < StackSizeCheck_stackSize; i++) {
  426. if (StackSizeCheck_myStack[i] != STACK_CHECK_VAL) {
  427. break;
  428. }
  429. }
  430. used = StackSizeCheck_stackSize - i;
  431. if ((ssize_t)*StackSizeCheck_stackSizeHWM_ptr < used)
  432. *StackSizeCheck_stackSizeHWM_ptr = used;
  433. return used;
  434. }
  435. static WC_INLINE ssize_t StackSizeHWM_OffsetCorrected(void)
  436. {
  437. ssize_t used = StackSizeHWM();
  438. if (used < 0)
  439. return used;
  440. if (StackSizeCheck_stackOffsetPointer) {
  441. used -= (ssize_t)(((char *)StackSizeCheck_myStack +
  442. StackSizeCheck_stackSize) -
  443. (char *)StackSizeCheck_stackOffsetPointer);
  444. }
  445. return used;
  446. }
  447. static
  448. #ifdef __GNUC__
  449. __attribute__((unused)) __attribute__((noinline))
  450. #endif
  451. int StackSizeHWMReset(void)
  452. {
  453. volatile ssize_t i;
  454. if (StackSizeCheck_myStack == NULL)
  455. return -BAD_FUNC_ARG;
  456. for (i = (ssize_t)((char *)&i - (char *)StackSizeCheck_myStack) -
  457. (ssize_t)sizeof(i) - 1; i >= 0; --i) {
  458. StackSizeCheck_myStack[i] = STACK_CHECK_VAL;
  459. }
  460. return 0;
  461. }
  462. #define STACK_SIZE_CHECKPOINT(...) ({ \
  463. ssize_t HWM = StackSizeHWM_OffsetCorrected(); \
  464. __VA_ARGS__; \
  465. printf(" relative stack peak usage = %ld bytes\n", (long int)HWM); \
  466. StackSizeHWMReset(); \
  467. })
  468. #define STACK_SIZE_CHECKPOINT_MSG(msg) ({ \
  469. ssize_t HWM = StackSizeHWM_OffsetCorrected(); \
  470. wc_mem_printf("%ld\t%s\n", (long int)HWM, msg); \
  471. StackSizeHWMReset(); \
  472. })
  473. #define STACK_SIZE_CHECKPOINT_WITH_MAX_CHECK(max, ...) ({ \
  474. ssize_t HWM = StackSizeHWM_OffsetCorrected(); \
  475. int _ret; \
  476. __VA_ARGS__; \
  477. printf(" relative stack peak usage = %ld bytes\n", (long int)HWM); \
  478. _ret = StackSizeHWMReset(); \
  479. if ((max >= 0) && (HWM > (ssize_t)(max))) { \
  480. wc_mem_printf( \
  481. " relative stack usage at %s L%d exceeds designated " \
  482. "max %ld bytes.\n", \
  483. __FILE__, __LINE__, (long int)(max)); \
  484. _ret = -1; \
  485. } \
  486. _ret; \
  487. })
  488. #if defined(__GNUC__) || defined(__clang__)
  489. #define STACK_SIZE_INIT() \
  490. (void)StackSizeSetOffset(__FUNCTION__, __builtin_frame_address(0))
  491. #endif
  492. #endif /* HAVE_STACK_SIZE_VERBOSE */
  493. static WC_INLINE int StackSizeCheck(struct func_args* args, thread_func tf)
  494. {
  495. size_t i;
  496. int ret;
  497. void* status;
  498. unsigned char* myStack = NULL;
  499. size_t stackSize = 1024*1024*2;
  500. pthread_attr_t myAttr;
  501. pthread_t threadId;
  502. #ifdef HAVE_STACK_SIZE_VERBOSE
  503. struct stack_size_debug_context shim_args;
  504. #endif
  505. #ifdef PTHREAD_STACK_MIN
  506. if (stackSize < PTHREAD_STACK_MIN)
  507. stackSize = PTHREAD_STACK_MIN;
  508. #endif
  509. ret = posix_memalign((void**)&myStack, sysconf(_SC_PAGESIZE), stackSize);
  510. if (ret != 0 || myStack == NULL) {
  511. wc_mem_printf("posix_memalign failed\n");
  512. return -1;
  513. }
  514. XMEMSET(myStack, STACK_CHECK_VAL, stackSize);
  515. ret = pthread_attr_init(&myAttr);
  516. if (ret != 0) {
  517. wc_mem_printf("attr_init failed\n");
  518. return ret;
  519. }
  520. ret = pthread_attr_setstack(&myAttr, myStack, stackSize);
  521. if (ret != 0) {
  522. wc_mem_printf("attr_setstackaddr failed\n");
  523. return ret;
  524. }
  525. #ifdef HAVE_STACK_SIZE_VERBOSE
  526. StackSizeCheck_stackSizeHWM = 0;
  527. shim_args.myStack = myStack;
  528. shim_args.stackSize = stackSize;
  529. shim_args.stackSizeHWM_ptr = &StackSizeCheck_stackSizeHWM;
  530. shim_args.fn = tf;
  531. shim_args.args = args;
  532. ret = pthread_create(&threadId, &myAttr,
  533. (thread_func)debug_stack_size_verbose_shim, (void *)&shim_args);
  534. #else
  535. ret = pthread_create(&threadId, &myAttr, tf, args);
  536. #endif
  537. if (ret != 0) {
  538. printf("ret = %d\n", ret);
  539. perror("pthread_create failed");
  540. exit(EXIT_FAILURE);
  541. }
  542. ret = pthread_join(threadId, &status);
  543. if (ret != 0) {
  544. wc_mem_printf("pthread_join failed\n");
  545. return ret;
  546. }
  547. for (i = 0; i < stackSize; i++) {
  548. if (myStack[i] != STACK_CHECK_VAL) {
  549. break;
  550. }
  551. }
  552. free(myStack);
  553. #ifdef HAVE_STACK_SIZE_VERBOSE
  554. printf("stack used = %lu\n", StackSizeCheck_stackSizeHWM > (stackSize - i)
  555. ? (unsigned long)StackSizeCheck_stackSizeHWM
  556. : (unsigned long)(stackSize - i));
  557. StackSizeCheck_myStack = NULL;
  558. StackSizeCheck_stackOffsetPointer = NULL;
  559. #else
  560. {
  561. size_t used = stackSize - i;
  562. printf("stack used = %lu\n", (unsigned long)used);
  563. }
  564. #endif
  565. return (int)((size_t)status);
  566. }
  567. static WC_INLINE int StackSizeCheck_launch(struct func_args* args,
  568. thread_func tf, pthread_t *threadId, void **stack_context)
  569. {
  570. int ret;
  571. unsigned char* myStack = NULL;
  572. size_t stackSize = 1024*1024*2;
  573. pthread_attr_t myAttr;
  574. struct stack_size_debug_context* shim_args;
  575. #ifdef PTHREAD_STACK_MIN
  576. if (stackSize < PTHREAD_STACK_MIN)
  577. stackSize = PTHREAD_STACK_MIN;
  578. #endif
  579. shim_args = (struct stack_size_debug_context *)malloc(sizeof *shim_args);
  580. if (shim_args == NULL) {
  581. perror("malloc");
  582. return -1;
  583. }
  584. ret = posix_memalign((void**)&myStack, sysconf(_SC_PAGESIZE), stackSize);
  585. if (ret != 0 || myStack == NULL) {
  586. wc_mem_printf("posix_memalign failed\n");
  587. free(shim_args);
  588. return -1;
  589. }
  590. XMEMSET(myStack, STACK_CHECK_VAL, stackSize);
  591. ret = pthread_attr_init(&myAttr);
  592. if (ret != 0) {
  593. wc_mem_printf("attr_init failed\n");
  594. free(shim_args);
  595. free(myStack);
  596. return ret;
  597. }
  598. ret = pthread_attr_setstack(&myAttr, myStack, stackSize);
  599. if (ret != 0) {
  600. wc_mem_printf("attr_setstackaddr failed\n");
  601. }
  602. shim_args->myStack = myStack;
  603. shim_args->stackSize = stackSize;
  604. #ifdef HAVE_STACK_SIZE_VERBOSE
  605. shim_args->stackSizeHWM_ptr = &StackSizeCheck_stackSizeHWM;
  606. shim_args->fn = tf;
  607. shim_args->args = args;
  608. ret = pthread_create(threadId, &myAttr,
  609. (thread_func)debug_stack_size_verbose_shim, (void *)shim_args);
  610. #else
  611. ret = pthread_create(threadId, &myAttr, tf, args);
  612. #endif
  613. if (ret != 0) {
  614. fprintf(stderr,"pthread_create failed: %s",strerror(ret));
  615. exit(EXIT_FAILURE);
  616. }
  617. *stack_context = (void *)shim_args;
  618. return 0;
  619. }
  620. static WC_INLINE int StackSizeCheck_reap(pthread_t threadId,
  621. void *stack_context)
  622. {
  623. struct stack_size_debug_context *shim_args =
  624. (struct stack_size_debug_context *)stack_context;
  625. size_t i;
  626. void *status;
  627. int ret = pthread_join(threadId, &status);
  628. if (ret != 0) {
  629. wc_mem_printf("pthread_join failed\n");
  630. return ret;
  631. }
  632. for (i = 0; i < shim_args->stackSize; i++) {
  633. if (shim_args->myStack[i] != STACK_CHECK_VAL) {
  634. break;
  635. }
  636. }
  637. free(shim_args->myStack);
  638. #ifdef HAVE_STACK_SIZE_VERBOSE
  639. printf("stack used = %lu\n",
  640. *shim_args->stackSizeHWM_ptr > (shim_args->stackSize - i)
  641. ? (unsigned long)*shim_args->stackSizeHWM_ptr
  642. : (unsigned long)(shim_args->stackSize - i));
  643. #else
  644. {
  645. size_t used = shim_args->stackSize - i;
  646. printf("stack used = %lu\n", (unsigned long)used);
  647. }
  648. #endif
  649. free(shim_args);
  650. return (int)((size_t)status);
  651. }
  652. #endif /* HAVE_STACK_SIZE */
  653. #ifdef STACK_TRAP
  654. /* good settings
  655. ./configure --enable-debug --disable-shared C_EXTRA_FLAGS="-DUSER_TIME \
  656. -DTFM_TIMING_RESISTANT -DPOSITIVE_EXP_ONLY -DSTACK_TRAP"
  657. */
  658. #ifdef HAVE_STACK_SIZE
  659. /* client only for now, setrlimit will fail if pthread_create() called */
  660. /* STACK_SIZE does pthread_create() on client */
  661. #error "can't use STACK_TRAP with STACK_SIZE, setrlimit will fail"
  662. #endif /* HAVE_STACK_SIZE */
  663. static WC_INLINE void StackTrap(void)
  664. {
  665. struct rlimit rl;
  666. if (getrlimit(RLIMIT_STACK, &rl) != 0) {
  667. wc_mem_printf("getrlimit failed\n");
  668. }
  669. printf("rlim_cur = %llu\n", rl.rlim_cur);
  670. rl.rlim_cur = 1024*21; /* adjust trap size here */
  671. if (setrlimit(RLIMIT_STACK, &rl) != 0) {
  672. wc_mem_printf("setrlimit failed\n");
  673. }
  674. }
  675. #else /* STACK_TRAP */
  676. static WC_INLINE void StackTrap(void)
  677. {
  678. }
  679. #endif /* STACK_TRAP */
  680. /* Stubs when not used */
  681. #ifndef STACK_SIZE_CHECKPOINT
  682. #define STACK_SIZE_CHECKPOINT(...) (__VA_ARGS__)
  683. #endif
  684. #ifndef STACK_SIZE_CHECKPOINT_MSG
  685. #define STACK_SIZE_CHECKPOINT_MSG(msg) WC_DO_NOTHING
  686. #endif
  687. #ifndef STACK_SIZE_CHECKPOINT_WITH_MAX_CHECK
  688. #define STACK_SIZE_CHECKPOINT_WITH_MAX_CHECK(max, ...) (__VA_ARGS__, 0)
  689. #endif
  690. #ifndef STACK_SIZE_INIT
  691. #define STACK_SIZE_INIT() WC_DO_NOTHING
  692. #endif
  693. #endif /* WOLFSSL_MEM_TRACK_H */