diff options
author | Gerald Combs <gerald@wireshark.org> | 2006-01-09 23:11:40 +0000 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2006-01-09 23:11:40 +0000 |
commit | c919d31d092f2cc82fc325a8f925d719bda61c08 (patch) | |
tree | 12260f3a9e721643bba6614c3e10ce1eb3042732 /epan | |
parent | d5649bc2de2d33b7ca404dd70298f0ceb3837ee3 (diff) |
Add canary values after each allocation. If our canaries values don't
match when we call {ep|se}_free_all(), throw an assertion.
svn path=/trunk/; revision=16984
Diffstat (limited to 'epan')
-rw-r--r-- | epan/emem.c | 232 |
1 files changed, 151 insertions, 81 deletions
diff --git a/epan/emem.c b/epan/emem.c index 4b0190c66b..9e752d1b95 100644 --- a/epan/emem.c +++ b/epan/emem.c @@ -30,6 +30,24 @@ #include <stdlib.h> #include <string.h> #include <stdarg.h> + +#include <time.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef _WIN32 +#include <process.h> /* getpid */ +#endif + #include <glib.h> #include <proto.h> #include "emem.h" @@ -37,19 +55,31 @@ /* When required, allocate more memory from the OS in this size chunks */ #define EMEM_PACKET_CHUNK_SIZE 10485760 +/* The maximum number of allocations per chunk */ +#define EMEM_ALLOCS_PER_CHUNK (EMEM_PACKET_CHUNK_SIZE / 512) + /* - * Tools like Valgrind and ElectricFence don't work well with memchunks. + * Tools like Valgrind and ElectricFence don't work well with memchunks. * Uncomment the defines below to make {ep|se}_alloc() allocate each * object individually. */ /* #define EP_DEBUG_FREE 1 */ /* #define SE_DEBUG_FREE 1 */ +#if GLIB_MAJOR_VERSION >= 2 +GRand *rand_state = NULL; +#endif +/* XXX - Are four bytes enough? ProPolice uses 8. */ +guint32 ep_canary, se_canary; +#define EMEM_CANARY_SIZE sizeof(guint32) + typedef struct _emem_chunk_t { struct _emem_chunk_t *next; unsigned int amount_free; unsigned int free_offset; char *buf; + unsigned int c_count; + void *canary[EMEM_ALLOCS_PER_CHUNK]; } emem_chunk_t; typedef struct _emem_header_t { @@ -60,59 +90,103 @@ typedef struct _emem_header_t { static emem_header_t ep_packet_mem; static emem_header_t se_packet_mem; +/* + * Set a canary value to be placed between memchunks. + */ + +guint32 +emem_canary() { + guint32 canary; + int fd; + size_t sz; + + /* Try /dev/urandom first */ + fd = open("/dev/urandom", 0); + if (fd != -1) { + sz = read(fd, &canary, EMEM_CANARY_SIZE); + if (sz == EMEM_CANARY_SIZE) { + return canary; + } + } + + /* Next, use GLib's random function if we have it */ +#if GLIB_MAJOR_VERSION >= 2 + if (rand_state == NULL) { + rand_state = g_rand_new(); + } + return g_rand_int(rand_state); +#else + /* Our last resort */ + return (guint32) time(NULL) | getpid(); +#endif /* GLIB_MAJOR_VERSION >= 2 */ +} + /* Initialize the packet-lifetime memory allocation pool. - * This function should be called only once when Etehreal or Tethereal starts + * This function should be called only once when Ethereal or Tethereal starts * up. */ void ep_init_chunk(void) { - ep_packet_mem.free_list=NULL; - ep_packet_mem.used_list=NULL; + ep_packet_mem.free_list=NULL; + ep_packet_mem.used_list=NULL; + + ep_canary = emem_canary(); } /* Initialize the capture-lifetime memory allocation pool. - * This function should be called only once when Etehreal or Tethereal starts + * This function should be called only once when Ethereal or Tethereal starts * up. */ void se_init_chunk(void) { - se_packet_mem.free_list=NULL; - se_packet_mem.used_list=NULL; + se_packet_mem.free_list=NULL; + se_packet_mem.used_list=NULL; + + se_canary = emem_canary(); } +#define EMEM_CREATE_CHUNK(FREE_LIST) \ + /* we dont have any free data, so we must allocate a new one */ \ + if(!FREE_LIST){ \ + emem_chunk_t *npc; \ + npc=g_malloc(sizeof(emem_chunk_t)); \ + npc->next=NULL; \ + npc->amount_free=EMEM_PACKET_CHUNK_SIZE; \ + npc->free_offset=0; \ + npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE); \ + npc->c_count = 0; \ + FREE_LIST=npc; \ + } + /* allocate 'size' amount of memory with an allocation lifetime until the * next packet. */ void * ep_alloc(size_t size) { - void *buf; + void *buf, *cptr; #ifndef EP_DEBUG_FREE /* round up to 8 byte boundary */ + /* XXX - Commented out, since the canary values should be adjacent + * to the end/beginning of each buffer. */ + /* if(size&0x07){ size=(size+7)&0xfffffff8; } + */ + size += EMEM_CANARY_SIZE; /* make sure we dont try to allocate too much (arbitrary limit) */ DISSECTOR_ASSERT(size<(EMEM_PACKET_CHUNK_SIZE>>2)); - /* we dont have any free data, so we must allocate a new one */ - if(!ep_packet_mem.free_list){ - emem_chunk_t *npc; - npc=g_malloc(sizeof(emem_chunk_t)); - npc->next=NULL; - npc->amount_free=EMEM_PACKET_CHUNK_SIZE; - npc->free_offset=0; - npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE); - ep_packet_mem.free_list=npc; - } + EMEM_CREATE_CHUNK(ep_packet_mem.free_list); /* oops, we need to allocate more memory to serve this request * than we have free. move this node to the used list and try again */ - if(size>ep_packet_mem.free_list->amount_free){ + if(size>ep_packet_mem.free_list->amount_free || ep_packet_mem.free_list->c_count >= EMEM_ALLOCS_PER_CHUNK){ emem_chunk_t *npc; npc=ep_packet_mem.free_list; ep_packet_mem.free_list=ep_packet_mem.free_list->next; @@ -120,23 +194,18 @@ ep_alloc(size_t size) ep_packet_mem.used_list=npc; } - /* we dont have any free data, so we must allocate a new one */ - if(!ep_packet_mem.free_list){ - emem_chunk_t *npc; - npc=g_malloc(sizeof(emem_chunk_t)); - npc->next=NULL; - npc->amount_free=EMEM_PACKET_CHUNK_SIZE; - npc->free_offset=0; - npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE); - ep_packet_mem.free_list=npc; - } - + EMEM_CREATE_CHUNK(ep_packet_mem.free_list); buf=ep_packet_mem.free_list->buf+ep_packet_mem.free_list->free_offset; ep_packet_mem.free_list->amount_free-=size; ep_packet_mem.free_list->free_offset+=size; + cptr = buf + size - EMEM_CANARY_SIZE; + ep_packet_mem.free_list->canary[ep_packet_mem.free_list->c_count] = cptr; + memcpy(cptr, &ep_canary, EMEM_CANARY_SIZE); + ep_packet_mem.free_list->c_count++; + #else /* EP_DEBUG_FREE */ emem_chunk_t *npc; @@ -157,32 +226,28 @@ ep_alloc(size_t size) void * se_alloc(size_t size) { - void *buf; + void *buf, *cptr; #ifndef SE_DEBUG_FREE /* round up to 8 byte boundary */ + /* XXX - Commented out, since the canary values should be adjacent + * to the end/beginning of each buffer. */ + /* if(size&0x07){ size=(size+7)&0xfffffff8; } + */ + size += EMEM_CANARY_SIZE; /* make sure we dont try to allocate too much (arbitrary limit) */ DISSECTOR_ASSERT(size<(EMEM_PACKET_CHUNK_SIZE>>2)); - /* we dont have any free data, so we must allocate a new one */ - if(!se_packet_mem.free_list){ - emem_chunk_t *npc; - npc=g_malloc(sizeof(emem_chunk_t)); - npc->next=NULL; - npc->amount_free=EMEM_PACKET_CHUNK_SIZE; - npc->free_offset=0; - npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE); - se_packet_mem.free_list=npc; - } + EMEM_CREATE_CHUNK(se_packet_mem.free_list); /* oops, we need to allocate more memory to serve this request * than we have free. move this node to the used list and try again */ - if(size>se_packet_mem.free_list->amount_free){ + if(size>se_packet_mem.free_list->amount_free || se_packet_mem.free_list->c_count >= EMEM_ALLOCS_PER_CHUNK){ emem_chunk_t *npc; npc=se_packet_mem.free_list; se_packet_mem.free_list=se_packet_mem.free_list->next; @@ -190,23 +255,18 @@ se_alloc(size_t size) se_packet_mem.used_list=npc; } - /* we dont have any free data, so we must allocate a new one */ - if(!se_packet_mem.free_list){ - emem_chunk_t *npc; - npc=g_malloc(sizeof(emem_chunk_t)); - npc->next=NULL; - npc->amount_free=EMEM_PACKET_CHUNK_SIZE; - npc->free_offset=0; - npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE); - se_packet_mem.free_list=npc; - } - + EMEM_CREATE_CHUNK(se_packet_mem.free_list); buf=se_packet_mem.free_list->buf+se_packet_mem.free_list->free_offset; se_packet_mem.free_list->amount_free-=size; se_packet_mem.free_list->free_offset+=size; + cptr = buf + size - EMEM_CANARY_SIZE; + se_packet_mem.free_list->canary[se_packet_mem.free_list->c_count] = cptr; + memcpy(cptr, &se_canary, EMEM_CANARY_SIZE); + se_packet_mem.free_list->c_count++; + #else /* SE_DEBUG_FREE */ emem_chunk_t *npc; @@ -230,23 +290,23 @@ void* ep_alloc0(size_t size) { gchar* ep_strdup(const gchar* src) { guint len = strlen(src); gchar* dst; - + dst = strncpy(ep_alloc(len+1), src, len); dst[len] = '\0'; - + return dst; } gchar* ep_strndup(const gchar* src, size_t len) { gchar* dst = ep_alloc(len+1); guint i; - + for (i = 0; src[i] && i < len; i++) dst[i] = src[i]; - + dst[i] = '\0'; - + return dst; } @@ -273,7 +333,7 @@ gchar* ep_strdup_vprintf(const gchar* fmt, va_list ap) { gchar* ep_strdup_printf(const gchar* fmt, ...) { va_list ap; gchar* dst; - + va_start(ap,fmt); dst = ep_strdup_vprintf(fmt, ap); va_end(ap); @@ -290,34 +350,34 @@ gchar** ep_strsplit(const gchar* string, const gchar* sep, int max_tokens) { gchar** vec; enum { AT_START, IN_PAD, IN_TOKEN } state; guint curr_tok = 0; - - if ( ! string + + if ( ! string || ! sep || ! sep[0]) return NULL; - + s = splitted = ep_strdup(string); str_len = strlen(splitted); sep_len = strlen(sep); - + if (max_tokens < 1) max_tokens = INT_MAX; tokens = 1; - - + + while (tokens <= (guint)max_tokens && ( s = strstr(s,sep) )) { tokens++; - + for(i=0; i < sep_len; i++ ) s[i] = '\0'; - + s += sep_len; - - } - + + } + vec = ep_alloc_array(gchar*,tokens+1); state = AT_START; - + for (i=0; i< str_len; i++) { switch(state) { case AT_START: @@ -349,9 +409,9 @@ gchar** ep_strsplit(const gchar* string, const gchar* sep, int max_tokens) { } } } - + vec[curr_tok] = NULL; - + return vec; } @@ -367,28 +427,28 @@ void* se_alloc0(size_t size) { gchar* se_strdup(const gchar* src) { guint len; gchar* dst; - + if(!src){ return "<NULL>"; } len = strlen(src); dst = strncpy(se_alloc(len+1), src, len); - + dst[len] = '\0'; - + return dst; } gchar* se_strndup(const gchar* src, size_t len) { gchar* dst = se_alloc(len+1); guint i; - + for (i = 0; src[i] && i < len; i++) dst[i] = src[i]; - + dst[i] = '\0'; - + return dst; } @@ -415,7 +475,7 @@ gchar* se_strdup_vprintf(const gchar* fmt, va_list ap) { gchar* se_strdup_printf(const gchar* fmt, ...) { va_list ap; gchar* dst; - + va_start(ap,fmt); dst = se_strdup_vprintf(fmt, ap); va_end(ap); @@ -428,6 +488,7 @@ void ep_free_all(void) { emem_chunk_t *npc; + guint i; /* move all used chunks over to the free list */ while(ep_packet_mem.used_list){ @@ -441,6 +502,10 @@ ep_free_all(void) npc = ep_packet_mem.free_list; while (npc != NULL) { #ifndef EP_DEBUG_FREE + for (i = 0; i < npc->c_count; i++) { + g_assert(memcmp(npc->canary[i], &ep_canary, EMEM_CANARY_SIZE) == 0); + } + npc->c_count = 0; npc->amount_free=EMEM_PACKET_CHUNK_SIZE; npc->free_offset=0; npc = npc->next; @@ -463,6 +528,7 @@ void se_free_all(void) { emem_chunk_t *npc; + guint i; /* move all used chunks ove to the free list */ while(se_packet_mem.used_list){ @@ -476,6 +542,10 @@ se_free_all(void) npc = se_packet_mem.free_list; while (npc != NULL) { #ifndef SE_DEBUG_FREE + for (i = 0; i < npc->c_count; i++) { + g_assert(memcmp(npc->canary[i], &se_canary, EMEM_CANARY_SIZE) == 0); + } + npc->c_count = 0; npc->amount_free=EMEM_PACKET_CHUNK_SIZE; npc->free_offset=0; npc = npc->next; @@ -525,7 +595,7 @@ void* ep_stack_push(ep_stack_t stack, void* data) { } void* ep_stack_pop(ep_stack_t stack) { - + if ((*stack)->below) { (*stack) = (*stack)->below; return (*stack)->above->payload; |