|
11 | 11 | #include <stdint.h> |
12 | 12 | #include <stdbool.h> |
13 | 13 | #include <unistd.h> |
| 14 | +#include <time.h> |
| 15 | +#if defined(__APPLE__) |
| 16 | +#include <mach/mach.h> |
| 17 | +#endif |
14 | 18 | #include <sys/stat.h> |
15 | 19 | #include <ctype.h> |
16 | 20 | #include <errno.h> |
@@ -1600,7 +1604,65 @@ static options_t parse_options(int argc, char *argv[]) { |
1600 | 1604 |
|
1601 | 1605 |
|
1602 | 1606 | #ifndef PRINTABLE_BINARY_NO_MAIN |
| 1607 | +/* ---- memory-leak suite support (driven by test/leak_test via --leak-seconds) ---- */ |
| 1608 | +static long pb_now_ms(void) { |
| 1609 | + struct timespec ts; |
| 1610 | + clock_gettime(CLOCK_MONOTONIC, &ts); |
| 1611 | + return ts.tv_sec * 1000L + ts.tv_nsec / 1000000L; |
| 1612 | +} |
| 1613 | +static long pb_rss_kb(void) { |
| 1614 | +#if defined(__APPLE__) |
| 1615 | + mach_task_basic_info_data_t info; |
| 1616 | + mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; |
| 1617 | + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count) != KERN_SUCCESS) return -1; |
| 1618 | + return (long)(info.resident_size / 1024); |
| 1619 | +#else |
| 1620 | + FILE *f = fopen("/proc/self/statm", "r"); |
| 1621 | + if (!f) return -1; |
| 1622 | + long total = 0, resident = 0; |
| 1623 | + int n = fscanf(f, "%ld %ld", &total, &resident); |
| 1624 | + fclose(f); |
| 1625 | + return n == 2 ? resident * (sysconf(_SC_PAGESIZE) / 1024) : -1; |
| 1626 | +#endif |
| 1627 | +} |
| 1628 | +/* Time-bounded encode/decode loop that self-reports RSS, so the leak suite can |
| 1629 | + * watch the C standalone's buffer_t alloc/free path for growth over time. */ |
| 1630 | +static void run_leak_loop(long seconds) { |
| 1631 | + if (seconds <= 0) seconds = 8; |
| 1632 | + long start = pb_now_ms(), deadline = start + seconds * 1000L, last = start; |
| 1633 | + static uint8_t buf[8192]; |
| 1634 | + uint64_t rng = 0x9E3779B97F4A7C15ULL; |
| 1635 | + options_t opts; |
| 1636 | + memset(&opts, 0, sizeof opts); |
| 1637 | + printf("RSS %ld\n", pb_rss_kb()); |
| 1638 | + fflush(stdout); |
| 1639 | + for (long i = 0;; i++) { |
| 1640 | + if ((i & 0x3FF) == 0) { |
| 1641 | + long t = pb_now_ms(); |
| 1642 | + if (t >= deadline) break; |
| 1643 | + if (t - last >= 100) { printf("RSS %ld\n", pb_rss_kb()); fflush(stdout); last = t; } |
| 1644 | + } |
| 1645 | + rng = rng * 6364136223846793005ULL + 1442695040888963407ULL; |
| 1646 | + size_t len = (size_t)((rng >> 33) % (sizeof(buf) + 1)); |
| 1647 | + for (size_t k = 0; k < len; k++) { rng = rng * 6364136223846793005ULL + 1442695040888963407ULL; buf[k] = (uint8_t)(rng >> 33); } |
| 1648 | + buffer_t enc = encode_data(buf, len, &opts); |
| 1649 | + buffer_t dec = decode_data((uint8_t *)enc.data, enc.size, false); |
| 1650 | + buffer_free(&dec); |
| 1651 | + buffer_free(&enc); |
| 1652 | + } |
| 1653 | + printf("RSS %ld\n", pb_rss_kb()); |
| 1654 | + fflush(stdout); |
| 1655 | +} |
| 1656 | + |
1603 | 1657 | int main(int argc, char *argv[]) { |
| 1658 | + // Leak-test mode (test/leak_test): long-lived encode/decode loop, then exit. |
| 1659 | + for (int ai = 1; ai < argc; ai++) { |
| 1660 | + if (strcmp(argv[ai], "--leak-seconds") == 0 && ai + 1 < argc) { |
| 1661 | + init_tables(argv[0]); |
| 1662 | + run_leak_loop(atol(argv[ai + 1])); |
| 1663 | + return 0; |
| 1664 | + } |
| 1665 | + } |
1604 | 1666 | // Parse command line options first (needed for help/usage) |
1605 | 1667 | options_t opts = parse_options(argc, argv); |
1606 | 1668 | const char *program_display_name = resolve_program_name(argv[0]); |
|
0 commit comments