mempool-alloconly.c revision e4a7dbe5e02280e561d9ac438326ed70700cd39b
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen/* @UNSAFE: whole file */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "lib.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "safe-memset.h"
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen#include "mempool.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#ifndef DEBUG
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen# define POOL_ALLOCONLY_MAX_EXTRA MEM_ALIGN(1)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#else
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen# define POOL_ALLOCONLY_MAX_EXTRA \
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen (MEM_ALIGN(sizeof(size_t)) + MEM_ALIGN(1) + MEM_ALIGN(SENTRY_COUNT))
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen#endif
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenstruct alloconly_pool {
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen struct pool pool;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen int refcount;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen struct pool_block *block;
46ec5983bf4519ea42dbfcae3d7c62be0d8ef95fTimo Sirainen#ifdef DEBUG
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen const char *name;
6523f54d1521edf894880f2d45e75cef5dd31c3dTimo Sirainen size_t base_size;
72f5f2c5c6905b5d3f389b424313e2c450dfad96Timo Sirainen bool disable_warning;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#endif
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen bool clean_frees;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen};
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstruct pool_block {
373492be949e159fda651807b3acda2c5c077027Timo Sirainen struct pool_block *prev;
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch size_t size;
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch size_t left;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen size_t last_alloc_size;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
da7f1a07f583df8905684a7b78469960afd7c78dPhil Carmody /* unsigned char data[]; */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen};
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#define SIZEOF_POOLBLOCK (MEM_ALIGN(sizeof(struct pool_block)))
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#define POOL_BLOCK_DATA(block) \
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen ((unsigned char *) (block) + SIZEOF_POOLBLOCK)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen#define DEFAULT_BASE_SIZE MEM_ALIGN(sizeof(struct alloconly_pool))
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen#ifdef DEBUG
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen# define CLEAR_CHR 0xde
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen# define SENTRY_COUNT 8
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen#else
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen# define SENTRY_COUNT 0
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen# define CLEAR_CHR 0
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen#endif
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic const char *pool_alloconly_get_name(pool_t pool);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void pool_alloconly_ref(pool_t pool);
51fb710488efa419a2964335c30451c62b9633b1Timo Sirainenstatic void pool_alloconly_unref(pool_t *pool);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void *pool_alloconly_malloc(pool_t pool, size_t size);
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainenstatic void pool_alloconly_free(pool_t pool, void *mem);
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainenstatic void *pool_alloconly_realloc(pool_t pool, void *mem,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen size_t old_size, size_t new_size);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void pool_alloconly_clear(pool_t pool);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic size_t pool_alloconly_get_max_easy_alloc_size(pool_t pool);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainenstatic void block_alloc(struct alloconly_pool *pool, size_t size);
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainenstatic const struct pool_vfuncs static_alloconly_pool_vfuncs = {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_alloconly_get_name,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_alloconly_ref,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_alloconly_unref,
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_alloconly_malloc,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_alloconly_free,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_alloconly_realloc,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
da7f1a07f583df8905684a7b78469960afd7c78dPhil Carmody pool_alloconly_clear,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_alloconly_get_max_easy_alloc_size
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen};
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic const struct pool static_alloconly_pool = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .v = &static_alloconly_pool_vfuncs,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .alloconly_pool = TRUE,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .datastack_pool = FALSE
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen};
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen#ifdef DEBUG
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void check_sentries(struct pool_block *block)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const unsigned char *data = POOL_BLOCK_DATA(block);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen size_t i, max_pos, alloc_size, used_size;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen used_size = block->size - block->left;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen for (i = 0; i < used_size; ) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen alloc_size = *(size_t *)(data + i);
ba8498efbf886ca8b69fdb20c0ba2f5dba9416e3Timo Sirainen if (alloc_size == 0 || used_size - i < alloc_size)
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen i_panic("mempool-alloconly: saved alloc size broken");
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen i += MEM_ALIGN(sizeof(alloc_size));
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen max_pos = i + MEM_ALIGN(alloc_size + SENTRY_COUNT);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i += alloc_size;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen for (; i < max_pos; i++) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (data[i] != CLEAR_CHR)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen i_panic("mempool-alloconly: buffer overflow");
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (i != used_size)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_panic("mempool-alloconly: used_size wrong");
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
544a727de8ab0e6c55cab18a7ee475fffdf5eff3Timo Sirainen /* The unused data must be NULs */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen for (; i < block->size; i++) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (data[i] != '\0')
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen i_unreached();
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen }
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen if (block->prev != NULL)
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen check_sentries(block->prev);
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen}
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen#endif
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainenpool_t pool_alloconly_create(const char *name ATTR_UNUSED, size_t size)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen struct alloconly_pool apool, *new_apool;
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen size_t min_alloc = SIZEOF_POOLBLOCK +
b484ab4b55b0d5341f2f4dd98a655a75f0bf1275Timo Sirainen MEM_ALIGN(sizeof(struct alloconly_pool) + SENTRY_COUNT);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#ifdef DEBUG
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen min_alloc += MEM_ALIGN(strlen(name) + 1 + SENTRY_COUNT) +
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen sizeof(size_t)*2;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen#endif
544a727de8ab0e6c55cab18a7ee475fffdf5eff3Timo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen /* create a fake alloconly_pool so we can call block_alloc() */
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen i_zero(&apool);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen apool.pool = static_alloconly_pool;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen apool.refcount = 1;
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen if (size < min_alloc)
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen size = nearest_power(size + min_alloc);
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen block_alloc(&apool, size);
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen /* now allocate the actual alloconly_pool from the created block */
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen new_apool = p_new(&apool.pool, struct alloconly_pool, 1);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen *new_apool = apool;
b484ab4b55b0d5341f2f4dd98a655a75f0bf1275Timo Sirainen#ifdef DEBUG
b484ab4b55b0d5341f2f4dd98a655a75f0bf1275Timo Sirainen if (strncmp(name, MEMPOOL_GROWING, strlen(MEMPOOL_GROWING)) == 0 ||
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen getenv("DEBUG_SILENT") != NULL) {
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen name += strlen(MEMPOOL_GROWING);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen new_apool->disable_warning = TRUE;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen new_apool->name = p_strdup(&new_apool->pool, name);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
544a727de8ab0e6c55cab18a7ee475fffdf5eff3Timo Sirainen /* set base_size so p_clear() doesn't trash alloconly_pool structure. */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen new_apool->base_size = new_apool->block->size - new_apool->block->left;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen new_apool->block->last_alloc_size = 0;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen#endif
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* the first pool allocations must be from the first block */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen i_assert(new_apool->block->prev == NULL);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return &new_apool->pool;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenpool_t pool_alloconly_create_clean(const char *name, size_t size)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct alloconly_pool *apool;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen pool_t pool;
544a727de8ab0e6c55cab18a7ee475fffdf5eff3Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen pool = pool_alloconly_create(name, size);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen apool = (struct alloconly_pool *)pool;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen apool->clean_frees = TRUE;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen return pool;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainenstatic void pool_alloconly_destroy(struct alloconly_pool *apool)
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen{
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen void *block;
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen
b484ab4b55b0d5341f2f4dd98a655a75f0bf1275Timo Sirainen /* destroy all but the last block */
b484ab4b55b0d5341f2f4dd98a655a75f0bf1275Timo Sirainen pool_alloconly_clear(&apool->pool);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* destroy the last block */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen block = apool->block;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen#ifdef DEBUG
74fb6b5a156c5a61bb6ec827089bb142a10547ddTimo Sirainen safe_memset(block, CLEAR_CHR, SIZEOF_POOLBLOCK + apool->block->size);
544a727de8ab0e6c55cab18a7ee475fffdf5eff3Timo Sirainen#else
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (apool->clean_frees) {
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen safe_memset(block, CLEAR_CHR,
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen SIZEOF_POOLBLOCK + apool->block->size);
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen }
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen#endif
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen free(block);
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen}
b484ab4b55b0d5341f2f4dd98a655a75f0bf1275Timo Sirainen
b484ab4b55b0d5341f2f4dd98a655a75f0bf1275Timo Sirainenstatic const char *pool_alloconly_get_name(pool_t pool ATTR_UNUSED)
b484ab4b55b0d5341f2f4dd98a655a75f0bf1275Timo Sirainen{
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen#ifdef DEBUG
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)pool;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return apool->name;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen#else
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return "alloconly";
544a727de8ab0e6c55cab18a7ee475fffdf5eff3Timo Sirainen#endif
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void pool_alloconly_ref(pool_t pool)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen{
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)pool;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen apool->refcount++;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void pool_alloconly_unref(pool_t *pool)
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)*pool;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen /* erase the pointer before freeing anything, as the pointer may
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen exist inside the pool's memory area */
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen *pool = NULL;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (--apool->refcount > 0)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen pool_alloconly_destroy(apool);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainenstatic void block_alloc(struct alloconly_pool *apool, size_t size)
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen{
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen struct pool_block *block;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(size > SIZEOF_POOLBLOCK);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (apool->block != NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* each block is at least twice the size of the previous one */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (size <= apool->block->size)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen size += apool->block->size;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen size = nearest_power(size);
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen#ifdef DEBUG
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!apool->disable_warning) {
44cf91b7a701a9b4d9f59a990552eab4f7f64fbcTimo Sirainen /* i_debug() overwrites unallocated data in data
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen stack, so make sure everything is allocated before
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen calling it. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen t_buffer_alloc_last_full();
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen i_debug("Growing pool '%s' with: %"PRIuSIZE_T,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen apool->name, size);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#endif
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen block = calloc(size, 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (unlikely(block == NULL)) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "block_alloc(%"PRIuSIZE_T
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "): Out of memory", size);
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen }
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen block->prev = apool->block;
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainen apool->block = block;
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainen
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen block->size = size - SIZEOF_POOLBLOCK;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen block->left = block->size;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainenstatic void *pool_alloconly_malloc(pool_t pool, size_t size)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)pool;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen void *mem;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen size_t alloc_size;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
f2df3069766c747cbf020fea5d3a4261949064b0Timo Sirainen if (unlikely(size == 0 || size > SSIZE_T_MAX - POOL_ALLOCONLY_MAX_EXTRA))
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
062ea54b7775d0c92ed67b9b1f4d93fa8ec80c84Timo Sirainen#ifndef DEBUG
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen alloc_size = MEM_ALIGN(size);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen#else
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen alloc_size = MEM_ALIGN(sizeof(size)) + MEM_ALIGN(size + SENTRY_COUNT);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen#endif
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (apool->block->left < alloc_size) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* we need a new block */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen block_alloc(apool, alloc_size + SIZEOF_POOLBLOCK);
44cf91b7a701a9b4d9f59a990552eab4f7f64fbcTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mem = POOL_BLOCK_DATA(apool->block) +
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen (apool->block->size - apool->block->left);
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen apool->block->left -= alloc_size;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen apool->block->last_alloc_size = alloc_size;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen#ifdef DEBUG
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen memcpy(mem, &size, sizeof(size));
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mem = PTR_OFFSET(mem, MEM_ALIGN(sizeof(size)));
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* write CLEAR_CHRs to sentry */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen memset(PTR_OFFSET(mem, size), CLEAR_CHR,
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen MEM_ALIGN(size + SENTRY_COUNT) - size);
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen#endif
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen return mem;
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainen}
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainen
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainenstatic void pool_alloconly_free(pool_t pool, void *mem)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)pool;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* we can free only the last allocation */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (POOL_BLOCK_DATA(apool->block) +
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen (apool->block->size - apool->block->left -
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen apool->block->last_alloc_size) == mem) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen memset(mem, 0, apool->block->last_alloc_size);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen apool->block->left += apool->block->last_alloc_size;
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen apool->block->last_alloc_size = 0;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic bool pool_try_grow(struct alloconly_pool *apool, void *mem, size_t size)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen /* see if we want to grow the memory we allocated last */
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (POOL_BLOCK_DATA(apool->block) +
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen (apool->block->size - apool->block->left -
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen apool->block->last_alloc_size) == mem) {
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen /* yeah, see if we can grow */
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (apool->block->left >= size-apool->block->last_alloc_size) {
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen /* just shrink the available size */
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen apool->block->left -=
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen size - apool->block->last_alloc_size;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen apool->block->last_alloc_size = size;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen return TRUE;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen }
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen }
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen return FALSE;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen}
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainenstatic void *pool_alloconly_realloc(pool_t pool, void *mem,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen size_t old_size, size_t new_size)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen{
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)pool;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen unsigned char *new_mem;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (unlikely(new_size == 0 || new_size > SSIZE_T_MAX - POOL_ALLOCONLY_MAX_EXTRA))
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen i_panic("Trying to allocate %"PRIuSIZE_T" bytes", new_size);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (mem == NULL)
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen return pool_alloconly_malloc(pool, new_size);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (new_size <= old_size)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen return mem;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen new_size = MEM_ALIGN(new_size);
3190f12fb96daf61f7c880390472e18184cbb2d8Timo Sirainen
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen /* see if we can directly grow it */
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen if (!pool_try_grow(apool, mem, new_size)) {
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen /* slow way - allocate + copy */
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen new_mem = pool_alloconly_malloc(pool, new_size);
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen memcpy(new_mem, mem, old_size);
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen mem = new_mem;
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen }
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen return mem;
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen}
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainenstatic void pool_alloconly_clear(pool_t pool)
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen{
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)pool;
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen struct pool_block *block;
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen size_t base_size, avail_size;
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen#ifdef DEBUG
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen check_sentries(apool->block);
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen#endif
3190f12fb96daf61f7c880390472e18184cbb2d8Timo Sirainen
3190f12fb96daf61f7c880390472e18184cbb2d8Timo Sirainen /* destroy all blocks but the oldest, which contains the
3190f12fb96daf61f7c880390472e18184cbb2d8Timo Sirainen struct alloconly_pool allocation. */
3190f12fb96daf61f7c880390472e18184cbb2d8Timo Sirainen while (apool->block->prev != NULL) {
3190f12fb96daf61f7c880390472e18184cbb2d8Timo Sirainen block = apool->block;
a5bcc9f96bf56121a0704433c12137a43cd093beTimo Sirainen apool->block = block->prev;
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen
a5bcc9f96bf56121a0704433c12137a43cd093beTimo Sirainen#ifdef DEBUG
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen safe_memset(block, CLEAR_CHR, SIZEOF_POOLBLOCK + block->size);
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen#else
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen if (apool->clean_frees) {
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen safe_memset(block, CLEAR_CHR,
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen SIZEOF_POOLBLOCK + block->size);
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen }
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen#endif
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen free(block);
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen }
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen /* clear the first block */
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen#ifdef DEBUG
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen base_size = apool->base_size;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen#else
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen base_size = DEFAULT_BASE_SIZE;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen#endif
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen avail_size = apool->block->size - base_size;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen memset(PTR_OFFSET(POOL_BLOCK_DATA(apool->block), base_size), 0,
6bd263caf006edc75205f446fa0283c6f364941bTimo Sirainen avail_size - apool->block->left);
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen apool->block->left = avail_size;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen apool->block->last_alloc_size = 0;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen}
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainenstatic size_t pool_alloconly_get_max_easy_alloc_size(pool_t pool)
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen{
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)pool;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen return apool->block->left;
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen}
4addfd26372c6ae32ec93252696d86fd32081327Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainensize_t pool_alloconly_get_total_used_size(pool_t pool)
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen{
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)pool;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen struct pool_block *block;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen size_t size = 0;
0f62889d833767acf9c2ad010c3269806b4cfae3Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen i_assert(pool->v == &static_alloconly_pool_vfuncs);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen for (block = apool->block; block != NULL; block = block->prev)
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen size += block->size - block->left;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return size;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen}
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainensize_t pool_alloconly_get_total_alloc_size(pool_t pool)
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen{
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen struct alloconly_pool *apool = (struct alloconly_pool *)pool;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen struct pool_block *block;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen size_t size = 0;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen i_assert(pool->v == &static_alloconly_pool_vfuncs);
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen for (block = apool->block; block != NULL; block = block->prev)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen size += block->size + SIZEOF_POOLBLOCK;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen return size;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen}
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen