1 #include "test_allocator.h" 2 3 #ifdef HAS_EXECINFO 4 #include <execinfo.h> 5 #endif 6 7 // How many alloc calls we expect 8 int alloc_calls_expected; 9 // How many alloc calls we got 10 int alloc_calls; 11 // Array of booleans indicating whether to return a block or fail with NULL 12 call_expectation *expectations; 13 14 void set_mock_malloc(int calls, ...) { 15 va_list args; 16 va_start(args, calls); 17 alloc_calls_expected = calls; 18 alloc_calls = 0; 19 expectations = calloc(calls, sizeof(expectations)); 20 for (int i = 0; i < calls; i++) { 21 // Promotable types, baby 22 expectations[i] = va_arg(args, call_expectation); 23 } 24 va_end(args); 25 } 26 27 void finalize_mock_malloc(void) { 28 assert_int_equal(alloc_calls, alloc_calls_expected); 29 free(expectations); 30 } 31 32 void print_backtrace() { 33 #if HAS_EXECINFO 34 void *buffer[128]; 35 int frames = backtrace(buffer, 128); 36 char **symbols = backtrace_symbols(buffer, frames); 37 // Skip this function and the caller 38 for (int i = 2; i < frames; ++i) { 39 printf("%s\n", symbols[i]); 40 } 41 free(symbols); 42 #endif 43 } 44 45 void *instrumented_malloc(size_t size) { 46 if (alloc_calls >= alloc_calls_expected) { 47 goto error; 48 } 49 50 if (expectations[alloc_calls] == MALLOC) { 51 alloc_calls++; 52 return malloc(size); 53 } else if (expectations[alloc_calls] == MALLOC_FAIL) { 54 alloc_calls++; 55 return NULL; 56 } 57 58 error: 59 print_error( 60 "Unexpected call to malloc(%zu) at position %d of %d; expected %d\n", 61 size, alloc_calls, alloc_calls_expected, 62 alloc_calls < alloc_calls_expected ? expectations[alloc_calls] : -1); 63 print_backtrace(); 64 fail(); 65 return NULL; 66 } 67 68 void *instrumented_realloc(void *ptr, size_t size) { 69 if (alloc_calls >= alloc_calls_expected) { 70 goto error; 71 } 72 73 if (expectations[alloc_calls] == REALLOC) { 74 alloc_calls++; 75 return realloc(ptr, size); 76 } else if (expectations[alloc_calls] == REALLOC_FAIL) { 77 alloc_calls++; 78 return NULL; 79 } 80 81 error: 82 print_error( 83 "Unexpected call to realloc(%zu) at position %d of %d; expected %d\n", 84 size, alloc_calls, alloc_calls_expected, 85 alloc_calls < alloc_calls_expected ? expectations[alloc_calls] : -1); 86 print_backtrace(); 87 fail(); 88 return NULL; 89 } 90