dovecot-2.2: lib: add identifying markers to data-stack frames
dovecot at dovecot.org
dovecot at dovecot.org
Mon Jul 28 13:54:26 UTC 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/6ea0584e3861
changeset: 17635:6ea0584e3861
user: Phil Carmody <phil at dovecot.fi>
date: Mon Jul 28 16:45:33 2014 +0300
description:
lib: add identifying markers to data-stack frames
Add a string parameter to t_push() so that in DEBUG mode,
misbehaviour inside a stack level can be blamed on someone.
Default the T_BEGIN macro to automatigally use __FUNCTION__ or
__FILE__:__LINE__ as that identifier, therefore no clients of
those macros need to change.
ioloop used t_push() directly as it wanted customised diagnostic
strings. To preserve this friendliness, also introduce a t_push_named()
which takes a format string with paramters.
Apart from the unused paramter, a non-DEBUG build should see no
changes.
Signed-off-by: Phil Carmody <phil at dovecot.fi>
diffstat:
src/lib/data-stack.c | 29 ++++++++++++++++++++++++++---
src/lib/data-stack.h | 22 ++++++++++++++++++----
src/lib/ioloop.c | 6 ++++--
3 files changed, 48 insertions(+), 9 deletions(-)
diffs (137 lines):
diff -r 098725138469 -r 6ea0584e3861 src/lib/data-stack.c
--- a/src/lib/data-stack.c Mon Jul 28 16:40:25 2014 +0300
+++ b/src/lib/data-stack.c Mon Jul 28 16:45:33 2014 +0300
@@ -54,6 +54,9 @@
struct stack_block *block[BLOCK_FRAME_COUNT];
size_t block_space_used[BLOCK_FRAME_COUNT];
size_t last_alloc_size[BLOCK_FRAME_COUNT];
+#ifdef DEBUG
+ const char *marker[BLOCK_FRAME_COUNT];
+#endif
};
unsigned int data_stack_frame = 0;
@@ -112,7 +115,7 @@
}
}
-unsigned int t_push(void)
+unsigned int t_push(const char *marker)
{
struct stack_frame_block *frame_block;
@@ -123,7 +126,7 @@
/* kludgy, but allow this before initialization */
frame_pos = 0;
data_stack_init();
- return t_push();
+ return t_push(marker);
}
frame_pos = 0;
@@ -153,10 +156,30 @@
current_frame_block->block[frame_pos] = current_block;
current_frame_block->block_space_used[frame_pos] = current_block->left;
current_frame_block->last_alloc_size[frame_pos] = 0;
+#ifdef DEBUG
+ current_frame_block->marker[frame_pos] = marker;
+#else
+ (void)marker; /* only used for debugging */
+#endif
return data_stack_frame++;
}
+unsigned int t_push_named(const char *format, ...)
+{
+ unsigned int ret = t_push(NULL);
+#ifdef DEBUG
+ va_list args;
+ va_start(args, format);
+ current_frame_block->marker[frame_pos] = p_strdup_vprintf(unsafe_data_stack_pool, format, args);
+ va_end(args);
+#else
+ (void)format; /* unused in non-DEBUG builds */
+#endif
+
+ return ret;
+}
+
static void free_blocks(struct stack_block *block)
{
struct stack_block *next;
@@ -523,7 +546,7 @@
last_buffer_block = NULL;
last_buffer_size = 0;
- (void)t_push();
+ (void)t_push("data_stack_init");
}
void data_stack_deinit(void)
diff -r 098725138469 -r 6ea0584e3861 src/lib/data-stack.h
--- a/src/lib/data-stack.h Mon Jul 28 16:40:25 2014 +0300
+++ b/src/lib/data-stack.h Mon Jul 28 16:45:33 2014 +0300
@@ -33,21 +33,35 @@
extern unsigned int data_stack_frame;
-/* All t_..() allocations between t_push() and t_pop() are freed after t_pop()
+/* All t_..() allocations between t_push*() and t_pop() are freed after t_pop()
is called. Returns the current stack frame number, which can be used
to detect missing t_pop() calls:
- x = t_push(); .. if (t_pop() != x) abort();
+ x = t_push(__func__); .. if (t_pop() != x) abort();
+
+ In DEBUG mode, t_push_named() makes a temporary allocation for the name,
+ but is safe to call in a loop as it performs the allocation within its own
+ frame. However, you should always prefer to use T_BEGIN { ... } T_END below.
*/
-unsigned int t_push(void) ATTR_HOT;
+unsigned int t_push(const char *marker) ATTR_HOT;
+unsigned int t_push_named(const char *format, ...) ATTR_HOT ATTR_FORMAT(1, 2);
unsigned int t_pop(void) ATTR_HOT;
/* Simplifies the if (t_pop() != x) check by comparing it internally and
panicking if it doesn't match. */
void t_pop_check(unsigned int *id) ATTR_HOT;
/* Usage: T_BEGIN { code } T_END */
+#ifndef DEBUG
#define T_BEGIN \
- STMT_START { unsigned int _data_stack_cur_id = t_push();
+ STMT_START { unsigned int _data_stack_cur_id = t_push(NULL);
+#elif defined (__GNUC__) && !defined (__STRICT_ANSI__)
+#define T_BEGIN \
+ STMT_START { unsigned int _data_stack_cur_id = t_push(__FUNCTION__);
+#else
+#define T_CAT2(a,b) (a ":" #b)
+#define T_BEGIN \
+ STMT_START { unsigned int _data_stack_cur_id = t_push(T_CAT2(__FILE__,__LINE__));
+#endif
#define T_END \
t_pop_check(&_data_stack_cur_id); } STMT_END
diff -r 098725138469 -r 6ea0584e3861 src/lib/ioloop.c
--- a/src/lib/ioloop.c Mon Jul 28 16:40:25 2014 +0300
+++ b/src/lib/ioloop.c Mon Jul 28 16:45:33 2014 +0300
@@ -406,7 +406,8 @@
if (timeout->ctx != NULL)
io_loop_context_activate(timeout->ctx);
- t_id = t_push();
+ t_id = t_push_named("ioloop timeout handler %p",
+ (void *)timeout->callback);
timeout->callback(timeout->context);
if (t_pop() != t_id) {
i_panic("Leaked a t_pop() call in timeout handler %p",
@@ -437,7 +438,8 @@
if (io->ctx != NULL)
io_loop_context_activate(io->ctx);
- t_id = t_push();
+ t_id = t_push_named("ioloop handler %p",
+ (void *)io->callback);
io->callback(io->context);
if (t_pop() != t_id) {
i_panic("Leaked a t_pop() call in I/O handler %p",
More information about the dovecot-cvs
mailing list