|
|
|
|
@ -5,31 +5,55 @@
|
|
|
|
|
#include "memory_pool.h" |
|
|
|
|
#include "mem.h" |
|
|
|
|
|
|
|
|
|
#define POOL_CANARY_OFF (pool->object_size) |
|
|
|
|
#define POOL_TAG_OFF (pool->object_size + 1) |
|
|
|
|
#define POOL_ALLOC_SIZE (pool->object_size + 2) |
|
|
|
|
#define POOL_CANARY_VAL 0xAA |
|
|
|
|
|
|
|
|
|
static void pool_init_tags(struct memory_pool* pool, void* obj) |
|
|
|
|
// Layout: [user_data: object_size] [canary: 4 bytes] [alloc_loc: pointer] [counter: 1 byte]
|
|
|
|
|
#define POOL_CANARY_OFF (pool->object_size) |
|
|
|
|
#define POOL_LOC_OFF (pool->object_size + 4) |
|
|
|
|
#define POOL_COUNTER_OFF (pool->object_size + 4 + sizeof(const char*)) |
|
|
|
|
#define POOL_ALLOC_SIZE (pool->object_size + 4 + sizeof(const char*) + 1) |
|
|
|
|
#define POOL_CANARY_VAL 0xDEADBEAF |
|
|
|
|
|
|
|
|
|
static void pool_init_tags(struct memory_pool* pool, void* obj, const char* location) |
|
|
|
|
{ |
|
|
|
|
uint8_t* canary = (uint8_t*)obj + POOL_CANARY_OFF; |
|
|
|
|
uint8_t* counter = (uint8_t*)obj + POOL_TAG_OFF; |
|
|
|
|
uint32_t* canary = (uint32_t*)((uint8_t*)obj + POOL_CANARY_OFF); |
|
|
|
|
const char** loc = (const char**)((uint8_t*)obj + POOL_LOC_OFF); |
|
|
|
|
uint8_t* counter = (uint8_t*)obj + POOL_COUNTER_OFF; |
|
|
|
|
*canary = POOL_CANARY_VAL; |
|
|
|
|
*loc = location; |
|
|
|
|
*counter = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void pool_dump_object(void* obj, size_t len, const char* prefix) |
|
|
|
|
{ |
|
|
|
|
unsigned char* p = (unsigned char*)obj; |
|
|
|
|
char line[128]; |
|
|
|
|
int pos; |
|
|
|
|
size_t cnt = len < 32 ? len : 32; |
|
|
|
|
pos = snprintf(line, sizeof(line), " %s [%zu]:", prefix, len); |
|
|
|
|
for (size_t i = 0; i < cnt; i++) pos += snprintf(line + pos, sizeof(line) - pos, " %02x", p[i]); |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s", line); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void pool_check_and_clear_tags(struct memory_pool* pool, void* obj, const char* location) |
|
|
|
|
{ |
|
|
|
|
uint8_t* canary = (uint8_t*)obj + POOL_CANARY_OFF; |
|
|
|
|
uint8_t* counter = (uint8_t*)obj + POOL_TAG_OFF; |
|
|
|
|
uint32_t* canary = (uint32_t*)((uint8_t*)obj + POOL_CANARY_OFF); |
|
|
|
|
const char** loc = (const char**)((uint8_t*)obj + POOL_LOC_OFF); |
|
|
|
|
uint8_t* counter = (uint8_t*)obj + POOL_COUNTER_OFF; |
|
|
|
|
|
|
|
|
|
if (*canary != POOL_CANARY_VAL) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free BUFFER OVERFLOW %p canary=0x%02x from %s! halting", obj, *canary, location); |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free BUFFER OVERFLOW obj=%p sz=%zu alloc=%s free=%s canary=0x%08x expected=0x%08x", |
|
|
|
|
obj, pool->object_size, *loc ? *loc : "(null)", location, *canary, POOL_CANARY_VAL); |
|
|
|
|
pool_dump_object(obj, pool->object_size, "head"); |
|
|
|
|
pool_dump_object((uint8_t*)obj + (pool->object_size > 32 ? pool->object_size - 32 : 0), |
|
|
|
|
pool->object_size < 32 ? pool->object_size : 32, "tail"); |
|
|
|
|
// dump raw canary area
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, " canary_raw: %02x %02x %02x %02x loc=%p", |
|
|
|
|
((uint8_t*)canary)[0], ((uint8_t*)canary)[1], ((uint8_t*)canary)[2], ((uint8_t*)canary)[3], (void*)*loc); |
|
|
|
|
volatile int _halt = 1; |
|
|
|
|
while (_halt) {} |
|
|
|
|
} |
|
|
|
|
if (*counter == 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free DOUBLE FREE %p from %s! halting", obj, location); |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free DOUBLE FREE obj=%p alloc=%s free=%s! halting", |
|
|
|
|
obj, *loc ? *loc : "(null)", location); |
|
|
|
|
volatile int _halt = 1; |
|
|
|
|
while (_halt) {} |
|
|
|
|
} |
|
|
|
|
@ -70,7 +94,7 @@ void* memory_pool_alloc_impl(struct memory_pool* pool, const char* location) {
|
|
|
|
|
g_total_free--; |
|
|
|
|
pool->reuse_count++; |
|
|
|
|
memset(obj, 0, pool->object_size); |
|
|
|
|
pool_init_tags(pool, obj); |
|
|
|
|
pool_init_tags(pool, obj, location); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "pool_alloc reused: %s, remaining=%zu", location, pool->free_count); |
|
|
|
|
return obj; |
|
|
|
|
} |
|
|
|
|
@ -78,7 +102,7 @@ void* memory_pool_alloc_impl(struct memory_pool* pool, const char* location) {
|
|
|
|
|
pool->allocations++; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "pool_alloc: %s, total_allocs=%zu", location, pool->allocations); |
|
|
|
|
void* obj = u_calloc_impl(1, POOL_ALLOC_SIZE, location); |
|
|
|
|
if (obj) pool_init_tags(pool, obj); |
|
|
|
|
if (obj) pool_init_tags(pool, obj, location); |
|
|
|
|
return obj; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|