diff --git a/src/main.c b/src/main.c index 1fca08b..565669d 100644 --- a/src/main.c +++ b/src/main.c @@ -57,10 +57,6 @@ create(const Vec8_t* input) { vec.size = input->size + 1; } - if (input->capacity >= vec.capacity) - { - vec.capacity = 2 * input->capacity; - } vec.arr = calloc(vec.capacity, sizeof(char)); return vec; } @@ -149,30 +145,17 @@ back(const Vec8_t* vec) Vec8_t add_back(Vec8_t* vec, const char val) { - Vec8_t ret = { .arr = nullptr, .capacity = 0, .size = 0 }; - 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 == nullptr) { - printf("Malloc failed and returned nullptr: Returning old vector"); + vec->capacity *= 2; + char* nvec = reallocf(vec->arr, vec->capacity * sizeof(char)); + if(nvec == 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; - } - return ret; + } + vec->arr[vec->size] = val; + vec->size++; + return *vec; } int diff --git a/tests/crash_9b_test b/tests/crash_9b_test new file mode 100755 index 0000000..fe8ae2a Binary files /dev/null and b/tests/crash_9b_test differ diff --git a/tests/crash_9b_test.c b/tests/crash_9b_test.c new file mode 100644 index 0000000..943eab4 --- /dev/null +++ b/tests/crash_9b_test.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include + +typedef struct +{ + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +#define CAPACITY 1024 + +Vec8_t +create(const Vec8_t* input) +{ + Vec8_t vec = { .arr = NULL, .size = 0, .capacity = CAPACITY }; + if (input == NULL) + { + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; + } + if (input->size > 0) + { + vec.size = input->size + 1; + } + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; +} + +void +delete(Vec8_t* vec) +{ + if (vec->arr != NULL) + { + free(vec->arr); + vec->arr = NULL; + } + vec->size = 0; + vec->capacity = 0; +} + +Vec8_t +add_back(Vec8_t* vec, const char val) +{ + if (vec->size >= vec->capacity) + { + vec->capacity = 2 * vec->capacity; + char* new_arr = + reallocf(vec->arr, vec->capacity * sizeof(char)); + if (new_arr == NULL) + { + return *vec; + } + vec->arr = new_arr; + } + vec->arr[vec->size] = val; + vec->size++; + return *vec; +} + +vm_size_t +get_physical_mem() +{ + struct task_basic_info info; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, + &count); + return info.resident_size; +} + +int +main() +{ + printf("=== PROGRESSIVE TEST: 1K -> 10K -> 100K -> 1M -> 10M -> 100M -> 1B ===\n\n"); + + size_t targets[] = {1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; + int num_tests = 7; + + for (int t = 0; t < num_tests; t++) { + size_t target = targets[t]; + printf("\n=== TEST %d: %zu elements ===\n", t+1, target); + + Vec8_t vec = create(NULL); + size_t start_cap = vec.capacity; + + for (size_t i = 0; i < target; i++) { + vec = add_back(&vec, 'x'); + + if (vec.arr == NULL) { + printf("CRASHED at %zu elements!\n", i); + return 1; + } + } + + printf("SUCCESS: %zu elements, capacity %zu\n", vec.size, vec.capacity); + printf("Memory: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + delete(&vec); + } + + printf("\n=== ALL TESTS PASSED ===\n"); + printf("Final memory: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + return 0; +} \ No newline at end of file diff --git a/tests/crash_memory_test b/tests/crash_memory_test new file mode 100755 index 0000000..63332b9 Binary files /dev/null and b/tests/crash_memory_test differ diff --git a/tests/crash_memory_test.c b/tests/crash_memory_test.c new file mode 100644 index 0000000..9718b06 --- /dev/null +++ b/tests/crash_memory_test.c @@ -0,0 +1,198 @@ +#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; +} \ No newline at end of file diff --git a/tests/leak_check b/tests/leak_check new file mode 100755 index 0000000..501fdae Binary files /dev/null and b/tests/leak_check differ diff --git a/tests/leak_check.c b/tests/leak_check.c new file mode 100644 index 0000000..90e508f --- /dev/null +++ b/tests/leak_check.c @@ -0,0 +1,108 @@ +#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; + } + vec->size = 0; + vec->capacity = 0; +} + +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; +} + +vm_size_t get_physical_mem() { + struct task_basic_info info; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count); + return info.resident_size; +} + +int main() { + printf("=== PHYSICAL MEMORY LEAK TEST ===\n\n"); + + printf("Initial physical: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + printf("\n--- Creating large vector ---\n"); + Vec8_t big = create(NULL); + + printf("Adding elements...\n"); + for (size_t i = 0; i < 100000000; i++) { + big = add_back(&big, 'x'); + if (i % 10000000 == 0) { + printf(" %zu elements: %.2f MB\n", i+1, get_physical_mem() / 1024.0 / 1024.0); + } + } + + printf(" Final: %zu elements, %.2f MB\n", big.size, get_physical_mem() / 1024.0 / 1024.0); + + printf("\n--- BEFORE delete: %.2f MB ---\n", get_physical_mem() / 1024.0 / 1024.0); + + delete(&big); + + printf("--- AFTER delete: %.2f MB ---\n", get_physical_mem() / 1024.0 / 1024.0); + + printf("\n--- Create 1000 vectors then delete ---\n"); + printf("Before: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + for (int c = 0; c < 1000; c++) { + Vec8_t v = create(NULL); + for (int i = 0; i < 100000; i++) { + v = add_back(&v, 'x'); + } + delete(&v); + } + + printf("After cycles: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + printf("\n--- RESULT ---\n"); + printf("Physical memory used: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + return 0; +} \ No newline at end of file diff --git a/tests/stress_full_test b/tests/stress_full_test new file mode 100755 index 0000000..2f69d4a Binary files /dev/null and b/tests/stress_full_test differ diff --git a/tests/stress_full_test.c b/tests/stress_full_test.c new file mode 100644 index 0000000..bed1912 --- /dev/null +++ b/tests/stress_full_test.c @@ -0,0 +1,181 @@ +#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) { + Vec8_t ret = { .arr = NULL, .capacity = 0, .size = 0 }; + 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; + } + return ret; +} + +double time_diff(struct timespec start, struct timespec end_t) { + return (end_t.tv_sec - start.tv_sec) + (end_t.tv_nsec - start.tv_nsec) / 1e9; +} + +void get_memory_usage(size_t* used, size_t* peak) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + *used = ru.ru_maxrss * 1024; + *peak = ru.ru_maxrss * 1024; +} + +int main() { + printf("=== FULL STRESS TEST: add_back only ===\n\n"); + + struct timespec start, end_t; + Vec8_t vec; + size_t max_elements = 0; + int crashed = 0; + + printf("=== TEST 1: MAX ELEMENTS BEFORE CRASH ===\n\n"); + + vec = create(NULL); + clock_gettime(CLOCK_MONOTONIC, &start); + + for (size_t i = 0; i < SIZE_MAX; i++) { + vec = add_back(&vec, (char)(i % 256)); + + if (vec.arr == NULL) { + max_elements = i; + crashed = 1; + break; + } + + if (i % 100000000 == 0) { + printf(" %zu elements: capacity %zu (%.2f GB)\n", + i + 1, vec.capacity, (double)(vec.capacity * sizeof(char)) / 1024 / 1024 / 1024); + } + + if (i >= 1000000000) { + printf(" stopping at 1 billion elements\n"); + max_elements = 1000000000; + break; + } + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + + if (!crashed && vec.arr != NULL) { + max_elements = vec.size; + } + + printf("\nRESULT: %zu elements\n", max_elements); + printf("capacity: %zu\n", vec.capacity); + printf("memory: %.2f GB\n", (double)(vec.capacity * sizeof(char)) / 1024 / 1024 / 1024); + printf("time: %.2f sec\n", time_diff(start, end_t)); + + delete(&vec); + + printf("\n=== TEST 2: DIRECT MALLOCATION LIMIT ===\n\n"); + + const size_t test_sizes[] = {1000000, 10000000, 100000000, 500000000, 1000000000}; + int num_tests = 5; + + for (int t = 0; t < num_tests; t++) { + size_t n = test_sizes[t]; + printf("Testing %zu elements (%.2f GB)...\n", + n, (double)(n * sizeof(char)) / 1024 / 1024 / 1024); + + char* test_arr = calloc(n, sizeof(char)); + if (test_arr == NULL) { + printf(" FAILED at %zu\n", n); + break; + } + printf(" SUCCESS\n"); + free(test_arr); + } + + printf("\n=== TEST 3: SINGLE VECTOR ALLOCATION ===\n\n"); + + size_t single_max = 0; + for (size_t n = 1000000; n <= 5000000000UL; n *= 2) { + printf("Trying %.2f GB allocation...\n", (double)(n * sizeof(char)) / 1024 / 1024 / 1024); + + Vec8_t test_vec = create(NULL); + Vec8_t* vp = calloc(1, sizeof(Vec8_t)); + + vp->arr = calloc(n, sizeof(char)); + if (vp->arr == NULL) { + printf(" FAILED at %.2f GB\n", (double)(n * sizeof(char)) / 1024 / 1024 / 1024); + single_max = n / 2; + free(vp); + break; + } + + printf(" SUCCESS: %.2f GB\n", (double)(n * sizeof(char)) / 1024 / 1024 / 1024); + free(vp->arr); + free(vp); + delete(&test_vec); + single_max = n; + } + + printf("\n=== TEST 4: SPEED AT SCALE ===\n\n"); + + vec = create(NULL); + clock_gettime(CLOCK_MONOTONIC, &start); + for (size_t i = 0; i < 10000000; i++) { + vec = add_back(&vec, (char)(i % 256)); + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t10m = time_diff(start, end_t); + + printf("10M elements:\n"); + printf(" time: %.2f sec\n", t10m); + printf(" rate: %.0f/sec\n", 10000000.0 / t10m); + printf(" memory: %.2f MB\n", (vec.capacity * sizeof(char)) / 1024.0 / 1024.0); + + delete(&vec); + + printf("\n=== SUMMARY ===\n\n"); + printf("Max elements (vector): %zu\n", max_elements); + printf("Single allocation max: %zu (%.2f GB)\n", + single_max, (double)(single_max * sizeof(char)) / 1024 / 1024 / 1024); + + return 0; +} \ No newline at end of file