summaryrefslogtreecommitdiff
path: root/pjlib
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-06-01 07:26:21 +0000
committerBenny Prijono <bennylp@teluu.com>2007-06-01 07:26:21 +0000
commit411ab3b5701824a5e2806117049952f5ad2654aa (patch)
tree490a69dafe78baf27a8878a4a986d95804298f05 /pjlib
parent01ab9abb169648315c02118e3b6cc3747f639e2e (diff)
Implement ticket #314: Added PJ_SAFE_POOL configuration in PJLIB to track down memory corruptions
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1333 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjlib')
-rw-r--r--pjlib/include/pj/config.h16
-rw-r--r--pjlib/src/pj/pool_caching.c12
-rw-r--r--pjlib/src/pj/pool_policy_malloc.c17
-rw-r--r--pjlib/src/pj/pool_policy_new.cpp24
-rw-r--r--pjlib/src/pj/pool_signature.h67
5 files changed, 134 insertions, 2 deletions
diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
index c999bb87..cbdc0aa4 100644
--- a/pjlib/include/pj/config.h
+++ b/pjlib/include/pj/config.h
@@ -388,6 +388,22 @@
/**
+ * Set this flag to non-zero to enable various checking for pool
+ * operations. When this flag is set, assertion must be enabled
+ * in the application.
+ *
+ * This will slow down pool creation and destruction and will add
+ * few bytes of overhead, so application would normally want to
+ * disable this feature on release build.
+ *
+ * Default: 0
+ */
+#ifndef PJ_SAFE_POOL
+# define PJ_SAFE_POOL 0
+#endif
+
+
+/**
* If pool debugging is used, then each memory allocation from the pool
* will call malloc(), and pool will release all memory chunks when it
* is destroyed. This works better when memory verification programs
diff --git a/pjlib/src/pj/pool_caching.c b/pjlib/src/pj/pool_caching.c
index b00bf108..01c303d6 100644
--- a/pjlib/src/pj/pool_caching.c
+++ b/pjlib/src/pj/pool_caching.c
@@ -99,6 +99,8 @@ PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )
while (pool != (pj_pool_t*) &cp->used_list) {
pj_pool_t *next = pool->next;
pj_list_erase(pool);
+ PJ_LOG(4,(pool->obj_name,
+ "Pool is not released by application, releasing now"));
pj_pool_destroy_int(pool);
pool = next;
}
@@ -197,8 +199,18 @@ static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
PJ_CHECK_STACK();
+ PJ_ASSERT_ON_FAIL(pf && pool, return);
+
pj_lock_acquire(cp->lock);
+#if PJ_SAFE_POOL
+ /* Make sure pool is still in our used list */
+ if (pj_list_find_node(&cp->used_list, pool) != pool) {
+ pj_assert(!"Attempt to destroy pool that has been destroyed before");
+ return;
+ }
+#endif
+
/* Erase from the used list. */
pj_list_erase(pool);
diff --git a/pjlib/src/pj/pool_policy_malloc.c b/pjlib/src/pj/pool_policy_malloc.c
index d3f282da..d7e8ad1f 100644
--- a/pjlib/src/pj/pool_policy_malloc.c
+++ b/pjlib/src/pj/pool_policy_malloc.c
@@ -26,6 +26,7 @@
/*
* This file contains pool default policy definition and implementation.
*/
+#include "pool_signature.h"
static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
@@ -41,11 +42,16 @@ static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
return NULL;
}
- p = malloc(size);
+ p = malloc(size+(SIG_SIZE << 1));
if (p == NULL) {
if (factory->on_block_free)
factory->on_block_free(factory, size);
+ } else {
+ /* Apply signature when PJ_SAFE_POOL is set. It will move
+ * "p" pointer forward.
+ */
+ APPLY_SIG(p, size);
}
return p;
@@ -59,6 +65,15 @@ static void default_block_free(pj_pool_factory *factory, void *mem,
if (factory->on_block_free)
factory->on_block_free(factory, size);
+ /* Check and remove signature when PJ_SAFE_POOL is set. It will
+ * move "mem" pointer backward.
+ */
+ REMOVE_SIG(mem, size);
+
+ /* Note that when PJ_SAFE_POOL is set, the actual size of the block
+ * is size + SIG_SIZE*2.
+ */
+
free(mem);
}
diff --git a/pjlib/src/pj/pool_policy_new.cpp b/pjlib/src/pj/pool_policy_new.cpp
index 367be0f3..82374adc 100644
--- a/pjlib/src/pj/pool_policy_new.cpp
+++ b/pjlib/src/pj/pool_policy_new.cpp
@@ -25,15 +25,28 @@
/*
* This file contains pool default policy definition and implementation.
*/
+#include "pool_signature.h"
static void *operator_new(pj_pool_factory *factory, pj_size_t size)
{
+ void *mem;
+
PJ_CHECK_STACK();
PJ_UNUSED_ARG(factory);
PJ_UNUSED_ARG(size);
- return new char[size];
+ mem = (void*) new char[size+(SIG_SIZE << 1)];
+
+ /* Exception for new operator may be disabled, so.. */
+ if (mem) {
+ /* Apply signature when PJ_SAFE_POOL is set. It will move
+ * "mem" pointer forward.
+ */
+ APPLY_SIG(mem, size);
+ }
+
+ return mem;
}
static void operator_delete(pj_pool_factory *factory, void *mem, pj_size_t size)
@@ -42,6 +55,15 @@ static void operator_delete(pj_pool_factory *factory, void *mem, pj_size_t size)
PJ_UNUSED_ARG(factory);
PJ_UNUSED_ARG(size);
+ /* Check and remove signature when PJ_SAFE_POOL is set. It will
+ * move "mem" pointer backward.
+ */
+ REMOVE_SIG(mem, size);
+
+ /* Note that when PJ_SAFE_POOL is set, the actual size of the block
+ * is size + SIG_SIZE*2.
+ */
+
char *p = (char*)mem;
delete [] p;
}
diff --git a/pjlib/src/pj/pool_signature.h b/pjlib/src/pj/pool_signature.h
new file mode 100644
index 00000000..baf4139b
--- /dev/null
+++ b/pjlib/src/pj/pool_signature.h
@@ -0,0 +1,67 @@
+/* $Id$ */
+/*
+ * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/assert.h>
+#include <pj/string.h>
+
+#if PJ_SAFE_POOL
+# define SIG_SIZE sizeof(pj_uint32_t)
+
+static void apply_signature(void *p, pj_size_t size);
+static void check_pool_signature(void *p, pj_size_t size);
+
+# define APPLY_SIG(p,sz) apply_signature(p,sz), \
+ p=(void*)(((char*)p)+SIG_SIZE)
+# define REMOVE_SIG(p,sz) check_pool_signature(p,sz), \
+ p=(void*)(((char*)p)-SIG_SIZE)
+
+# define SIG_BEGIN 0x600DC0DE
+# define SIG_END 0x0BADC0DE
+
+static void apply_signature(void *p, pj_size_t size)
+{
+ pj_uint32_t sig;
+
+ sig = SIG_BEGIN;
+ pj_memcpy(p, &sig, SIG_SIZE);
+
+ sig = SIG_END;
+ pj_memcpy(((char*)p)+SIG_SIZE+size, &sig, SIG_SIZE);
+}
+
+static void check_pool_signature(void *p, pj_size_t size)
+{
+ pj_uint32_t sig;
+ pj_uint8_t *mem = (pj_uint8_t*)p;
+
+ /* Check that signature at the start of the block is still intact */
+ sig = SIG_BEGIN;
+ pj_assert(!pj_memcmp(mem-SIG_SIZE, &sig, SIG_SIZE));
+
+ /* Check that signature at the end of the block is still intact.
+ * Note that "mem" has been incremented by SIG_SIZE
+ */
+ sig = SIG_END;
+ pj_assert(!pj_memcmp(mem+size, &sig, SIG_SIZE));
+}
+
+#else
+# define SIG_SIZE 0
+# define APPLY_SIG(p,sz)
+# define REMOVE_SIG(p,sz)
+#endif