gnunet-android

GNUnet for Android
Log | Files | Refs | README

mem_track.h (23005B)


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