I am building a Visual Studio 2013 solution for a library that I support . The library mainly uses arena allocation, so we have a distributor interface:
allocator.h
#define HAMMER_ALLOCATOR__H__ #include <sys/types.h> #ifdef __cplusplus extern "C" { #endif typedef struct HAllocator_ { void* (*alloc)(struct HAllocator_* allocator, size_t size); void* (*realloc)(struct HAllocator_* allocator, void* ptr, size_t size); void (*free)(struct HAllocator_* allocator, void* ptr); } HAllocator; [... API functions ... ] #ifdef __cplusplus } #endif #endif
We also implement a wrapper around malloc , realloc and free :
system_allocator.c
#include <string.h> #include <stdlib.h> #include "internal.h" void* system_alloc(HAllocator *allocator, size_t size) { void* ptr = malloc(size + sizeof(size_t)); *(size_t*)ptr = size; return (uint8_t*)ptr + sizeof(size_t); } void* system_realloc(HAllocator *allocator, void* ptr, size_t size) { if (ptr == NULL) return system_alloc(allocator, size); ptr = realloc((uint8_t*)ptr - sizeof(size_t), size + sizeof(size_t)); *(size_t*)ptr = size; return (uint8_t*)ptr + sizeof(size_t); } void system_free(HAllocator *allocator, void* ptr) { if (ptr != NULL) free((uint8_t*)ptr - sizeof(size_t)); } HAllocator system_allocator = { .alloc = &system_alloc, .realloc = &system_realloc, .free = &system_free, };
system_allocator global is declared as extern in internal.h (which is #include allocator.h ), and it is exported as a character (in the .def file). However, apparently, the structure is never initialized, because when my unit tests try to pass the system_allocator to the address of the function that the alloc member alloc , they segfault with the "Unhandled exception in 0x000007FEFAD3EB6D (hammer.dll) in hammer-test.exe: 0xC0000005: read access violation location 0xFFFFFFFFFFFFFFFF. "
Checking the passed pointer in the debugger assumes that something is definitely not correct:
- mm__ 0x000000013fb0a094 {hammer-test.exe! HAllocator_ system_allocator} {alloc = 0x25ff00019ff625ff realloc = ...} HAllocator_ *
- alloc 0x25ff00019ff625ff void * (HAllocator_ *, unsigned __int64) *
- realloc 0x9ffa25ff00019ff8 void * (HAllocator_ *, void *, unsigned __int64) *
- free 0x00019ffc25ff0001 void (HAllocator_ *, void *) *
In particular, since when I check the original string literal, everything looks reasonable:
- system_allocator = {alloc = 0x000007fefad31410 {hammer.dll! system_alloc} realloc = 0x000007fefad313f7 {hammer.dll! system_realloc} ...}
- alloc = 0x000007fefad31410 {hammer.dll! system_alloc}
- realloc = 0x000007fefad313f7 {hammer.dll! system_realloc}
- free = 0x000007fefad310d2 {hammer.dll! system_free}
I tried to set breakpoints both in the declaration and in the definition of system_allocator , and VS2013 tells me that "no executable code such as the target code of the debugger is associated with this line." Does this mean that system_allocator is not actually initialized? (If so, what do these 0x000007fefad31 ... addresses mean?)
I have never encountered this problem with gcc or clang, and this is my first experience using VS. What am I missing?
EDIT: for one chux comment, a test that does not work does not actually work during setup. system_allocator is passed as follows:
HBitWriter *w = h_bit_writer_new(&system_allocator);
A line of code that does not match the first line of HBitWriter *h_bit_writer_new(HAllocator* mm__) :
HBitWriter *writer = h_new(HBitWriter, 1);
where h_new #definined as
#define h_new(type, count) ((type*)(mm__->alloc(mm__, sizeof(type)*(count))))