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 */