xref: /freebsd/contrib/libcbor/test/test_allocator.c (revision abd872540f24cfc7dbd1ea29b6918c7082a22108)
15d3e7166SEd Maste #include "test_allocator.h"
25d3e7166SEd Maste 
35d3e7166SEd Maste #ifdef HAS_EXECINFO
45d3e7166SEd Maste #include <execinfo.h>
55d3e7166SEd Maste #endif
65d3e7166SEd Maste 
75d3e7166SEd Maste // How many alloc calls we expect
85d3e7166SEd Maste int alloc_calls_expected;
95d3e7166SEd Maste // How many alloc calls we got
105d3e7166SEd Maste int alloc_calls;
115d3e7166SEd Maste // Array of booleans indicating whether to return a block or fail with NULL
125d3e7166SEd Maste call_expectation *expectations;
135d3e7166SEd Maste 
145d3e7166SEd Maste void set_mock_malloc(int calls, ...) {
155d3e7166SEd Maste   va_list args;
165d3e7166SEd Maste   va_start(args, calls);
175d3e7166SEd Maste   alloc_calls_expected = calls;
185d3e7166SEd Maste   alloc_calls = 0;
195d3e7166SEd Maste   expectations = calloc(calls, sizeof(expectations));
205d3e7166SEd Maste   for (int i = 0; i < calls; i++) {
215d3e7166SEd Maste     // Promotable types, baby
225d3e7166SEd Maste     expectations[i] = va_arg(args, call_expectation);
235d3e7166SEd Maste   }
245d3e7166SEd Maste   va_end(args);
255d3e7166SEd Maste }
265d3e7166SEd Maste 
275d3e7166SEd Maste void finalize_mock_malloc(void) {
285d3e7166SEd Maste   assert_int_equal(alloc_calls, alloc_calls_expected);
295d3e7166SEd Maste   free(expectations);
305d3e7166SEd Maste }
315d3e7166SEd Maste 
32*abd87254SEd Maste void print_backtrace(void) {
335d3e7166SEd Maste #if HAS_EXECINFO
345d3e7166SEd Maste   void *buffer[128];
355d3e7166SEd Maste   int frames = backtrace(buffer, 128);
365d3e7166SEd Maste   char **symbols = backtrace_symbols(buffer, frames);
375d3e7166SEd Maste   // Skip this function and the caller
385d3e7166SEd Maste   for (int i = 2; i < frames; ++i) {
395d3e7166SEd Maste     printf("%s\n", symbols[i]);
405d3e7166SEd Maste   }
415d3e7166SEd Maste   free(symbols);
425d3e7166SEd Maste #endif
435d3e7166SEd Maste }
445d3e7166SEd Maste 
455d3e7166SEd Maste void *instrumented_malloc(size_t size) {
465d3e7166SEd Maste   if (alloc_calls >= alloc_calls_expected) {
475d3e7166SEd Maste     goto error;
485d3e7166SEd Maste   }
495d3e7166SEd Maste 
505d3e7166SEd Maste   if (expectations[alloc_calls] == MALLOC) {
515d3e7166SEd Maste     alloc_calls++;
525d3e7166SEd Maste     return malloc(size);
535d3e7166SEd Maste   } else if (expectations[alloc_calls] == MALLOC_FAIL) {
545d3e7166SEd Maste     alloc_calls++;
555d3e7166SEd Maste     return NULL;
565d3e7166SEd Maste   }
575d3e7166SEd Maste 
585d3e7166SEd Maste error:
595d3e7166SEd Maste   print_error(
605d3e7166SEd Maste       "Unexpected call to malloc(%zu) at position %d of %d; expected %d\n",
615d3e7166SEd Maste       size, alloc_calls, alloc_calls_expected,
625d3e7166SEd Maste       alloc_calls < alloc_calls_expected ? expectations[alloc_calls] : -1);
635d3e7166SEd Maste   print_backtrace();
645d3e7166SEd Maste   fail();
655d3e7166SEd Maste   return NULL;
665d3e7166SEd Maste }
675d3e7166SEd Maste 
685d3e7166SEd Maste void *instrumented_realloc(void *ptr, size_t size) {
695d3e7166SEd Maste   if (alloc_calls >= alloc_calls_expected) {
705d3e7166SEd Maste     goto error;
715d3e7166SEd Maste   }
725d3e7166SEd Maste 
735d3e7166SEd Maste   if (expectations[alloc_calls] == REALLOC) {
745d3e7166SEd Maste     alloc_calls++;
755d3e7166SEd Maste     return realloc(ptr, size);
765d3e7166SEd Maste   } else if (expectations[alloc_calls] == REALLOC_FAIL) {
775d3e7166SEd Maste     alloc_calls++;
785d3e7166SEd Maste     return NULL;
795d3e7166SEd Maste   }
805d3e7166SEd Maste 
815d3e7166SEd Maste error:
825d3e7166SEd Maste   print_error(
835d3e7166SEd Maste       "Unexpected call to realloc(%zu) at position %d of %d; expected %d\n",
845d3e7166SEd Maste       size, alloc_calls, alloc_calls_expected,
855d3e7166SEd Maste       alloc_calls < alloc_calls_expected ? expectations[alloc_calls] : -1);
865d3e7166SEd Maste   print_backtrace();
875d3e7166SEd Maste   fail();
885d3e7166SEd Maste   return NULL;
895d3e7166SEd Maste }
90