We now expose the following environment variables:

* WIRESHARK_DEBUG_EP_NO_CHUNKS
 * WIRESHARK_DEBUG_SE_NO_CHUNKS
 * WIRESHARK_DEBUG_EP_NO_CANARY
 * WIRESHARK_DEBUG_SE_NO_CANARY

This allows us to enable/disable memory chunks and canaries at runtime _without_ needing to recompile.

svn path=/trunk/; revision=29375
This commit is contained in:
Kovarththanan Rajaratnam 2009-08-11 09:24:56 +00:00
parent a8fbd4577f
commit e0e33ca74b
2 changed files with 110 additions and 111 deletions

View File

@ -51,19 +51,25 @@
#include <process.h> /* getpid */
#endif
/*
* Tools like Valgrind and ElectricFence don't work well with memchunks.
* Uncomment the defines below to make {ep|se}_alloc() allocate each
* Export the following environment variables to make {ep|se}_alloc() allocate each
* object individually.
*
* WIRESHARK_DEBUG_EP_NO_CHUNKS
* WIRESHARK_DEBUG_SE_NO_CHUNKS
*/
/* #define EP_DEBUG_FREE 1 */
/* #define SE_DEBUG_FREE 1 */
static gboolean ep_debug_use_chunks;
static gboolean se_debug_use_chunks;
/* Do we want to use canaries ? */
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
#define DEBUG_USE_CANARIES 1
#endif
/* Do we want to use canaries?
* Export the following environment variables to disable canaries
*
* WIRESHARK_DEBUG_EP_NO_CANARY
* WIRESHARK_DEBUG_SE_NO_CANARY
*/
static gboolean ep_debug_use_canary;
static gboolean se_debug_use_canary;
/* Do we want to use guardpages? if available */
#define WANT_GUARD_PAGES 1
@ -99,29 +105,27 @@ static int dev_zero_fd;
/* The maximum number of allocations per chunk */
#define EMEM_ALLOCS_PER_CHUNK (EMEM_PACKET_CHUNK_SIZE / 512)
#ifdef DEBUG_USE_CANARIES
#define EMEM_CANARY_SIZE 8
#define EMEM_CANARY_DATA_SIZE (EMEM_CANARY_SIZE * 2 - 1)
/* this should be static, but if it were gdb would had problems finding it */
guint8 ep_canary[EMEM_CANARY_DATA_SIZE], se_canary[EMEM_CANARY_DATA_SIZE];
#endif /* DEBUG_USE_CANARIES */
guint8 ep_canary[EMEM_CANARY_DATA_SIZE];
guint8 se_canary[EMEM_CANARY_DATA_SIZE];
typedef struct _emem_no_chunk_t {
unsigned int c_count;
void *canary[EMEM_ALLOCS_PER_CHUNK];
guint8 cmp_len[EMEM_ALLOCS_PER_CHUNK];
} emem_canary_t;
typedef struct _emem_chunk_t {
struct _emem_chunk_t *next;
char *buf;
unsigned int amount_free_init;
unsigned int amount_free;
unsigned int free_offset_init;
unsigned int free_offset;
char *buf;
#ifdef DEBUG_USE_CANARIES
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
unsigned int c_count;
void *canary[EMEM_ALLOCS_PER_CHUNK];
guint8 cmp_len[EMEM_ALLOCS_PER_CHUNK];
#endif
#endif /* DEBUG_USE_CANARIES */
emem_canary_t *canary_info;
} emem_chunk_t;
typedef struct _emem_header_t {
@ -132,7 +136,6 @@ typedef struct _emem_header_t {
static emem_header_t ep_packet_mem;
static emem_header_t se_packet_mem;
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
#if defined (_WIN32)
static SYSTEM_INFO sysinfo;
static OSVERSIONINFO versinfo;
@ -140,9 +143,7 @@ static int pagesize;
#elif defined(USE_GUARD_PAGES)
static intptr_t pagesize;
#endif /* _WIN32 / USE_GUARD_PAGES */
#endif /* ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE) */
#ifdef DEBUG_USE_CANARIES
/*
* Set a canary value to be placed between memchunks.
*/
@ -174,7 +175,6 @@ emem_canary_pad (size_t allocation) {
return pad;
}
#endif /* DEBUG_USE_CANARIES */
/* used for debugging canaries, will block */
#ifdef DEBUG_INTENSE_CANARY_CHECKS
@ -204,12 +204,12 @@ void ep_check_canary_integrity(const char* fmt, ...) {
for (npc = ep_packet_mem.free_list; npc != NULL; npc = npc->next) {
static unsigned i_ctr;
if (npc->c_count > 0x00ffffff) {
if (npc->canary_info->c_count > 0x00ffffff) {
g_error("ep_packet_mem.free_list was corrupted\nbetween: %s\nand: %s",there, here);
}
for (i_ctr = 0; i_ctr < npc->c_count; i_ctr++) {
if (memcmp(npc->canary[i_ctr], &ep_canary, npc->cmp_len[i_ctr]) != 0) {
for (i_ctr = 0; i_ctr < npc->canary_info->c_count; i_ctr++) {
if (memcmp(npc->canary_info->canary[i_ctr], &ep_canary, npc->canary_info->cmp_len[i_ctr]) != 0) {
g_error("Per-packet memory corrupted\nbetween: %s\nand: %s",there, here);
}
}
@ -231,15 +231,16 @@ ep_init_chunk(void)
ep_packet_mem.free_list=NULL;
ep_packet_mem.used_list=NULL;
ep_debug_use_chunks = (gboolean) (!getenv("WIRESHARK_DEBUG_EP_NO_CHUNKS"));
ep_debug_use_canary = (gboolean) (!getenv("WIRESHARK_DEBUG_EP_NO_CANARY"));
#ifdef DEBUG_INTENSE_CANARY_CHECKS
intense_canary_checking = (gboolean)getenv("WIRESHARK_DEBUG_EP_CANARY");
intense_canary_checking = (gboolean)getenv("WIRESHARK_DEBUG_EP_INTENSE_CANARY");
#endif
#ifdef DEBUG_USE_CANARIES
emem_canary(ep_canary);
#endif /* DEBUG_USE_CANARIES */
if (ep_debug_use_canary)
emem_canary(ep_canary);
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
#if defined (_WIN32)
/* Set up our guard page info for Win32 */
GetSystemInfo(&sysinfo);
@ -263,10 +264,8 @@ ep_init_chunk(void)
g_assert(dev_zero_fd != -1);
#endif
#endif /* _WIN32 / USE_GUARD_PAGES */
#endif /* ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE) */
}
/* Initialize the capture-lifetime memory allocation pool.
* This function should be called only once when Wireshark or TShark starts
* up.
@ -277,14 +276,15 @@ se_init_chunk(void)
se_packet_mem.free_list=NULL;
se_packet_mem.used_list=NULL;
#ifdef DEBUG_USE_CANARIES
emem_canary(se_canary);
#endif /* DEBUG_USE_CANARIES */
se_debug_use_chunks = (gboolean) (!getenv("WIRESHARK_DEBUG_SE_NO_CHUNKS"));
se_debug_use_canary = (gboolean) (!getenv("WIRESHARK_DEBUG_SE_NO_CANARY"));
if (se_debug_use_canary)
emem_canary(se_canary);
}
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
static void
emem_create_chunk(emem_chunk_t **free_list) {
emem_create_chunk(emem_chunk_t **free_list, gboolean use_canary) {
#if defined (_WIN32)
BOOL ret;
char *buf_end, *prot1, *prot2;
@ -298,11 +298,12 @@ emem_create_chunk(emem_chunk_t **free_list) {
emem_chunk_t *npc;
npc = g_malloc(sizeof(emem_chunk_t));
npc->next = NULL;
#ifdef DEBUG_USE_CANARIES
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
npc->c_count = 0;
#endif
#endif /* DEBUG_USE_CANARIES */
if (use_canary) {
npc->canary_info = g_new(emem_canary_t, 1);
npc->canary_info->c_count = 0;
}
else
npc->canary_info = NULL;
*free_list = npc;
#if defined (_WIN32)
@ -367,42 +368,39 @@ emem_create_chunk(emem_chunk_t **free_list) {
#endif /* USE_GUARD_PAGES */
}
}
#endif
/* allocate 'size' amount of memory. */
static void *
emem_alloc(size_t size, gboolean debug_free, emem_header_t *mem, guint8 *canary)
emem_alloc(size_t size, emem_header_t *mem, gboolean use_chunks, guint8 *canary)
{
void *buf;
#ifdef DEBUG_USE_CANARIES
void *cptr;
guint8 pad = emem_canary_pad(size);
#else
static guint8 pad = 8;
#endif /* DEBUG_USE_CANARIES */
guint8 pad;
emem_chunk_t *free_list;
if (!debug_free) {
/* Round up to an 8 byte boundary. Make sure we have at least
if (use_chunks) {
gboolean use_canary = canary != NULL;
/* Round up to an 8 byte boundary. Make sure we have at least
* 8 pad bytes for our canary.
*/
if (use_canary)
pad = emem_canary_pad(size);
else
pad = 8;
size += pad;
/* make sure we dont try to allocate too much (arbitrary limit) */
DISSECTOR_ASSERT(size<(EMEM_PACKET_CHUNK_SIZE>>2));
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
emem_create_chunk(&mem->free_list);
#endif
emem_create_chunk(&mem->free_list, use_canary);
/* 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>mem->free_list->amount_free
#ifdef DEBUG_USE_CANARIES
|| mem->free_list->c_count >= EMEM_ALLOCS_PER_CHUNK
#endif /* DEBUG_USE_CANARIES */
) {
if(size>mem->free_list->amount_free ||
(use_canary &&
mem->free_list->canary_info->c_count >= EMEM_ALLOCS_PER_CHUNK)) {
emem_chunk_t *npc;
npc=mem->free_list;
mem->free_list=mem->free_list->next;
@ -410,9 +408,7 @@ emem_alloc(size_t size, gboolean debug_free, emem_header_t *mem, guint8 *canary)
mem->used_list=npc;
}
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
emem_create_chunk(&mem->free_list);
#endif
emem_create_chunk(&mem->free_list, use_canary);
free_list = mem->free_list;
@ -421,21 +417,20 @@ emem_alloc(size_t size, gboolean debug_free, emem_header_t *mem, guint8 *canary)
free_list->amount_free -= (unsigned int) size;
free_list->free_offset += (unsigned int) size;
#ifdef DEBUG_USE_CANARIES
cptr = (char *)buf + size - pad;
memcpy(cptr, canary, pad);
free_list->canary[free_list->c_count] = cptr;
free_list->cmp_len[free_list->c_count] = pad;
free_list->c_count++;
#endif /* DEBUG_USE_CANARIES */
if (use_canary) {
cptr = (char *)buf + size - pad;
memcpy(cptr, canary, pad);
free_list->canary_info->canary[free_list->canary_info->c_count] = cptr;
free_list->canary_info->cmp_len[free_list->canary_info->c_count] = pad;
free_list->canary_info->c_count++;
}
} else {
emem_chunk_t *npc;
npc=g_malloc(sizeof(emem_chunk_t));
npc->next=mem->used_list;
npc->amount_free=(unsigned int) size;
npc->free_offset=0;
npc->buf=g_malloc(size);
npc->canary_info = NULL;
buf = npc->buf;
mem->used_list=npc;
}
@ -449,11 +444,13 @@ emem_alloc(size_t size, gboolean debug_free, emem_header_t *mem, guint8 *canary)
void *
ep_alloc(size_t size)
{
#ifdef EP_DEBUG_FREE
return emem_alloc(size, TRUE, &ep_packet_mem, NULL);
#else
return emem_alloc(size, FALSE, &ep_packet_mem, ep_canary);
#endif
if (ep_debug_use_chunks)
if (ep_debug_use_canary)
return emem_alloc(size, &ep_packet_mem, TRUE, ep_canary);
else
return emem_alloc(size, &ep_packet_mem, TRUE, NULL);
else
return emem_alloc(size, &ep_packet_mem, FALSE, NULL);
}
/* allocate 'size' amount of memory with an allocation lifetime until the
@ -462,11 +459,13 @@ ep_alloc(size_t size)
void *
se_alloc(size_t size)
{
#ifdef SE_DEBUG_FREE
return emem_alloc(size, TRUE, &se_packet_mem, NULL);
#else
return emem_alloc(size, FALSE, &se_packet_mem, se_canary);
#endif
if (se_debug_use_chunks)
if (se_debug_use_canary)
return emem_alloc(size, &se_packet_mem, TRUE, se_canary);
else
return emem_alloc(size, &se_packet_mem, TRUE, NULL);
else
return emem_alloc(size, &se_packet_mem, FALSE, NULL);
}
void* ep_alloc0(size_t size) {
@ -670,13 +669,11 @@ gchar* se_strdup_printf(const gchar* fmt, ...) {
/* release all allocated memory back to the pool. */
static void
emem_free_all(gboolean debug_free, emem_header_t *mem, guint8 *canary, emem_tree_t *trees)
emem_free_all(emem_header_t *mem, gboolean use_chunks, guint8 *canary, emem_tree_t *trees)
{
emem_chunk_t *npc;
emem_tree_t *tree_list;
#ifdef DEBUG_USE_CANARIES
guint i;
#endif /* DEBUG_USE_CANARIES */
/* move all used chunks over to the free list */
while(mem->used_list){
@ -689,14 +686,14 @@ emem_free_all(gboolean debug_free, emem_header_t *mem, guint8 *canary, emem_tree
/* clear them all out */
npc = mem->free_list;
while (npc != NULL) {
if (!debug_free) {
#ifdef DEBUG_USE_CANARIES
for (i = 0; i < npc->c_count; i++) {
if (memcmp(npc->canary[i], canary, npc->cmp_len[i]) != 0)
g_error("Memory corrupted");
if (use_chunks) {
if (canary) {
for (i = 0; i < npc->canary_info->c_count; i++) {
if (memcmp(npc->canary_info->canary[i], canary, npc->canary_info->cmp_len[i]) != 0)
g_error("Memory corrupted");
}
npc->canary_info->c_count = 0;
}
npc->c_count = 0;
#endif /* DEBUG_USE_CANARIES */
npc->amount_free = npc->amount_free_init;
npc->free_offset = npc->free_offset_init;
npc = npc->next;
@ -719,30 +716,32 @@ emem_free_all(gboolean debug_free, emem_header_t *mem, guint8 *canary, emem_tree
void
ep_free_all(void)
{
#ifdef EP_DEBUG_FREE
emem_free_all(TRUE, &ep_packet_mem, NULL, NULL);
#else
emem_free_all(FALSE, &ep_packet_mem, ep_canary, NULL);
#endif
if (ep_debug_use_chunks)
if (ep_debug_use_canary)
emem_free_all(&ep_packet_mem, TRUE, ep_canary, NULL /* trees */);
else
emem_free_all(&ep_packet_mem, TRUE, NULL, NULL /* trees */);
else
emem_free_all(&ep_packet_mem, FALSE, NULL, NULL /* trees */);
#ifdef EP_DEBUG_FREE
ep_init_chunk();
#endif
if (!ep_debug_use_chunks)
ep_init_chunk();
}
/* release all allocated memory back to the pool. */
void
se_free_all(void)
{
#ifdef SE_DEBUG_FREE
emem_free_all(TRUE, &se_packet_mem, NULL, se_trees);
#else
emem_free_all(FALSE, &se_packet_mem, se_canary, se_trees);
#endif
if (se_debug_use_chunks)
if (se_debug_use_canary)
emem_free_all(&se_packet_mem, TRUE, se_canary, se_trees);
else
emem_free_all(&se_packet_mem, TRUE, NULL, se_trees);
else
emem_free_all(&se_packet_mem, FALSE, NULL, se_trees);
#ifdef SE_DEBUG_FREE
se_init_chunk();
#endif
if (!se_debug_use_chunks)
se_init_chunk();
}
ep_stack_t ep_stack_new(void) {

View File

@ -474,7 +474,7 @@ emem_strbuf_t *ep_strbuf_truncate(emem_strbuf_t *strbuf, gsize len);
/* #define DEBUG_INTENSE_CANARY_CHECKS */
/* Helper to troubleshoot ep memory corruption
* if compiled and the environment variable WIRESHARK_DEBUG_EP_CANARY exists
* if compiled and the environment variable WIRESHARK_DEBUG_EP_INTENSE_CANARY exists
* it will check the canaries and when found corrupt stop there in the hope
* the corruptor is still there in the stack.
* Some checkpoints are already set in packet.c in strategic points