data-stack.c revision 10b25ed61cbe92a1435b322a9c2fbda208473018
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen/* @UNSAFE: whole file */
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi/* Initial stack size - this should be kept in a size that doesn't exceed
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen in a normal use to avoid extra malloc()ing. */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen /* unsigned char data[]; */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#define SIZEOF_MEMBLOCK MEM_ALIGN(sizeof(struct stack_block))
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen/* current_frame_block contains last t_push()ed frames. After that new
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen stack_frame_block is created and it's ->prev is set to
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen current_frame_block. */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenunsigned int data_stack_frame = 0;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic int frame_pos = BLOCK_FRAME_COUNT-1; /* in current_frame_block */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic struct stack_frame_block *current_frame_block;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic struct stack_frame_block *unused_frame_blocks;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic struct stack_block *current_block; /* block now used for allocation */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic struct stack_block *unused_block; /* largest unused block is kept here */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic union {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic void data_stack_last_buffer_reset(bool preserve_data ATTR_UNUSED)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen unsigned char *p;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen unsigned int i;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen MEM_ALIGN(sizeof(size_t)) + MEM_ALIGN(last_buffer_size);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen /* reset t_buffer_get() mark - not really needed but makes it
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen easier to notice if t_malloc()/t_push()/t_pop() is called
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen between t_buffer_get() and t_buffer_alloc().
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen do this before we get to i_panic() to avoid recursive
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen for (i = 0; i < SENTRY_COUNT; i++) {
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainenunsigned int t_push(void)
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen /* frame block full */
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen /* kludgy, but allow this before initialization */
009217abb57a24a4076092e8e4e165545747839eStephan Bosch /* allocate new block */
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen frame_block = calloc(sizeof(*frame_block), 1);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen frame_block = GC_malloc(sizeof(*frame_block));
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen "t_push(): Out of memory");
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen /* use existing unused frame_block */
009217abb57a24a4076092e8e4e165545747839eStephan Bosch unused_frame_blocks = unused_frame_blocks->prev;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen /* mark our current position */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen current_frame_block->block[frame_pos] = current_block;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen current_frame_block->block_space_used[frame_pos] = current_block->left;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen current_frame_block->last_alloc_size[frame_pos] = 0;
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainenstatic void free_blocks(struct stack_block *block)
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi /* free all the blocks, except if any of them is bigger than
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi unused_block, replace it */
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi memset(STACK_BLOCK_DATA(block), CLEAR_CHR, block->size);
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi if (unused_block == NULL || block->size > unused_block->size) {
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomistatic void t_pop_verify(void)
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi unsigned char *p;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi pos = block->size - current_frame_block->block_space_used[frame_pos];
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi max_pos = pos + MEM_ALIGN(alloc_size + SENTRY_COUNT);
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi /* if we had used t_buffer_get(), the rest of the buffer
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi may not contain CLEAR_CHRs. but we've already checked all
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi the allocations, so there's no need to check them anyway. */
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomiunsigned int t_pop(void)
#ifdef DEBUG
t_pop_verify();
if (clean_after_pop) {
if (frame_pos > 0)
frame_pos--;
return --data_stack_frame;
*id = 0;
#ifndef USE_GC
if (outofmem) {
abort();
#ifdef DEBUG
return block;
void *ret;
#ifdef DEBUG
#ifndef DEBUG
if (permanent)
#ifdef DEBUG
if (permanent)
#ifdef DEBUG
if (warn) {
#ifdef DEBUG
return ret;
void *mem;
return mem;
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)
#ifdef DEBUG
if (data_stack_frame == 0) {
last_buffer_size = 0;
t_push();
void data_stack_deinit(void)
t_pop();
#ifndef USE_GC