data-stack.c revision 395a730fac26f68dd1e197a168d07edbcb436730
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen/* @UNSAFE: whole file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include "lib.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "data-stack.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include <stdlib.h>
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#ifdef HAVE_GC_GC_H
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen# include <gc/gc.h>
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#elif defined (HAVE_GC_H)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# include <gc.h>
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#endif
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen/* Initial stack size - this should be kept in a size that doesn't exceed
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen in a normal use to avoid extra malloc()ing. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#ifdef DEBUG
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen# define INITIAL_STACK_SIZE (1024*10)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#else
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen# define INITIAL_STACK_SIZE (1024*32)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#endif
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifdef DEBUG
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# define CLEAR_CHR 0xD5 /* D5 is mnemonic for "Data 5tack" */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# define SENTRY_COUNT (4*8)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# define BLOCK_CANARY ((void *)0xBADBADD5BADBADD5) /* contains 'D5' */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# define BLOCK_CANARY_CHECK(block) i_assert((block)->canary == BLOCK_CANARY)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# define ALLOC_SIZE(size) (MEM_ALIGN(sizeof(size_t)) + MEM_ALIGN(size + SENTRY_COUNT))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#else
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# define CLEAR_CHR 0
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# define BLOCK_CANARY NULL
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# define BLOCK_CANARY_CHECK(block) do { ; } while(0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen# define ALLOC_SIZE(size) MEM_ALIGN(size)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#endif
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstruct stack_block {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct stack_block *next;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t size, left, lowwater;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* NULL or a poison value, just in case something accesses
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen the memory in front of an allocated area */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen void *canary;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* unsigned char data[]; */
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen};
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#define SIZEOF_MEMBLOCK MEM_ALIGN(sizeof(struct stack_block))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#define STACK_BLOCK_DATA(block) \
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ((unsigned char *) (block) + SIZEOF_MEMBLOCK)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen/* current_frame_block contains last t_push()ed frames. After that new
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen stack_frame_block is created and it's ->prev is set to
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_frame_block. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#define BLOCK_FRAME_COUNT 32
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct stack_frame_block {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct stack_frame_block *prev;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct stack_block *block[BLOCK_FRAME_COUNT];
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t block_space_used[BLOCK_FRAME_COUNT];
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t last_alloc_size[BLOCK_FRAME_COUNT];
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifdef DEBUG
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *marker[BLOCK_FRAME_COUNT];
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* Fairly arbitrary profiling data */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen unsigned long long alloc_bytes[BLOCK_FRAME_COUNT];
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen unsigned int alloc_count[BLOCK_FRAME_COUNT];
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen#endif
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen};
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenunsigned int data_stack_frame = 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int frame_pos = BLOCK_FRAME_COUNT-1; /* in current_frame_block */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic struct stack_frame_block *current_frame_block;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic struct stack_frame_block *unused_frame_blocks;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic struct stack_block *current_block; /* block now used for allocation */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic struct stack_block *unused_block; /* largest unused block is kept here */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic struct stack_block *last_buffer_block;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic size_t last_buffer_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifdef DEBUG
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic bool clean_after_pop = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#else
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic bool clean_after_pop = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#endif
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic bool outofmem = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic union {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct stack_block block;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned char data[512];
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen} outofmem_area;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic inline
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenunsigned char *data_stack_after_last_alloc(struct stack_block *block)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return STACK_BLOCK_DATA(block) + (block->size - block->left);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic void data_stack_last_buffer_reset(bool preserve_data ATTR_UNUSED)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (last_buffer_block != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifdef DEBUG
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned char *last_alloc_end, *p;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned int i;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen last_alloc_end = data_stack_after_last_alloc(current_block);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen p = last_alloc_end + MEM_ALIGN(sizeof(size_t)) + MEM_ALIGN(last_buffer_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#endif
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* reset t_buffer_get() mark - not really needed but makes it
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen easier to notice if t_malloc()/t_push()/t_pop() is called
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen between t_buffer_get() and t_buffer_alloc().
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen do this before we get to i_panic() to avoid recursive
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen panics. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen last_buffer_block = NULL;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#ifdef DEBUG
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (i = 0; i < SENTRY_COUNT; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (p[i] != CLEAR_CHR)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_panic("t_buffer_get(): buffer overflow");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen if (!preserve_data) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen p = last_alloc_end;
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen memset(p, CLEAR_CHR, SENTRY_COUNT);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen#endif
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenunsigned int t_push(const char *marker)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct stack_frame_block *frame_block;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_pos++;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (frame_pos == BLOCK_FRAME_COUNT) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* frame block full */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (data_stack_frame == 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* kludgy, but allow this before initialization */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_pos = 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen data_stack_init();
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen return t_push(marker);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_pos = 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (unused_frame_blocks == NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* allocate new block */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#ifndef USE_GC
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_block = calloc(sizeof(*frame_block), 1);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#else
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_block = GC_malloc(sizeof(*frame_block));
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#endif
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (frame_block == NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_fatal_status(FATAL_OUTOFMEM,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen "t_push(): Out of memory");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen /* use existing unused frame_block */
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen frame_block = unused_frame_blocks;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen unused_frame_blocks = unused_frame_blocks->prev;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_block->prev = current_frame_block;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_frame_block = frame_block;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen data_stack_last_buffer_reset(FALSE);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* mark our current position */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_frame_block->block[frame_pos] = current_block;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen current_frame_block->block_space_used[frame_pos] = current_block->left;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen current_frame_block->last_alloc_size[frame_pos] = 0;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen#ifdef DEBUG
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_frame_block->marker[frame_pos] = marker;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen current_frame_block->alloc_bytes[frame_pos] = 0ULL;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_frame_block->alloc_count[frame_pos] = 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#else
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen (void)marker; /* only used for debugging */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#endif
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return data_stack_frame++;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenunsigned int t_push_named(const char *format, ...)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen unsigned int ret = t_push(NULL);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen#ifdef DEBUG
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen va_list args;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen va_start(args, format);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_frame_block->marker[frame_pos] = p_strdup_vprintf(unsafe_data_stack_pool, format, args);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen va_end(args);
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen#else
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen (void)format; /* unused in non-DEBUG builds */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#endif
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return ret;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen}
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic void free_blocks(struct stack_block *block)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct stack_block *next;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* free all the blocks, except if any of them is bigger than
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen unused_block, replace it */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen while (block != NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen BLOCK_CANARY_CHECK(block);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen next = block->next;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (clean_after_pop)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen memset(STACK_BLOCK_DATA(block), CLEAR_CHR, block->size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (unused_block == NULL || block->size > unused_block->size) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#ifndef USE_GC
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen free(unused_block);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#endif
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen unused_block = block;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#ifndef USE_GC
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (block != &outofmem_area.block)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen free(block);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#endif
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen }
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen block = next;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen}
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#ifdef DEBUG
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic void t_pop_verify(void)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct stack_block *block;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen unsigned char *p;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen size_t pos, max_pos, used_size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen block = current_frame_block->block[frame_pos];
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen pos = block->size - current_frame_block->block_space_used[frame_pos];
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen while (block != NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen BLOCK_CANARY_CHECK(block);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen used_size = block->size - block->left;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen p = STACK_BLOCK_DATA(block);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen while (pos < used_size) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen size_t requested_size = *(size_t *)(p + pos);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (used_size - pos < requested_size)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_panic("data stack[%s]: saved alloc size broken",
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_frame_block->marker[frame_pos]);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen max_pos = pos + ALLOC_SIZE(requested_size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen pos += MEM_ALIGN(sizeof(size_t)) + requested_size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen for (; pos < max_pos; pos++) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (p[pos] != CLEAR_CHR)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_panic("data stack[%s]: buffer overflow",
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_frame_block->marker[frame_pos]);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* if we had used t_buffer_get(), the rest of the buffer
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen may not contain CLEAR_CHRs. but we've already checked all
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen the allocations, so there's no need to check them anyway. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen block = block->next;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen pos = 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#endif
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenunsigned int t_pop(void)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct stack_frame_block *frame_block;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (unlikely(frame_pos < 0))
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_panic("t_pop() called with empty stack");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen data_stack_last_buffer_reset(FALSE);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#ifdef DEBUG
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen t_pop_verify();
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#endif
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* update the current block */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_block = current_frame_block->block[frame_pos];
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen BLOCK_CANARY_CHECK(current_block);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (clean_after_pop) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen size_t pos, used_size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen pos = current_block->size -
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_frame_block->block_space_used[frame_pos];
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen used_size = current_block->size - current_block->lowwater;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(used_size >= pos);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen memset(STACK_BLOCK_DATA(current_block) + pos, CLEAR_CHR,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen used_size - pos);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_block->left = current_frame_block->block_space_used[frame_pos];
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_block->lowwater = current_block->left;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (current_block->next != NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* free unused blocks */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen free_blocks(current_block->next);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_block->next = NULL;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (frame_pos > 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_pos--;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen else {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* frame block is now unused, add it to unused list */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_pos = BLOCK_FRAME_COUNT-1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_block = current_frame_block;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_frame_block = frame_block->prev;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen frame_block->prev = unused_frame_blocks;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen unused_frame_blocks = frame_block;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return --data_stack_frame;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid t_pop_check(unsigned int *id)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (unlikely(t_pop() != *id))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_panic("Leaked t_pop() call");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *id = 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic struct stack_block *mem_block_alloc(size_t min_size)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct stack_block *block;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t prev_size, alloc_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen prev_size = current_block == NULL ? 0 : current_block->size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen alloc_size = nearest_power(prev_size + min_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifndef USE_GC
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen block = malloc(SIZEOF_MEMBLOCK + alloc_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#else
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen block = GC_malloc(SIZEOF_MEMBLOCK + alloc_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#endif
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (unlikely(block == NULL)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (outofmem) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (min_size > outofmem_area.block.left)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen abort();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return &outofmem_area.block;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen outofmem = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_panic("data stack: Out of memory when allocating %"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen PRIuSIZE_T" bytes", alloc_size + SIZEOF_MEMBLOCK);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen block->size = alloc_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen block->left = 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen block->lowwater = block->size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen block->next = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen block->canary = BLOCK_CANARY;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifdef DEBUG
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen memset(STACK_BLOCK_DATA(block), CLEAR_CHR, alloc_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#endif
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return block;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void *t_malloc_real(size_t size, bool permanent)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen void *ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t alloc_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifdef DEBUG
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen bool warn = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int old_errno = errno;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#endif
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (unlikely(size == 0 || size > SSIZE_T_MAX))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (unlikely(data_stack_frame == 0)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* kludgy, but allow this before initialization */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen data_stack_init();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen BLOCK_CANARY_CHECK(current_block);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* allocate only aligned amount of memory so alignment comes
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen always properly */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen alloc_size = ALLOC_SIZE(size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifdef DEBUG
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if(permanent) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_frame_block->alloc_bytes[frame_pos] += alloc_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_frame_block->alloc_count[frame_pos]++;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#endif
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen data_stack_last_buffer_reset(TRUE);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* used for t_try_realloc() */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_frame_block->last_alloc_size[frame_pos] = alloc_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (current_block->left < alloc_size) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct stack_block *block;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* current block is full, see if we can use the unused_block */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (unused_block != NULL && unused_block->size >= alloc_size) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen block = unused_block;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unused_block = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen block = mem_block_alloc(alloc_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifdef DEBUG
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen warn = TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#endif
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen block->left = block->size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen block->next = NULL;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen current_block->next = block;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen current_block = block;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* enough space in current block, use it */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ret = data_stack_after_last_alloc(current_block);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (current_block->left - alloc_size < current_block->lowwater)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_block->lowwater = current_block->left - alloc_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (permanent)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_block->left -= alloc_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#ifdef DEBUG
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (warn && getenv("DEBUG_SILENT") == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* warn after allocation, so if i_warning() wants to
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen allocate more memory we don't go to infinite loop */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_warning("Growing data stack by %"PRIuSIZE_T" as "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "'%s' reaches %llu bytes from %u allocations.",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_block->size,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_frame_block->marker[frame_pos],
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_frame_block->alloc_bytes[frame_pos],
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_frame_block->alloc_count[frame_pos]);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen memcpy(ret, &size, sizeof(size));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = PTR_OFFSET(ret, MEM_ALIGN(sizeof(size)));
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* make sure the sentry contains CLEAR_CHRs. it might not if we
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen had used t_buffer_get(). */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen memset(PTR_OFFSET(ret, size), CLEAR_CHR,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen MEM_ALIGN(size + SENTRY_COUNT) - size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* we rely on errno not changing. it shouldn't. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(errno == old_errno);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#endif
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid *t_malloc(size_t size)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return t_malloc_real(size, TRUE);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid *t_malloc0(size_t size)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen void *mem;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mem = t_malloc_real(size, TRUE);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen memset(mem, 0, size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return mem;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenbool t_try_realloc(void *mem, size_t size)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen size_t last_alloc_size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned char *after_last_alloc;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (unlikely(size == 0 || size > SSIZE_T_MAX))
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen BLOCK_CANARY_CHECK(current_block);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen last_alloc_size = current_frame_block->last_alloc_size[frame_pos];
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* see if we're trying to grow the memory we allocated last */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen after_last_alloc = data_stack_after_last_alloc(current_block);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (after_last_alloc - last_alloc_size == mem) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* yeah, see if we have space to grow */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size = MEM_ALIGN(size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (current_block->left >= size - last_alloc_size) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* just shrink the available size */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_block->left -= size - last_alloc_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen current_frame_block->last_alloc_size[frame_pos] = size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainensize_t t_get_bytes_available(void)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#ifndef DEBUG
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const unsigned int extra = MEM_ALIGN_SIZE-1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#else
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const unsigned int extra = MEM_ALIGN_SIZE-1 + SENTRY_COUNT +
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen MEM_ALIGN(sizeof(size_t));
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#endif
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen BLOCK_CANARY_CHECK(current_block);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return current_block->left < extra ? current_block->left :
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen current_block->left - extra;
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid *t_buffer_get(size_t size)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen void *ret;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ret = t_malloc_real(size, FALSE);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen last_buffer_size = size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen last_buffer_block = current_block;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return ret;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid *t_buffer_reget(void *buffer, size_t size)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen size_t old_size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen void *new_buffer;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen old_size = last_buffer_size;
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen if (size <= old_size)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return buffer;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen new_buffer = t_buffer_get(size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (new_buffer != buffer)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen memcpy(new_buffer, buffer, old_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return new_buffer;
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen}
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenvoid t_buffer_alloc(size_t size)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen i_assert(last_buffer_block != NULL);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen i_assert(last_buffer_size >= size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(current_block->left >= size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
fb7dd075cf883e5e7defbc0c8fb8326e30bdccdeTimo Sirainen /* we've already reserved the space, now we just mark it used */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen (void)t_malloc_real(size, TRUE);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid t_buffer_alloc_last_full(void)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen if (last_buffer_block != NULL)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen (void)t_malloc_real(last_buffer_size, TRUE);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid data_stack_set_clean_after_pop(bool enable ATTR_UNUSED)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen#ifndef DEBUG
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen clean_after_pop = enable;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen#endif
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainenvoid data_stack_init(void)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (data_stack_frame > 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* already initialized (we did auto-initialization in
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen t_malloc/t_push) */
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen data_stack_frame = 1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen outofmem_area.block.size = outofmem_area.block.left =
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen sizeof(outofmem_area) - sizeof(outofmem_area.block);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen current_block = mem_block_alloc(INITIAL_STACK_SIZE);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen current_block->left = current_block->size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen current_block->next = NULL;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen current_frame_block = NULL;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen unused_frame_blocks = NULL;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen frame_pos = BLOCK_FRAME_COUNT-1;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen last_buffer_block = NULL;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen last_buffer_size = 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen (void)t_push("data_stack_init");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid data_stack_deinit(void)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen (void)t_pop();
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
41955c400476941fa274f18b106a5922866fd780Timo Sirainen if (frame_pos != BLOCK_FRAME_COUNT-1)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_panic("Missing t_pop() call");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen#ifndef USE_GC
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen while (unused_frame_blocks != NULL) {
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen struct stack_frame_block *frame_block = unused_frame_blocks;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen unused_frame_blocks = unused_frame_blocks->prev;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen free(frame_block);
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen }
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen free(current_block);
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen free(unused_block);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#endif
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unused_frame_blocks = NULL;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen current_block = NULL;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unused_block = NULL;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen