1#include "test_allocator.h"
2
3#ifdef HAS_EXECINFO
4#include <execinfo.h>
5#endif
6
7// How many alloc calls we expect
8int alloc_calls_expected;
9// How many alloc calls we got
10int alloc_calls;
11// Array of booleans indicating whether to return a block or fail with NULL
12call_expectation *expectations;
13
14void 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
27void finalize_mock_malloc(void) {
28  assert_int_equal(alloc_calls, alloc_calls_expected);
29  free(expectations);
30}
31
32void print_backtrace(void) {
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
45void *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
58error:
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
68void *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
81error:
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