#include "sync/sync.h" #include "memory_region.h" #include "rust_env.h" #if RUSTRT_TRACK_ALLOCATIONS >= 3 #include #endif #if RUSTRT_TRACK_ALLOCATIONS >= 1 // For some platforms, 16 byte alignment is required. # define PTR_SIZE 16 # define ALIGN_PTR(x) (((x)+PTR_SIZE-1)/PTR_SIZE*PTR_SIZE) # define HEADER_SIZE ALIGN_PTR(sizeof(alloc_header)) # define MAGIC 0xbadc0ffe #else # define HEADER_SIZE 0 #endif memory_region::alloc_header *memory_region::get_header(void *mem) { return (alloc_header *)((char *)mem - HEADER_SIZE); } void *memory_region::get_data(alloc_header *ptr) { return (void*)((char *)ptr + HEADER_SIZE); } memory_region::memory_region(rust_env *env, bool synchronized) : _env(env), _parent(NULL), _live_allocations(0), _detailed_leaks(env->detailed_leaks), _synchronized(synchronized) { } memory_region::memory_region(memory_region *parent) : _env(parent->_env), _parent(parent), _live_allocations(0), _detailed_leaks(parent->_detailed_leaks), _synchronized(parent->_synchronized) { } void memory_region::add_alloc() { //_live_allocations++; sync::increment(_live_allocations); } void memory_region::dec_alloc() { //_live_allocations--; sync::decrement(_live_allocations); } void memory_region::free(void *mem) { // printf("free: ptr 0x%" PRIxPTR" region=%p\n", (uintptr_t) mem, this); if (!mem) { return; } alloc_header *alloc = get_header(mem); # if RUSTRT_TRACK_ALLOCATIONS >= 1 assert(alloc->magic == MAGIC); # endif if (_live_allocations < 1) { assert(false && "live_allocs < 1"); } release_alloc(mem); maybe_poison(mem); ::free(alloc); } void * memory_region::realloc(void *mem, size_t orig_size) { if (!mem) { add_alloc(); } alloc_header *alloc = get_header(mem); # if RUSTRT_TRACK_ALLOCATIONS >= 1 assert(alloc->magic == MAGIC); # endif size_t size = orig_size + HEADER_SIZE; alloc_header *newMem = (alloc_header *)::realloc(alloc, size); # if RUSTRT_TRACK_ALLOCATIONS >= 1 assert(newMem->magic == MAGIC); newMem->size = orig_size; # endif # if RUSTRT_TRACK_ALLOCATIONS >= 2 if (_synchronized) { _lock.lock(); } if (_allocation_list[newMem->index] != alloc) { printf("at index %d, found %p, expected %p\n", alloc->index, _allocation_list[alloc->index], alloc); printf("realloc: ptr 0x%" PRIxPTR " (%s) is not in allocation_list\n", (uintptr_t) get_data(alloc), alloc->tag); assert(false && "not in allocation_list"); } else { _allocation_list[newMem->index] = newMem; // printf("realloc: stored %p at index %d, replacing %p\n", // newMem, index, mem); } if (_synchronized) { _lock.unlock(); } # endif return get_data(newMem); } void * memory_region::malloc(size_t size, const char *tag, bool zero) { size_t old_size = size; size += HEADER_SIZE; alloc_header *mem = (alloc_header *)::malloc(size); # if RUSTRT_TRACK_ALLOCATIONS >= 1 mem->magic = MAGIC; mem->tag = tag; mem->index = -1; mem->size = old_size; # endif void *data = get_data(mem); claim_alloc(data); if(zero) { memset(data, 0, old_size); } return data; } void * memory_region::calloc(size_t size, const char *tag) { return malloc(size, tag, true); } memory_region::~memory_region() { if (_synchronized) { _lock.lock(); } if (_live_allocations == 0 && !_detailed_leaks) { if (_synchronized) { _lock.unlock(); } return; } char msg[128]; if(_live_allocations > 0) { snprintf(msg, sizeof(msg), "leaked memory in rust main loop (%d objects)", _live_allocations); } # if RUSTRT_TRACK_ALLOCATIONS >= 2 if (_detailed_leaks) { int leak_count = 0; for (size_t i = 0; i < _allocation_list.size(); i++) { if (_allocation_list[i] != NULL) { alloc_header *header = (alloc_header*)_allocation_list[i]; printf("allocation (%s) 0x%" PRIxPTR " was not freed\n", header->tag, (uintptr_t) get_data(header)); ++leak_count; # if RUSTRT_TRACK_ALLOCATIONS >= 3 if (_detailed_leaks) { backtrace_symbols_fd(header->bt + 1, header->btframes - 1, 2); } # endif } } assert(leak_count == _live_allocations); } # endif if (_live_allocations > 0) { fprintf(stderr, "%s\n", msg); assert(false); } if (_synchronized) { _lock.unlock(); } } void memory_region::release_alloc(void *mem) { # if RUSTRT_TRACK_ALLOCATIONS >= 1 alloc_header *alloc = get_header(mem); assert(alloc->magic == MAGIC); # endif # if RUSTRT_TRACK_ALLOCATIONS >= 2 if (_synchronized) { _lock.lock(); } if (_allocation_list[alloc->index] != alloc) { printf("free: ptr 0x%" PRIxPTR " (%s) is not in allocation_list\n", (uintptr_t) get_data(alloc), alloc->tag); assert(false && "not in allocation_list"); } else { // printf("freed index %d\n", index); _allocation_list[alloc->index] = NULL; alloc->index = -1; } if (_synchronized) { _lock.unlock(); } # endif dec_alloc(); } void memory_region::claim_alloc(void *mem) { # if RUSTRT_TRACK_ALLOCATIONS >= 1 alloc_header *alloc = get_header(mem); assert(alloc->magic == MAGIC); # endif # if RUSTRT_TRACK_ALLOCATIONS >= 2 if (_synchronized) { _lock.lock(); } alloc->index = _allocation_list.append(alloc); if (_synchronized) { _lock.unlock(); } # endif # if RUSTRT_TRACK_ALLOCATIONS >= 3 if (_detailed_leaks) { alloc->btframes = ::backtrace(alloc->bt, 32); } # endif add_alloc(); } void memory_region::maybe_poison(void *mem) { if (!_env->poison_on_free) return; # if RUSTRT_TRACK_ALLOCATIONS >= 1 alloc_header *alloc = get_header(mem); memset(mem, '\xcd', alloc->size); # endif } // // Local Variables: // mode: C++ // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // End: //