Also rewrote the internals to use SilcTree for tracking allocations for
increased performance when there are tens of thousands of allocations.
Changed AVL tree to not do any allocations in debug version.
AC_DEFINE([SILC_ALIGNMENT], SILC_SIZEOF_VOID_P, [SILC_ALIGNMENT])
])
AC_DEFINE([SILC_ALIGNMENT], SILC_SIZEOF_VOID_P, [SILC_ALIGNMENT])
])
-# Stack trace checking
-__SILC_ENABLE_STACKTRACE=""
-AC_MSG_CHECKING(whether to enable stack tracing)
-AC_ARG_ENABLE(stack-trace,
- [ --enable-stack-trace enable memory stack trace],
+# Memory trace checking
+__SILC_ENABLE_MEMTRACE=""
+AC_MSG_CHECKING(whether to enable memory tracing)
+AC_ARG_ENABLE(mem-trace,
+ [ --enable-mem-trace enable memory tracing],
[
case "${enableval}" in
yes)
AC_MSG_RESULT(yes)
[
case "${enableval}" in
yes)
AC_MSG_RESULT(yes)
- AC_DEFINE([SILC_STACKTRACE], [], [SILC_STACKTRACE])
- __SILC_ENABLE_STACKTRACE="#define __SILC_ENABLE_STACKTRACE 1"
+ AC_DEFINE([SILC_MEMTRACE], [], [SILC_MEMTRACE])
+ __SILC_ENABLE_MEMTRACE="#define __SILC_ENABLE_MEMTRACE 1"
CFLAGS="$CFLAGS -rdynamic"
PC_CFLAGS="$PC_CFLAGS -rdynamic"
;;
CFLAGS="$CFLAGS -rdynamic"
PC_CFLAGS="$PC_CFLAGS -rdynamic"
;;
AC_SUBST(SILC_LIB_INCLUDES)
AC_SUBST(PC_CFLAGS)
AC_SUBST(__SILC_ENABLE_DEBUG)
AC_SUBST(SILC_LIB_INCLUDES)
AC_SUBST(PC_CFLAGS)
AC_SUBST(__SILC_ENABLE_DEBUG)
-AC_SUBST(__SILC_ENABLE_STACKTRACE)
+AC_SUBST(__SILC_ENABLE_MEMTRACE)
AC_SUBST(__SILC_HAVE_PTHREAD)
AC_SUBST(__RUNTIME_PACKAGE_VERSION)
AC_SUBST(__SILC_HAVE_PTHREAD)
AC_SUBST(__RUNTIME_PACKAGE_VERSION)
DIST_SUBDIRS=win32 symbian unix tests
DIST_SUBDIRS=win32 symbian unix tests
-SILC_DIST_SOURCE = stacktrace.c
-SILC_DIST_HEADER = stacktrace.h
+SILC_DIST_SOURCE = memtrace.c
+SILC_DIST_HEADER = memtrace.h
noinst_LTLIBRARIES = libsilcutil.la
noinst_LTLIBRARIES = libsilcutil.la
Author: Pekka Riikonen <priikone@silcnet.org>
Author: Pekka Riikonen <priikone@silcnet.org>
setting this variable the program will show where the memory was
originally allocated and freed.
setting this variable the program will show where the memory was
originally allocated and freed.
+ SILC_MALLOC_NO_ALLOCATED
+
+ When set to value 1, the program will not check if given memory was
+ allocated. This will speed up debugging but will not detect if freeing
+ memory that was never allocated.
+
SILC_MALLOC_DUMP
When set to value 1, in case of fatal error, dumps the memory location,
SILC_MALLOC_DUMP
When set to value 1, in case of fatal error, dumps the memory location,
#include <execinfo.h>
#include <signal.h>
#include <malloc.h>
#include <sys/mman.h>
#include <execinfo.h>
#include <signal.h>
#include <malloc.h>
#include <sys/mman.h>
-static void *st_blocks = NULL;
-static unsigned long st_blocks_count = 0;
+static SilcTree st_blocks;
static unsigned long st_num_malloc = 0;
static SilcBool dump = FALSE;
static SilcBool no_free = FALSE;
static SilcBool dump_mem = FALSE;
static unsigned long st_num_malloc = 0;
static SilcBool dump = FALSE;
static SilcBool no_free = FALSE;
static SilcBool dump_mem = FALSE;
+static SilcBool no_allocated = FALSE;
static SilcUInt32 pg = 0;
static SilcMutex lock = NULL;
static SilcUInt32 pg = 0;
static SilcMutex lock = NULL;
/* Memory block with stack trace */
typedef struct SilcStBlockStruct {
/* Memory block with stack trace */
typedef struct SilcStBlockStruct {
- struct SilcStBlockStruct *next;
- struct SilcStBlockStruct *prev;
void *stack[SILC_ST_DEPTH]; /* Stack trace */
const char *file; /* Allocation file in program */
const char *free_file; /* Free file in program */
void *stack[SILC_ST_DEPTH]; /* Stack trace */
const char *file; /* Allocation file in program */
const char *free_file; /* Free file in program */
((SilcStBlock)(((unsigned char *)p) + (SILC_ST_GET_SIZE_ALIGN(size, pg) - \
SILC_ST_GET_SIZE(size)) + 4))
((SilcStBlock)(((unsigned char *)p) + (SILC_ST_GET_SIZE_ALIGN(size, pg) - \
SILC_ST_GET_SIZE(size)) + 4))
+SilcCompareValue silc_st_compare(void *val1, void *val2, void *context)
+{
+ if (SILC_PTR_TO_32(val1) > SILC_PTR_TO_32(val2))
+ return SILC_COMPARE_GREATER_THAN;
+ if (SILC_PTR_TO_32(val1) < SILC_PTR_TO_32(val2))
+ return SILC_COMPARE_LESS_THAN;
+ return SILC_COMPARE_EQUAL_TO;
+}
+
void silc_st_abort(SilcStBlock stack, const char *file, int line,
char *fmt, ...)
{
void silc_st_abort(SilcStBlock stack, const char *file, int line,
char *fmt, ...)
{
"SILC_MALLOC: access violation (overflow)\n");
}
"SILC_MALLOC: access violation (overflow)\n");
}
-void silc_st_stacktrace_init(void)
+void silc_st_memtrace_init(void)
+ silc_tree_init(st_blocks, SILC_TREE_AVL, silc_st_compare, NULL,
+ silc_offsetof(struct SilcStBlockStruct, h), FALSE);
+
atexit(silc_st_dump);
dump = TRUE;
atexit(silc_st_dump);
dump = TRUE;
if (var && *var == '1')
no_free = TRUE;
if (var && *var == '1')
no_free = TRUE;
+ var = silc_getenv("SILC_MALLOC_NO_ALLOCATED");
+ if (var && *var == '1')
+ no_allocated = TRUE;
+
var = silc_getenv("SILC_MALLOC_DUMP");
if (var && *var == '1')
dump_mem = TRUE;
var = silc_getenv("SILC_MALLOC_DUMP");
if (var && *var == '1')
dump_mem = TRUE;
SilcStBlock stack;
if (silc_unlikely(!dump))
SilcStBlock stack;
if (silc_unlikely(!dump))
- silc_st_stacktrace_init();
+ silc_st_memtrace_init();
if (pg) {
unsigned char *ptr;
if (pg) {
unsigned char *ptr;
/* Protect the page */
if (mprotect(stack, pg, PROT_NONE))
silc_st_abort(NULL, file, line, "SILC_MALLOC: mprotect() error: %s\n",
/* Protect the page */
if (mprotect(stack, pg, PROT_NONE))
silc_st_abort(NULL, file, line, "SILC_MALLOC: mprotect() error: %s\n",
- errno == ENOMEM ? "Cannot allocate memory. \nYour program "
- "leaks memory, allocates too much or system \n"
- "is out of memory. The SILC_MALLOC_PROTECT cannot "
- "be used." : strerror(errno));
+ errno == ENOMEM ? "Cannot allocate memory. \nOn Linux, try"
+ " giving 'echo 1000000 >/proc/sys/vm/max_map_count',\n"
+ "to get rid of the problem" : strerror(errno));
/* Get the accessible page */
stack = SILC_ST_GET_STACK_ALIGN(ptr, size, pg);
/* Get the accessible page */
stack = SILC_ST_GET_STACK_ALIGN(ptr, size, pg);
+ memset(&stack->h, 0, sizeof(stack->h));
stack->dumpped = 0;
stack->file = file;
stack->free_file = NULL;
stack->dumpped = 0;
stack->file = file;
stack->free_file = NULL;
stack->depth = backtrace(stack->stack, SILC_ST_DEPTH);
silc_mutex_lock(lock);
stack->depth = backtrace(stack->stack, SILC_ST_DEPTH);
silc_mutex_lock(lock);
-
- stack->next = st_blocks;
- stack->prev = NULL;
- if (st_blocks)
- ((SilcStBlock)st_blocks)->prev = stack;
- st_blocks = stack;
- st_blocks_count++;
+ silc_tree_add(st_blocks, stack);
silc_mutex_unlock(lock);
if (!pg)
silc_mutex_unlock(lock);
if (!pg)
void silc_st_free(void *ptr, const char *file, int line)
{
void silc_st_free(void *ptr, const char *file, int line)
{
stack = SILC_ST_GET_STACK(ptr);
stack = SILC_ST_GET_STACK(ptr);
- silc_mutex_lock(lock);
-
- /* Check if we have ever made this allocation */
- for (s = st_blocks; s; s = s->next)
- if (s == stack)
- break;
- if (s == NULL)
- silc_st_abort(NULL, file, line,
- "SILC_MALLOC: %p was never allocated\n", stack);
+ /* Check for underflow */
+ if (stack->bound != SILC_ST_TOP_BOUND)
+ silc_st_abort(stack, file, line,
+ "SILC_MALLOC: %p was written out of bounds (underflow)\n",
+ stack);
- /* Check for underflow */
- if (stack->bound != SILC_ST_TOP_BOUND)
- silc_st_abort(stack, file, line,
- "SILC_MALLOC: %p was written out of bounds (underflow)\n",
- stack);
-
/* Check for overflow */
if (*SILC_ST_GET_BOUND(stack, stack->size) != SILC_ST_BOTTOM_BOUND)
silc_st_abort(stack, file, line,
/* Check for overflow */
if (*SILC_ST_GET_BOUND(stack, stack->size) != SILC_ST_BOTTOM_BOUND)
silc_st_abort(stack, file, line,
- if (stack->next)
- stack->next->prev = stack->prev;
- if (stack->prev)
- stack->prev->next = stack->next;
- else
- st_blocks = stack->next;
+ /* Check if we have ever made this allocation */
+ if (!no_allocated && !silc_tree_find(st_blocks, stack))
+ silc_st_abort(NULL, file, line,
+ "SILC_MALLOC: %p was never allocated\n", stack);
+
+ if (!silc_tree_del(st_blocks, stack))
+ silc_st_abort(NULL, file, line,
+ "SILC_MALLOC: %p was never allocated\n", stack);
lock = NULL;
silc_mutex_free(l);
lock = NULL;
silc_mutex_free(l);
- for (stack = st_blocks; stack; stack = stack->next) {
+ for (stack = silc_tree_enumerate(st_blocks, NULL); stack != NULL;
+ stack = silc_tree_enumerate(st_blocks, stack)) {
bytes = blocks = 0;
if (stack->dumpped)
bytes = blocks = 0;
if (stack->dumpped)
- fp = fopen("stacktrace.log", "wb");
+ fp = fopen("memtrace.log", "wb");
syms = backtrace_symbols(stack->stack, stack->depth);
/* Find number of leaks and bytes leaked for this leak */
syms = backtrace_symbols(stack->stack, stack->depth);
/* Find number of leaks and bytes leaked for this leak */
- for (s = stack; s; s = s->next) {
+ for (s = silc_tree_enumerate(st_blocks, NULL); s != NULL;
+ s = silc_tree_enumerate(st_blocks, s)) {
if (s->file == stack->file && s->line == stack->line &&
s->depth == stack->depth &&
!memcmp(s->stack, stack->stack,
if (s->file == stack->file && s->line == stack->line &&
s->depth == stack->depth &&
!memcmp(s->stack, stack->stack,
fprintf(stderr, "\nNo memory leaks\n");
} else {
fprintf(stderr,
fprintf(stderr, "\nNo memory leaks\n");
} else {
fprintf(stderr,
- "-----------------------------------------\n"
- "-----------------------------------------\n"
- " Memory leaks dumped to 'stacktrace.log'\n"
+ "---------------------------------------\n"
+ "---------------------------------------\n"
+ " Memory leaks dumped to 'memtrace.log'\n"
" Leaks: %lu leaks, %lu blocks\n"
" Leaks: %lu leaks, %lu blocks\n"
- "-----------------------------------------\n"
- "-----------------------------------------\n",
- leaks, st_blocks_count);
+ "---------------------------------------\n"
+ "---------------------------------------\n",
+ leaks, (unsigned long)silc_tree_count(st_blocks));
fprintf(stderr, "Number of allocations: %lu\n", st_num_malloc);
}
fprintf(stderr, "Number of allocations: %lu\n", st_num_malloc);
}
-#endif /* SILC_STACKTRACE */
+#endif /* SILC_MEMTRACE */
Author: Pekka Riikonen <priikone@silcnet.org>
Author: Pekka Riikonen <priikone@silcnet.org>
-#ifndef STACKTRACE_H
-#define STACKTRACE_H
+#ifndef MEMTRACE_H
+#define MEMTRACE_H
#ifndef SILCMEMORY_H
#error "Do not include internal header file directly"
#endif
#if (defined(__GNUC__) && defined(HAVE_EXECINFO_H) && \
#ifndef SILCMEMORY_H
#error "Do not include internal header file directly"
#endif
#if (defined(__GNUC__) && defined(HAVE_EXECINFO_H) && \
- defined(HAVE_BACKTRACE)) || defined(__SILC_ENABLE_STACKTRACE)
+ defined(HAVE_BACKTRACE)) || defined(__SILC_ENABLE_MEMTRACE)
#undef strdup
#define silc_malloc(s) silc_st_malloc((s), __FILE__, __LINE__)
#undef strdup
#define silc_malloc(s) silc_st_malloc((s), __FILE__, __LINE__)
#error "memory allocation stack trace not supported on this platform"
#endif /* __GNUC__ && HAVE_EXECINFO_H && HAVE_BACKTRACE */
#error "memory allocation stack trace not supported on this platform"
#endif /* __GNUC__ && HAVE_EXECINFO_H && HAVE_BACKTRACE */
-#endif /* STACKTRACE_H */
+/* Define to 1 if you want hash table debug enabled */
+#ifndef SILC_AVL_TREE_DEBUG
+#define SILC_AVL_TREE_DEBUG 0
+#endif /* !SILC_AVL_TREE_DEBUG */
+
+#if SILC_ALV_TREE_DEBUG == 1
+#define SILC_TREE_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
+#else
+#define SILC_TREE_DEBUG(fmt)
+#endif
+
/************************ Static utility functions **************************/
/* Rotate left
/************************ Static utility functions **************************/
/* Rotate left
void *cmp_context = compare ? context : tree->context;
int ret;
void *cmp_context = compare ? context : tree->context;
int ret;
- SILC_LOG_DEBUG(("AVL tree %p, find %p", tree, entry));
+ SILC_TREE_DEBUG(("AVL tree %p, find %p", tree, entry));
h = tree->root;
while (h) {
ret = cmp(entry, SILC_TREE_GET_ENTRY(tree, h), cmp_context);
if (ret == SILC_COMPARE_EQUAL_TO) {
h = tree->root;
while (h) {
ret = cmp(entry, SILC_TREE_GET_ENTRY(tree, h), cmp_context);
if (ret == SILC_COMPARE_EQUAL_TO) {
- SILC_LOG_DEBUG(("Found %p", SILC_TREE_GET_ENTRY(tree, h)));
+ SILC_TREE_DEBUG(("Found %p", SILC_TREE_GET_ENTRY(tree, h)));
return SILC_TREE_GET_ENTRY(tree, h);
}
if (ret == SILC_COMPARE_STOP)
return SILC_TREE_GET_ENTRY(tree, h);
}
if (ret == SILC_COMPARE_STOP)
h = ret > 0 ? h->right : h->left;
}
h = ret > 0 ? h->right : h->left;
}
- SILC_LOG_DEBUG(("Not found"));
- silc_set_errno(SILC_ERR_NOT_FOUND);
+ SILC_TREE_DEBUG(("Not found"));
+ silc_set_errno_nofail(SILC_ERR_NOT_FOUND);
SilcTreeHeader *h, *parent = NULL, *q = NULL;
int ret = 0;
SilcTreeHeader *h, *parent = NULL, *q = NULL;
int ret = 0;
- SILC_LOG_DEBUG(("AVL tree %p, adding %p", tree, entry));
+ SILC_TREE_DEBUG(("AVL tree %p, adding %p", tree, entry));
/* If tree is empty, add to root */
if (!tree->root) {
/* If tree is empty, add to root */
if (!tree->root) {
h->t = 0;
tree->root = h;
h->t = 0;
tree->root = h;
- SILC_LOG_DEBUG(("Entry %p added as root", entry));
+ SILC_TREE_DEBUG(("Entry %p added as root", entry));
SILC_ASSERT(!tree->count);
tree->count = 1;
SILC_ASSERT(!tree->count);
tree->count = 1;
while (h) {
/* Same entry context must not be in tree */
if (entry == SILC_TREE_GET_ENTRY(tree, h)) {
while (h) {
/* Same entry context must not be in tree */
if (entry == SILC_TREE_GET_ENTRY(tree, h)) {
- silc_set_errno(SILC_ERR_ALREADY_EXISTS);
+ silc_set_errno_nofail(SILC_ERR_ALREADY_EXISTS);
return FALSE;
}
ret = tree->compare(entry, SILC_TREE_GET_ENTRY(tree, h), tree->context);
if (!tree->duplicates && ret == SILC_COMPARE_EQUAL_TO) {
return FALSE;
}
ret = tree->compare(entry, SILC_TREE_GET_ENTRY(tree, h), tree->context);
if (!tree->duplicates && ret == SILC_COMPARE_EQUAL_TO) {
- silc_set_errno(SILC_ERR_ALREADY_EXISTS);
+ silc_set_errno_nofail(SILC_ERR_ALREADY_EXISTS);
h->dup->parent = q;
q->dup = h->dup;
h->dup = q;
h->dup->parent = q;
q->dup = h->dup;
h->dup = q;
- SILC_LOG_DEBUG(("Entry %p is duplicate to %p", entry,
+ SILC_TREE_DEBUG(("Entry %p is duplicate to %p", entry,
SILC_TREE_GET_ENTRY(tree, h)));
tree->count++;
return TRUE;
SILC_TREE_GET_ENTRY(tree, h)));
tree->count++;
return TRUE;
- SILC_LOG_DEBUG(("Entry %p added, parent %p", entry,
- SILC_TREE_GET_ENTRY(tree, parent)));
+ SILC_TREE_DEBUG(("Entry %p added, parent %p", entry,
+ SILC_TREE_GET_ENTRY(tree, parent)));
/* Update the new entry */
h->parent = parent;
/* Update the new entry */
h->parent = parent;
SilcTreeHeader *h, *q, *out, *parent = NULL, tmp;
int left;
SilcTreeHeader *h, *q, *out, *parent = NULL, tmp;
int left;
- SILC_LOG_DEBUG(("AVL tree %p, delete %p", tree, entry));
+ SILC_TREE_DEBUG(("AVL tree %p, delete %p", tree, entry));
if (!tree->root || !entry) {
if (!tree->root || !entry) {
- silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+ silc_set_errno_nofail(SILC_ERR_INVALID_ARGUMENT);
h->right->parent = h->dup;
/* Cleanup the deleted entry */
h->right->parent = h->dup;
/* Cleanup the deleted entry */
- SILC_LOG_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
+ SILC_TREE_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
h->parent = h->left = h->right = h->dup = NULL;
h->t = 0;
h->parent = h->left = h->right = h->dup = NULL;
h->t = 0;
out->parent = parent;
/* Cleanup the deleted entry */
out->parent = parent;
/* Cleanup the deleted entry */
- SILC_LOG_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
+ SILC_TREE_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
h->parent = h->left = h->right = h->dup = NULL;
h->t = 0;
h->parent = h->left = h->right = h->dup = NULL;
h->t = 0;
#define SILC_MAX_ALLOC (1024 * 1024L * 1024L)
#define SILC_MAX_ALLOC (1024 * 1024L * 1024L)
return silc_memdup(str, strlen(str));
}
return silc_memdup(str, strlen(str));
}
-#endif /* !SILC_STACKTRACE */
+#endif /* !SILC_MEMTRACE */
/* SilcStack aware routines */
/* SilcStack aware routines */
/****f* silcutil/silc_malloc
*
/****f* silcutil/silc_malloc
*
char *silc_strdup(const char *str);
#else
char *silc_strdup(const char *str);
#else
-#include "stacktrace.h"
-#endif /* SILC_STACKTRACE */
+#include "memtrace.h"
+#endif /* SILC_MEMTRACE */
/* Following functions that use SilcStack as memory source. */
/* Following functions that use SilcStack as memory source. */
configured/compiled. */
@__SILC_HAVE_PTHREAD@
@__SILC_ENABLE_DEBUG@
configured/compiled. */
@__SILC_HAVE_PTHREAD@
@__SILC_ENABLE_DEBUG@
-@__SILC_ENABLE_STACKTRACE@
+@__SILC_ENABLE_MEMTRACE@
@__SILC_VA_COPY@
/* Types */
@__SILC_VA_COPY@
/* Types */
#define SILC_DEBUG 1
#endif /* __SILC_ENABLE_DEBUG */
#define SILC_DEBUG 1
#endif /* __SILC_ENABLE_DEBUG */
-#ifdef __SILC_ENABLE_STACKTRACE
-#undef SILC_STACKTRACE
-#define SILC_STACKTRACE 1
-#endif /* __SILC_ENABLE_STACKTRACE */
+#ifdef __SILC_ENABLE_MEMTRACE
+#undef SILC_MEMTRACE
+#define SILC_MEMTRACE 1
+#endif /* __SILC_ENABLE_MEMTRACE */
/* SILC Runtime Toolkit includes */
#include <silctypes.h>
/* SILC Runtime Toolkit includes */
#include <silctypes.h>