Index: src/lib/Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/Makefile.am,v
retrieving revision 1.62.2.2
diff -u -r1.62.2.2 Makefile.am
--- src/lib/Makefile.am	16 Aug 2006 15:54:56 -0000	1.62.2.2
+++ src/lib/Makefile.am	4 Nov 2006 18:55:51 -0000
@@ -45,6 +45,7 @@
 	lib-signals.c \
 	md4.c \
 	md5.c \
+	memdebug.c \
 	mempool.c \
 	mempool-alloconly.c \
 	mempool-datastack.c \
@@ -122,6 +123,7 @@
 	macros.h \
 	md4.h \
 	md5.h \
+	memdebug.h \
 	mempool.h \
 	mkdir-parents.h \
 	mmap-util.h \
Index: src/lib/data-stack.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/data-stack.c,v
retrieving revision 1.24.2.2
diff -u -r1.24.2.2 data-stack.c
--- src/lib/data-stack.c	10 Sep 2006 17:59:47 -0000	1.24.2.2
+++ src/lib/data-stack.c	4 Nov 2006 18:55:52 -0000
@@ -3,6 +3,7 @@
 /* @UNSAFE: whole file */
 
 #include "lib.h"
+#include "memdebug.h"
 #include "data-stack.h"
 
 #include <stdlib.h>
@@ -13,6 +14,12 @@
 #  include <gc.h>
 #endif
 
+#ifdef MEMDEBUG
+#  define malloc(size) memdebug_malloc(size)
+#  define calloc(count, size) memdebug_calloc(count, size)
+#  define free(ptr) memdebug_free(ptr)
+#endif
+
 /* Use malloc() and free() for all memory allocations. Useful for debugging
    memory corruption. */
 /* #define DISABLE_DATA_STACK */
Index: src/lib/memdebug.c
===================================================================
RCS file: src/lib/memdebug.c
diff -N src/lib/memdebug.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/lib/memdebug.c	4 Nov 2006 18:55:52 -0000
@@ -0,0 +1,193 @@
+/* Copyright (c) 2005 Timo Sirainen */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "memdebug.h"
+
+#ifdef MEMDEBUG
+#include <stdlib.h>
+#ifdef __sun__
+#  include <ucontext.h>
+#endif
+
+#define FREE_DELAY 3
+#define MAX_STACK_SIZE 1024
+
+struct malloc_block {
+	struct malloc_block *prev, *next;
+	size_t size;
+
+	void **free_stack;
+	time_t free_time;
+	unsigned int checksum;
+
+	unsigned char data[];
+};
+
+static struct timeout *to;
+static struct malloc_block *used_head;
+static struct malloc_block *unused_head, *unused_tail;
+
+void *memdebug_malloc(size_t size)
+{
+	struct malloc_block *block;
+
+	block = calloc(1, sizeof(*block) + size);
+	block->size = size;
+	block->next = used_head;
+	if (used_head != NULL)
+		used_head->prev = block;
+	used_head = block;
+	return block + 1;
+}
+
+void *memdebug_calloc(size_t count, size_t size)
+{
+	struct malloc_block *block;
+
+	i_assert((size_t)-1 / size > count);
+
+	block = calloc(sizeof(*block) + count*size, 1);
+	block->size = count*size;
+	block->next = used_head;
+	if (used_head != NULL)
+		used_head->prev = block;
+	used_head = block;
+	return block + 1;
+}
+
+void *memdebug_realloc(void *ptr, size_t size)
+{
+	struct malloc_block *block = PTR_OFFSET(ptr, -sizeof(*block));
+	void *new_ptr;
+
+	new_ptr = memdebug_malloc(size);
+	if (ptr != NULL) {
+		memcpy(new_ptr, ptr, block->size);
+		memdebug_free(ptr);
+	}
+	return new_ptr;
+}
+
+static void block_check(struct malloc_block *block)
+{
+	unsigned int i, h = 0, g;
+
+	for (i = 0; i < block->size; i++) {
+		h = (h << 4) + block->data[i];
+		if ((g = h & 0xf0000000UL)) {
+			h = h ^ (g >> 24);
+			h = h ^ g;
+		}
+	}
+
+	if (block->checksum != h) {
+		if (block->free_stack != NULL) {
+			i_error("Memory corruption, free() backtrace:");
+			for (i = 0; block->free_stack[i] != NULL; i++) {
+				i_error("%p[%u]: %p", (void *)(block + 1), i,
+					block->free_stack[i]);
+			}
+		}
+		i_panic("memory corruption");
+	}
+}
+
+static void memdebug_timeout(void *context __attr_unused__)
+{
+	time_t delete_time = ioloop_time - FREE_DELAY;
+
+	while (unused_head != NULL && unused_head->free_time <= delete_time) {
+		struct malloc_block *block = unused_head;
+
+		block_check(block);
+
+		unused_head = block->next;
+		if (unused_head == NULL)
+			unused_tail = NULL;
+		else
+			unused_head->prev = NULL;
+		free(block->free_stack);
+		free(block);
+	}
+}
+
+#ifdef __sun__
+struct walk_stack {
+	void *stack[MAX_STACK_SIZE+1];
+	unsigned int pos;
+};
+
+static int walk_callback(uintptr_t ptr, int signo __attr_unused__,
+			 void *context)
+{
+	struct walk_stack *stack = context;
+
+	if (stack->pos < MAX_STACK_SIZE)
+		stack->stack[stack->pos++] = (void *)ptr;
+	return 0;
+}
+#endif
+
+void memdebug_free(void *ptr)
+{
+	struct malloc_block *block;
+	size_t i;
+	unsigned int g, h;
+#ifdef __sun__
+	ucontext_t uc;
+	struct walk_stack stack;
+#endif
+
+	if (ptr == NULL)
+		return;
+	block = PTR_OFFSET(ptr, -sizeof(*block));
+
+#ifdef __sun__
+	if (getcontext(&uc) == 0) {
+		stack.pos = 0;
+		walkcontext(&uc, walk_callback, &stack);
+		stack.stack[stack.pos++] = NULL;
+		block->free_stack = malloc(sizeof(void *) * stack.pos);
+		memcpy(block->free_stack, stack.stack,
+		       sizeof(void *) * stack.pos);
+	}
+#endif
+
+	/* remove from used list */
+	if (block->prev == NULL)
+		used_head = block->next;
+	else
+		block->prev->next = block->next;
+
+	if (block->next != NULL)
+		block->next->prev = block->prev;
+
+	/* add to unused list */
+	block->prev = unused_tail;
+	block->next = NULL;
+
+	if (unused_tail != NULL)
+		unused_tail->next = block;
+	else
+		unused_head = block;
+	unused_tail = block;
+
+	/* fill the memory area with random data and calculate its checksum */
+	h = 0;
+	for (i = 0; i < block->size; i++) {
+		block->data[i] = rand();
+
+		h = (h << 4) + block->data[i];
+		if ((g = h & 0xf0000000UL)) {
+			h = h ^ (g >> 24);
+			h = h ^ g;
+		}
+	}
+	block->checksum = h;
+
+	block->free_time = ioloop_time;
+	if (to == NULL && current_ioloop != NULL)
+		to = timeout_add(1000, memdebug_timeout, NULL);
+}
+#endif
Index: src/lib/memdebug.h
===================================================================
RCS file: src/lib/memdebug.h
diff -N src/lib/memdebug.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/lib/memdebug.h	4 Nov 2006 18:55:52 -0000
@@ -0,0 +1,11 @@
+#ifndef __MEMDEBUG_H
+#define __MEMDEBUG_H
+
+#define MEMDEBUG
+
+void *memdebug_malloc(size_t size);
+void *memdebug_calloc(size_t count, size_t size);
+void *memdebug_realloc(void *ptr, size_t size);
+void memdebug_free(void *ptr);
+
+#endif
Index: src/lib/mempool-alloconly.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/mempool-alloconly.c,v
retrieving revision 1.35.2.3
diff -u -r1.35.2.3 mempool-alloconly.c
--- src/lib/mempool-alloconly.c	10 Sep 2006 17:49:06 -0000	1.35.2.3
+++ src/lib/mempool-alloconly.c	4 Nov 2006 18:55:52 -0000
@@ -2,6 +2,7 @@
 
 /* @UNSAFE: whole file */
 #include "lib.h"
+#include "memdebug.h"
 #include "mempool.h"
 
 #include <stdlib.h>
@@ -12,6 +13,11 @@
 #  include <gc.h>
 #endif
 
+#ifdef MEMDEBUG
+#  define calloc(count, size) memdebug_calloc(count, size)
+#  define free(ptr) memdebug_free(ptr)
+#endif
+
 #define MAX_ALLOC_SIZE SSIZE_T_MAX
 
 struct alloconly_pool {
Index: src/lib/mempool-system.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/mempool-system.c,v
retrieving revision 1.18.2.1
diff -u -r1.18.2.1 mempool-system.c
--- src/lib/mempool-system.c	10 Sep 2006 17:49:06 -0000	1.18.2.1
+++ src/lib/mempool-system.c	4 Nov 2006 18:55:52 -0000
@@ -3,6 +3,7 @@
 /* @UNSAFE: whole file */
 
 #include "lib.h"
+#include "memdebug.h"
 #include "mempool.h"
 
 #include <stdlib.h>
@@ -13,6 +14,13 @@
 #  include <gc.h>
 #endif
 
+#ifdef MEMDEBUG
+#  define malloc(size) memdebug_malloc(size)
+#  define calloc(count, size) memdebug_calloc(count, size)
+#  define realloc(ptr, size) memdebug_realloc(ptr, size)
+#  define free(ptr) memdebug_free(ptr)
+#endif
+
 static const char *pool_system_get_name(pool_t pool);
 static void pool_system_ref(pool_t pool);
 static void pool_system_unref(pool_t *pool);
