#include #include #include #include #include typedef struct { char* arr; size_t size; size_t capacity; } Vec8_t; Vec8_t create(const Vec8_t* input) { Vec8_t vec = { .arr = NULL, .size = 0, .capacity = 4 }; if (input == NULL) { vec.arr = calloc(vec.capacity, sizeof(char)); return vec; } if (input->size > 0) { vec.size = input->size + 1; } if (input->capacity >= vec.capacity) { vec.capacity = 2 * input->capacity; } vec.arr = calloc(vec.capacity, sizeof(char)); return vec; } void delete(Vec8_t* vec) { if (vec->arr != NULL) { free(vec->arr); } vec->arr = NULL; } Vec8_t add_back(Vec8_t* vec, const char val) { if (vec->size < vec->capacity) { vec->arr[vec->size] = val; vec->size++; return *vec; } if (vec->size >= vec->capacity) { Vec8_t nvec = create(vec); if (nvec.arr == NULL) { return *vec; } memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) { nvec.arr[vec->size] = val; } free(vec->arr); return nvec; } Vec8_t ret = { .arr = NULL, .capacity = 0, .size = 0 }; return ret; } void print_rusage(const char* label) { struct rusage ru; getrusage(RUSAGE_SELF, &ru); printf("%s: %.2f MB maxRSS\n", label, ru.ru_maxrss / 1024.0); } void force_rusage_reset() { struct rusage start; getrusage(RUSAGE_SELF, &start); } int main() { printf("=== MEMORY CRASH + LEAK TEST ===\n\n"); printf("Initial memory:\n"); print_rusage("before"); printf("\n=== TEST 1: PUSH UNTIL CRASH ===\n\n"); Vec8_t vec = create(NULL); size_t crashed_at = 0; for (size_t i = 0; ; i++) { vec = add_back(&vec, (char)(i % 256)); if (vec.arr == NULL) { crashed_at = i; break; } if (i % 50000000 == 0 && i > 0) { struct rusage ru; getrusage(RUSAGE_SELF, &ru); printf(" %zu elements: %.2f MB used\n", i, ru.ru_maxrss / 1024.0); } if (i >= 4000000000UL) { crashed_at = i; printf(" STOPPED at 4 billion\n"); break; } } struct rusage ru; getrusage(RUSAGE_SELF, &ru); if (crashed_at > 0) { printf("\nCRASHED at %zu elements\n", crashed_at); } else { printf("\nStopped at %zu elements\n", vec.size); printf("capacity: %zu\n", vec.capacity); } printf("memory used: %.2f MB\n", ru.ru_maxrss / 1024.0); delete(&vec); printf("\nAfter delete:\n"); print_rusage("after delete"); printf("\n=== TEST 2: MULTIPLE VECTORS (LEAK CHECK) ===\n\n"); size_t num_vectors = 10000; Vec8_t* vectors = calloc(num_vectors, sizeof(Vec8_t)); printf("Creating %zu vectors...\n", num_vectors); print_rusage("before vectors"); for (size_t i = 0; i < num_vectors; i++) { vectors[i] = create(NULL); for (size_t j = 0; j < 10000; j++) { vectors[i] = add_back(&vectors[i], (char)(j % 256)); } } print_rusage("with vectors"); printf("Each vector has %zu elements\n", vectors[0].size); printf("\nFreeing vectors...\n"); for (size_t i = 0; i < num_vectors; i++) { delete(&vectors[i]); } free(vectors); print_rusage("after free"); printf("\n=== TEST 3: CREATE/DELETE CYCLES ===\n\n"); size_t cycles = 100000; printf("Running %zu create/delete cycles...\n", cycles); print_rusage("before cycles"); for (size_t c = 0; c < cycles; c++) { Vec8_t v = create(NULL); for (size_t i = 0; i < 1000; i++) { v = add_back(&v, 'x'); } delete(&v); if (c % 10000 == 0) { struct rusage ru; getrusage(RUSAGE_SELF, &ru); printf(" cycle %zu: %.2f MB\n", c, ru.ru_maxrss / 1024.0); } } print_rusage("after cycles"); printf("\n=== TEST 4: REALLOC STRESS ===\n\n"); Vec8_t big = create(NULL); printf("Single vec realloc stress...\n"); size_t prev_cap = 0; for (size_t i = 0; i < 100000000; i++) { big = add_back(&big, 'x'); if (big.capacity != prev_cap) { struct rusage ru; getrusage(RUSAGE_SELF, &ru); printf(" cap %zu -> %.2f MB\n", big.capacity, ru.ru_maxrss / 1024.0); prev_cap = big.capacity; } } print_rusage("final big vec"); printf("size: %zu, capacity: %zu\n", big.size, big.capacity); delete(&big); printf("\nAfter cleanup:\n"); print_rusage("cleanup done"); printf("\n=== RESULT ===\n"); struct rusage final; getrusage(RUSAGE_SELF, &final); printf("Peak memory: %.2f MB\n", final.ru_maxrss / 1024.0); return 0; }