/* close data stack frame opened by master_service_init() */
if ((service->flags & MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME) == 0) {
- if (t_pop() != service->datastack_frame_id)
+ if (!t_pop(&service->datastack_frame_id))
i_panic("Leaked t_pop() call");
}
}
void ATTR_NORETURN
test_exit(int status)
{
+ data_stack_frame_t id = 0;
+
i_free_and_null(expected_error_str);
i_free_and_null(test_prefix);
- (void)t_pop(); /* as we were within a T_BEGIN { tests[i].func(); } T_END */
+ (void)t_pop(&id); /* as we were within a T_BEGIN { tests[i].func(); } T_END */
lib_deinit();
_exit(status);
}
data_stack_frame_t data_stack_frame = 0;
static bool data_stack_initialized = FALSE;
+static data_stack_frame_t root_frame_id;
+
static int frame_pos = BLOCK_FRAME_COUNT-1; /* in current_frame_block */
static struct stack_frame_block *current_frame_block;
static struct stack_frame_block *unused_frame_blocks;
}
#endif
-data_stack_frame_t t_pop(void)
+bool t_pop(data_stack_frame_t *id)
{
struct stack_frame_block *frame_block;
frame_block->prev = unused_frame_blocks;
unused_frame_blocks = frame_block;
}
-
- return --data_stack_frame;
-}
-
-void t_pop_check(data_stack_frame_t *id)
-{
- if (unlikely(t_pop() != *id))
- i_panic("Leaked t_pop() call");
+ if (unlikely(--data_stack_frame != *id))
+ return FALSE;
*id = 0;
+ return TRUE;
}
static struct stack_block *mem_block_alloc(size_t min_size)
last_buffer_block = NULL;
last_buffer_size = 0;
- (void)t_push("data_stack_init");
+ root_frame_id = t_push("data_stack_init");
}
void data_stack_deinit(void)
{
- (void)t_pop();
-
- if (frame_pos != BLOCK_FRAME_COUNT-1)
+ if (!t_pop(&root_frame_id) ||
+ frame_pos != BLOCK_FRAME_COUNT-1)
i_panic("Missing t_pop() call");
#ifndef USE_GC
is called. Returns the current stack frame number, which can be used
to detect missing t_pop() calls:
- x = t_push(__func__); .. 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
*/
data_stack_frame_t t_push(const char *marker) ATTR_HOT;
data_stack_frame_t t_push_named(const char *format, ...) ATTR_HOT ATTR_FORMAT(1, 2);
-data_stack_frame_t 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(data_stack_frame_t *id) ATTR_HOT;
+/* Returns TRUE on success, FALSE if t_pop() call was leaked. The caller
+ should panic. */
+bool t_pop(data_stack_frame_t *id) ATTR_HOT;
/* Usage: T_BEGIN { code } T_END */
#ifndef DEBUG
STMT_START { data_stack_frame_t _data_stack_cur_id = t_push(T_CAT2(__FILE__,__LINE__));
#endif
#define T_END \
- t_pop_check(&_data_stack_cur_id); } STMT_END
+ STMT_START { \
+ if (unlikely(!t_pop(&_data_stack_cur_id))) \
+ i_panic("Leaked t_pop() call"); \
+ } STMT_END; \
+ } STMT_END
/* WARNING: Be careful when using these functions, it's too easy to
accidentally save the returned value somewhere permanently.
t_id = t_push_named("ioloop timeout handler %p",
(void *)timeout->callback);
timeout->callback(timeout->context);
- if (t_pop() != t_id) {
+ if (!t_pop(&t_id)) {
i_panic("Leaked a t_pop() call in timeout handler %p",
(void *)timeout->callback);
}
t_id = t_push_named("ioloop handler %p",
(void *)io->callback);
io->callback(io->context);
- if (t_pop() != t_id) {
+ if (!t_pop(&t_id)) {
i_panic("Leaked a t_pop() call in I/O handler %p",
(void *)io->callback);
}
test_assert_idx(strspn(ps[i], tag) == size - 2, i);
test_assert_idx(ps[i][size-1] == tag[0], i);
}
- test_assert_idx(t_id == t_pop(), depth);
+ test_assert_idx(t_pop(&t_id), depth);
}
static void test_ds_recursive(int count, int depth)
undo_ptr = NULL;
/* t_pop musn't abort, that would cause recursion */
things_are_messed_up = TRUE;
- if (t_id != NONEXISTENT_STACK_FRAME_ID && t_pop() != t_id)
+ if (t_id != NONEXISTENT_STACK_FRAME_ID && !t_pop(&t_id))
return FATAL_TEST_ABORT; /* abort, things are messed up with us */
things_are_messed_up = FALSE;
t_id = NONEXISTENT_STACK_FRAME_ID;
undo_data = *undo_ptr;
*undo_ptr = '*';
/* t_pop will now fail */
- (void)t_pop();
+ (void)t_pop(&t_id);
t_id = NONEXISTENT_STACK_FRAME_ID; /* We're FUBAR, mustn't pop next entry */
return FATAL_TEST_FAILURE;
}
undo_data = *undo_ptr;
*undo_ptr = '*';
/* t_pop will now fail */
- (void)t_pop();
+ (void)t_pop(&t_id);
t_id = NONEXISTENT_STACK_FRAME_ID; /* We're FUBAR, mustn't pop next entry */
return FATAL_TEST_FAILURE;
}