data-stack.c revision 32c3ba3ba51c80d3fa2b4e17c34a621a8532cca0
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen/* @UNSAFE: whole file */
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen/* Initial stack size - this should be kept in a size that doesn't exceed
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen in a normal use to avoid extra malloc()ing. */
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen# define CLEAR_CHR 0xD5 /* D5 is mnemonic for "Data 5tack" */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen# define BLOCK_CANARY ((void *)0xBADBADD5BADBADD5) /* contains 'D5' */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen# define BLOCK_CANARY_CHECK(block) i_assert((block)->canary == BLOCK_CANARY)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen# define ALLOC_SIZE(size) (MEM_ALIGN(sizeof(size_t)) + MEM_ALIGN(size + SENTRY_COUNT))
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen# define BLOCK_CANARY_CHECK(block) do { ; } while(0)
859cc94211b759825db5e15b0c88754da902ca14Timo Sirainen /* NULL or a poison value, just in case something accesses
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen the memory in front of an allocated area */
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen /* unsigned char data[]; */
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen#define SIZEOF_MEMBLOCK MEM_ALIGN(sizeof(struct stack_block))
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen/* current_frame_block contains last t_push()ed frames. After that new
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stack_frame_block is created and it's ->prev is set to
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen current_frame_block. */
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen /* Fairly arbitrary profiling data */
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen unsigned long long alloc_bytes[BLOCK_FRAME_COUNT];
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenstatic int frame_pos = BLOCK_FRAME_COUNT-1; /* in current_frame_block */
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainenstatic struct stack_frame_block *current_frame_block;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenstatic struct stack_frame_block *unused_frame_blocks;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenstatic struct stack_block *current_block; /* block now used for allocation */
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenstatic struct stack_block *unused_block; /* largest unused block is kept here */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenstatic union {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenunsigned char *data_stack_after_last_alloc(struct stack_block *block)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return STACK_BLOCK_DATA(block) + (block->size - block->left);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenstatic void data_stack_last_buffer_reset(bool preserve_data ATTR_UNUSED)
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen last_alloc_end = data_stack_after_last_alloc(current_block);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen p = last_alloc_end + MEM_ALIGN(sizeof(size_t)) + last_buffer_size;
597dba3488c648ffb375ee4a552bd52ac4346979Timo Sirainen pend = last_alloc_end + ALLOC_SIZE(last_buffer_size);
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen /* reset t_buffer_get() mark - not really needed but makes it
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen easier to notice if t_malloc()/t_push()/t_pop() is called
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen between t_buffer_get() and t_buffer_alloc().
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen do this before we get to i_panic() to avoid recursive
frame_pos++;
frame_pos = 0;
frame_pos = 0;
#ifndef USE_GC
#ifdef DEBUG
return data_stack_frame++;
#ifdef DEBUG
return ret;
if (clean_after_pop)
#ifndef USE_GC
#ifndef USE_GC
#ifdef DEBUG
static void t_pop_verify(void)
pos = 0;
#ifdef DEBUG
t_pop_verify();
if (clean_after_pop) {
if (frame_pos > 0)
frame_pos--;
return FALSE;
*id = 0;
return TRUE;
#ifndef USE_GC
if (outofmem) {
abort();
#ifdef DEBUG
return block;
void *ret;
#ifdef DEBUG
#ifdef DEBUG
if(permanent) {
#ifdef DEBUG
if (permanent)
#ifdef DEBUG
return ret;
void *mem;
return mem;
unsigned char *after_last_alloc;
#ifdef DEBUG
#ifdef DEBUG
#ifdef DEBUG
return TRUE;
return FALSE;
#ifndef DEBUG
void *ret;
return ret;
void *new_buffer;
return buffer;
return new_buffer;
void t_buffer_alloc_last_full(void)
#ifndef DEBUG
void data_stack_init(void)
if (data_stack_initialized) {
last_buffer_size = 0;
void data_stack_deinit(void)
#ifndef USE_GC