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