diff options
author | Evan Huus <eapache@gmail.com> | 2013-01-23 02:31:04 +0000 |
---|---|---|
committer | Evan Huus <eapache@gmail.com> | 2013-01-23 02:31:04 +0000 |
commit | 0cb2a257dee749e8d62c40d1a831efad8a87afce (patch) | |
tree | 20470ad876df10cc67709f0c3c676a1a8e0643c5 /epan/wmem | |
parent | ec7d4f0cfd42209ef35293a0e4f00d339b7a7745 (diff) |
Convert the strict allocator to use a hash table similarly to the simple
allocator, allowing it to implement realloc and free.
svn path=/trunk/; revision=47222
Diffstat (limited to 'epan/wmem')
-rw-r--r-- | epan/wmem/wmem_allocator_strict.c | 187 |
1 files changed, 138 insertions, 49 deletions
diff --git a/epan/wmem/wmem_allocator_strict.c b/epan/wmem/wmem_allocator_strict.c index 5955d41c47..ad87b83314 100644 --- a/epan/wmem/wmem_allocator_strict.c +++ b/epan/wmem/wmem_allocator_strict.c @@ -27,6 +27,8 @@ #include <glib.h> +#include "config.h" + #include "wmem_core.h" #include "wmem_allocator.h" @@ -44,9 +46,6 @@ #define WMEM_POSTFILL 0x1A typedef struct _wmem_strict_allocator_block_t { - /* Simple manual singly-linked list of allocations */ - struct _wmem_strict_allocator_block_t *next; - /* Just the length of real_data, not counting the canaries */ gsize data_len; @@ -56,93 +55,181 @@ typedef struct _wmem_strict_allocator_block_t { } wmem_strict_allocator_block_t; typedef struct _wmem_strict_allocator_t { - wmem_strict_allocator_block_t *block_list; + GHashTable *block_table; } wmem_strict_allocator_t; -static void * -wmem_strict_alloc(void *private_data, const size_t size) +/* + * some internal helper functions + */ +static void +wmem_strict_block_check_canaries(wmem_strict_allocator_block_t *block) +{ + guint i; + + for (i=0; i<WMEM_CANARY_SIZE; i++) { + g_assert(block->leading_canary[i] == WMEM_CANARY_VALUE); + g_assert(block->trailing_canary[i] == WMEM_CANARY_VALUE); + } +} + +/* wrapper for use with g_hash_table_foreach() */ +static void +wmem_strict_ghash_check_canaries(gpointer key _U_, gpointer value, + gpointer user_data _U_) +{ + wmem_strict_block_check_canaries(value); +} + +static void +wmem_strict_block_free(wmem_strict_allocator_block_t *block) +{ + memset(block->real_data, WMEM_POSTFILL, block->data_len); + + g_free(block->leading_canary); + g_free(block); +} + +/* wrapper for use with g_hash_table_new_full() */ +static void +wmem_strict_ghash_block_free(gpointer data) +{ + wmem_strict_block_free(data); +} + +static wmem_strict_allocator_block_t * +wmem_strict_block_new(const size_t size) { - wmem_strict_allocator_t *allocator; wmem_strict_allocator_block_t *block; - allocator = (wmem_strict_allocator_t*) private_data; - block = g_new(wmem_strict_allocator_block_t, 1); block->data_len = size; block->leading_canary = g_malloc(block->data_len + (2 * WMEM_CANARY_SIZE)); block->real_data = block->leading_canary + WMEM_CANARY_SIZE; block->trailing_canary = block->real_data + block->data_len; - block->next = allocator->block_list; - allocator->block_list = block; memset(block->leading_canary, WMEM_CANARY_VALUE, WMEM_CANARY_SIZE); memset(block->real_data, WMEM_PREFILL, block->data_len); memset(block->trailing_canary, WMEM_CANARY_VALUE, WMEM_CANARY_SIZE); + + return block; +} + +/* + * public API functions + */ +static void * +wmem_strict_alloc(void *private_data, const size_t size) +{ + wmem_strict_allocator_t *allocator; + wmem_strict_allocator_block_t *block; + + allocator = (wmem_strict_allocator_t*) private_data; + + block = wmem_strict_block_new(size); + + /* we store a pointer to our header, keyed by a pointer to the actual + * block we return to the user */ + g_hash_table_insert(allocator->block_table, block->real_data, block); return block->real_data; } static void -wmem_strict_real_check_canaries(wmem_strict_allocator_t *allocator) +wmem_strict_free(void *private_data, void *ptr) { - guint i; + wmem_strict_allocator_t *allocator; wmem_strict_allocator_block_t *block; + + allocator = (wmem_strict_allocator_t*) private_data; + + block = g_hash_table_lookup(allocator->block_table, ptr); + + g_assert(block); + + wmem_strict_block_check_canaries(block); + + g_hash_table_remove(allocator->block_table, ptr); +} + +static void * +wmem_strict_realloc(void *private_data, void *ptr, const size_t size) +{ + gsize copy_len; + wmem_strict_allocator_t *allocator; + wmem_strict_allocator_block_t *block, *newblock; + + allocator = (wmem_strict_allocator_t*) private_data; - block = allocator->block_list; + /* retrieve and check the old block */ + block = g_hash_table_lookup(allocator->block_table, ptr); + g_assert(block); + wmem_strict_block_check_canaries(block); + + /* create a new block */ + newblock = wmem_strict_block_new(size); - while (block) { - for (i=0; i<WMEM_CANARY_SIZE; i++) { - g_assert(block->leading_canary[i] == WMEM_CANARY_VALUE); - g_assert(block->trailing_canary[i] == WMEM_CANARY_VALUE); - } - block = block->next; + /* copy from the old block to the new */ + if (block->data_len > newblock->data_len) { + copy_len = newblock->data_len; + } + else { + copy_len = block->data_len; } + + memcpy(newblock->real_data, block->real_data, copy_len); + + /* update the hash table */ + g_hash_table_remove(allocator->block_table, ptr); + g_hash_table_insert(allocator->block_table, newblock->real_data, newblock); + + return newblock->real_data; } void wmem_strict_check_canaries(wmem_allocator_t *allocator) { - /* XXX: Should this be a g_assert() instead? This is more of a general API - * issue - should allocator-specific functions be safe to call with an - * allocator of the wrong type or not? And how should they interact with the - * WIRESHARK_DEBUG_WMEM_OVERRIDE environment variable? */ + wmem_strict_allocator_t *private_allocator; + if (allocator->type != WMEM_ALLOCATOR_STRICT) { return; } + + private_allocator = (wmem_strict_allocator_t*) allocator->private_data; - wmem_strict_real_check_canaries(allocator->private_data); + g_hash_table_foreach(private_allocator->block_table, + &wmem_strict_ghash_check_canaries, NULL); } static void wmem_strict_free_all(void *private_data) { wmem_strict_allocator_t *allocator; - wmem_strict_allocator_block_t *block, *tmp; allocator = (wmem_strict_allocator_t*) private_data; - wmem_strict_real_check_canaries(allocator); - - block = allocator->block_list; - - while (block) { - memset(block->real_data, WMEM_POSTFILL, block->data_len); - - g_free(block->leading_canary); + g_hash_table_foreach(allocator->block_table, + &wmem_strict_ghash_check_canaries, NULL); - tmp = block; - block = block->next; - g_free(tmp); - } + g_hash_table_remove_all(allocator->block_table); +} - allocator->block_list = NULL; +static void +wmem_strict_gc(void *private_data _U_) +{ + /* We don't really have anything to garbage-collect, but it might be worth + * checking our canaries at this point? */ } static void wmem_strict_allocator_destroy(wmem_allocator_t *allocator) { - g_free(allocator->private_data); + wmem_strict_allocator_t *private_allocator; + + private_allocator = (wmem_strict_allocator_t*) allocator->private_data; + + g_hash_table_destroy(private_allocator->block_table); + g_free(private_allocator); g_free(allocator); } @@ -155,17 +242,19 @@ wmem_strict_allocator_new(void) allocator = g_new(wmem_allocator_t, 1); strict_allocator = g_new(wmem_strict_allocator_t, 1); - allocator->alloc = &wmem_strict_alloc; - allocator->free_all = &wmem_strict_free_all; - allocator->destroy = &wmem_strict_allocator_destroy; - allocator->private_data = (void*) strict_allocator; + allocator->alloc = &wmem_strict_alloc; + allocator->realloc = &wmem_strict_realloc; + allocator->free = &wmem_strict_free; - /* TODO */ - allocator->realloc = NULL; - allocator->free = NULL; - allocator->gc = NULL; + allocator->free_all = &wmem_strict_free_all; + allocator->gc = &wmem_strict_gc; + allocator->destroy = &wmem_strict_allocator_destroy; + + allocator->private_data = (void*) strict_allocator; - strict_allocator->block_list = NULL; + strict_allocator->block_table = g_hash_table_new_full( + &g_direct_hash, &g_direct_equal, + NULL, &wmem_strict_ghash_block_free); return allocator; } |