Index: epan/emem.c =================================================================== --- epan/emem.c (revision 36949) +++ epan/emem.c (working copy) @@ -105,6 +105,12 @@ #define EMEM_CANARY_SIZE 8 #define EMEM_CANARY_DATA_SIZE (EMEM_CANARY_SIZE * 2 - 1) +typedef struct _emem_chunk_dtor_t { + struct _emem_chunk_dtor_t *next; + emem_dtor_cb dtor; + void *buf; +} emem_chunk_dtor_t; + typedef struct _emem_chunk_t { struct _emem_chunk_t *next; char *buf; @@ -113,6 +119,8 @@ unsigned int free_offset_init; unsigned int free_offset; void *canary_last; + /* This points either to emem_dtor_cb or to emem_chunk_dtor_t */ + void *dtor; } emem_chunk_t; typedef struct _emem_header_t { @@ -122,7 +130,7 @@ emem_tree_t *trees; /* only used by se_mem allocator */ guint8 canary[EMEM_CANARY_DATA_SIZE]; - void *(*memory_alloc)(size_t size, struct _emem_header_t *); + void *(*memory_alloc)(size_t size, struct _emem_header_t *, emem_dtor_cb dtor); /* * Tools like Valgrind and ElectricFence don't work well with memchunks. @@ -173,8 +181,8 @@ static intptr_t pagesize; #endif /* _WIN32 / USE_GUARD_PAGES */ -static void *emem_alloc_chunk(size_t size, emem_header_t *mem); -static void *emem_alloc_glib(size_t size, emem_header_t *mem); +static void *emem_alloc_chunk(size_t size, emem_header_t *mem, emem_dtor_cb dtor); +static void *emem_alloc_glib(size_t size, emem_header_t *mem, emem_dtor_cb dtor); /* * Set a canary value to be placed between memchunks. @@ -634,6 +642,7 @@ npc = g_new(emem_chunk_t, 1); npc->next = NULL; npc->canary_last = NULL; + npc->dtor = NULL; #if defined (_WIN32) /* @@ -707,20 +716,27 @@ } static void * -emem_alloc_chunk(size_t size, emem_header_t *mem) +emem_alloc_chunk(size_t size, emem_header_t *mem, emem_dtor_cb dtor) { void *buf; size_t asize = size; + size_t dsize = size; gboolean use_canary = mem->debug_use_canary; guint8 pad; emem_chunk_t *free_list; + /* Allocate room for destructor's info if needed */ + if(dtor != NULL) { + asize += sizeof(emem_chunk_dtor_t); + dsize = asize; + } + /* Allocate room for at least 8 bytes of canary plus some padding * so the canary ends on an 8-byte boundary. * Then add the room needed for the pointer to the next canary. */ - if (use_canary) { + if (use_canary) { pad = emem_canary_pad(asize); asize += sizeof(void *); } else @@ -783,8 +799,16 @@ free_list->amount_free -= (unsigned int) asize; free_list->free_offset += (unsigned int) asize; + if(dtor) { + emem_chunk_dtor_t *chunk_dtor = (emem_chunk_dtor_t*)((char*)buf + size); + chunk_dtor->dtor = dtor; + chunk_dtor->buf = buf; + chunk_dtor->next = (emem_chunk_dtor_t*)free_list->dtor; + free_list->dtor = chunk_dtor; + } + if (use_canary) { - char *cptr = (char *)buf + size; + char *cptr = (char *)buf + dsize; memcpy(cptr, mem->canary, pad-1); cptr[pad-1] = '\0'; @@ -797,13 +821,14 @@ } static void * -emem_alloc_glib(size_t size, emem_header_t *mem) +emem_alloc_glib(size_t size, emem_header_t *mem, emem_dtor_cb dtor) { emem_chunk_t *npc; npc=g_new(emem_chunk_t, 1); npc->next=mem->used_list; npc->buf=g_malloc(size); + npc->dtor=dtor; npc->canary_last = NULL; mem->used_list=npc; /* There's no padding/alignment involved (from our point of view) when @@ -816,9 +841,9 @@ /* allocate 'size' amount of memory. */ static void * -emem_alloc(size_t size, emem_header_t *mem) +emem_alloc(size_t size, emem_header_t *mem, emem_dtor_cb dtor) { - void *buf = mem->memory_alloc(size, mem); + void *buf = mem->memory_alloc(size, mem, dtor); /* XXX - this is a waste of time if the allocator function is going to * memset this straight back to 0. @@ -834,31 +859,61 @@ void * ep_alloc(size_t size) { - return emem_alloc(size, &ep_packet_mem); + return emem_alloc(size, &ep_packet_mem, NULL); } /* allocate 'size' amount of memory with an allocation lifetime until the + * next packet, call dtor just before lifetime ends. + */ +void * +ep_alloc_dtor(size_t size, emem_dtor_cb dtor) +{ + return emem_alloc(size, &ep_packet_mem, dtor); +} + +/* allocate 'size' amount of memory with an allocation lifetime until the * next capture. */ void * se_alloc(size_t size) { - return emem_alloc(size, &se_packet_mem); + return emem_alloc(size, &se_packet_mem, NULL); } +/* allocate 'size' amount of memory with an allocation lifetime until the + * next capture, call dtor just before lifetime ends. + */ void * +se_alloc_dtor(size_t size, emem_dtor_cb dtor) +{ + return emem_alloc(size, &se_packet_mem, dtor); +} + +void * ep_alloc0(size_t size) { return memset(ep_alloc(size),'\0',size); } void * +ep_alloc_dtor0(size_t size, emem_dtor_cb dtor) +{ + return memset(ep_alloc_dtor(size, dtor),'\0',size); +} + +void * se_alloc0(size_t size) { return memset(se_alloc(size),'\0',size); } +void * +se_alloc_dtor0(size_t size, emem_dtor_cb dtor) +{ + return memset(se_alloc_dtor(size, dtor),'\0',size); +} + static gchar * emem_strdup(const gchar *src, void *allocator(size_t)) { @@ -1119,6 +1174,13 @@ npc = mem->free_list; while (npc != NULL) { if (use_chunks) { + emem_chunk_dtor_t *dtor = (emem_chunk_dtor_t *)npc->dtor; + while (dtor != NULL) { + dtor->dtor(dtor->buf); + dtor = dtor->next; + } + npc->dtor = NULL; + while (npc->canary_last != NULL) { npc->canary_last = emem_canary_next(mem->canary, npc->canary_last, NULL); /* XXX, check if canary_last is inside allocated memory? */ @@ -1137,6 +1199,9 @@ } else { emem_chunk_t *next = npc->next; + if(npc->dtor) + ((emem_dtor_cb)npc->dtor)(npc->buf); + emem_scrub_memory(npc->buf, npc->amount_free_init, FALSE); g_free(npc->buf); Index: epan/emem.h =================================================================== --- epan/emem.h (revision 36949) +++ epan/emem.h (working copy) @@ -36,6 +36,10 @@ */ void emem_init(void); +/** Destructor callback. Called when the memory chunk previously allocated in + * one of the pools is about to be collected. The supplied argument is the chunk it self */ +typedef void (*emem_dtor_cb)(void *chunk); + /* Functions for handling memory allocation and garbage collection with * a packet lifetime scope. * These functions are used to allocate memory that will only remain persistent @@ -56,6 +60,16 @@ void* ep_alloc0(size_t size) G_GNUC_MALLOC; #define ep_new0(type) ((type*)ep_alloc0(sizeof(type))) +/** Allocate memory with a packet lifetime scope and call dtor before memory is + * deallocated + */ +void *ep_alloc_dtor(size_t size, emem_dtor_cb dtor) G_GNUC_MALLOC; + +/** Allocate memory with a packet lifetime scope, fill it with zeros and call dtor + * before memory is deallocated + */ +void *ep_alloc_dtor0(size_t size, emem_dtor_cb dtor) G_GNUC_MALLOC; + /** Duplicate a string with a packet lifetime scope */ gchar* ep_strdup(const gchar* src) G_GNUC_MALLOC; @@ -76,10 +90,20 @@ #define ep_alloc_array(type,num) (type*)ep_alloc(sizeof(type)*(num)) /** allocates with a packet lifetime scope an array of type made of num elements, - * initialised to zero. + * initialised to zero */ #define ep_alloc_array0(type,num) (type*)ep_alloc0(sizeof(type)*(num)) +/** allocates with a packet lifetime scope an array of type made of num elements + * and dtor is called before memory is deallocated + */ +#define ep_alloc_array_dtor(type,num,dtor) (type*)ep_alloc_dtor(sizeof(type)*(num),dtor) + +/** allocates with a packet lifetime scope an array of type made of num elements, + * initialised to zero, and dtor is called before memory is deallocated + */ +#define ep_alloc_array_dtor0(type,num,dtor) (type*)ep_alloc_dtor0(sizeof(type)*(num),dtor) + /** * Splits a string into a maximum of max_tokens pieces, using the given * delimiter. If max_tokens is reached, the remainder of string is appended @@ -141,6 +165,16 @@ /** Allocate memory with a capture lifetime scope and fill it with zeros*/ void* se_alloc0(size_t size) G_GNUC_MALLOC; +/** Allocate memory with a capture lifetime scope and call dtor before memory is + * deallocated + */ +void *se_alloc_dtor(size_t size, emem_dtor_cb dtor) G_GNUC_MALLOC; + +/** Allocate memory with a capture lifetime scope, fill it with zeros and call dtor + * before memory is deallocated + */ +void* se_alloc_dtor0(size_t size, emem_dtor_cb dtor) G_GNUC_MALLOC; + /** Duplicate a string with a capture lifetime scope */ gchar* se_strdup(const gchar* src) G_GNUC_MALLOC; @@ -158,7 +192,12 @@ /** allocates with a capture lifetime scope an array of type made of num elements */ #define se_alloc_array(type,num) (type*)se_alloc(sizeof(type)*(num)) -/** release all memory allocated */ +/** allocates with a capture lifetime scope an array of type made of num elements + * and dtor is called before memory is deallocated + */ +#define se_alloc_array_dtor(type,num,dtor) (type*)se_alloc(sizeof(type)*(num),dtor) + +/** release all memory allocated and call destructors before release occurs */ void se_free_all(void); Index: epan/libwireshark.def =================================================================== --- epan/libwireshark.def (revision 36949) +++ epan/libwireshark.def (working copy) @@ -367,6 +367,8 @@ ep_address_to_str ep_alloc ep_alloc0 +ep_alloc_dtor +ep_alloc_dtor0 ep_free_all ep_memdup ep_stack_new @@ -934,6 +936,8 @@ scsi_ssc_vals DATA se_alloc se_alloc0 +se_alloc_dtor +se_alloc_dtor0 se_memdup se_strdup se_strdup_printf