aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2006-01-09 23:11:40 +0000
committerGerald Combs <gerald@wireshark.org>2006-01-09 23:11:40 +0000
commitc919d31d092f2cc82fc325a8f925d719bda61c08 (patch)
tree12260f3a9e721643bba6614c3e10ce1eb3042732 /epan
parentd5649bc2de2d33b7ca404dd70298f0ceb3837ee3 (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.c232
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;