diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index ee72da3a4e..5e9ebebae7 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -331,6 +331,7 @@ test_lib_SOURCES = \ test-hash-method.c \ test-hmac.c \ test-hex-binary.c \ + test-imem.c \ test-ioloop.c \ test-iso8601-date.c \ test-iostream-pump.c \ diff --git a/src/lib/imem.h b/src/lib/imem.h index 0d35ffcc6e..4065b6e6f5 100644 --- a/src/lib/imem.h +++ b/src/lib/imem.h @@ -6,6 +6,8 @@ extern pool_t default_pool; #define i_new(type, count) p_new(default_pool, type, count) +#define i_realloc_type(mem, type, old_count, new_count) \ + p_realloc_type(default_pool, mem, type, old_count, new_count) void *i_malloc(size_t size) ATTR_MALLOC ATTR_RETURNS_NONNULL; void *i_realloc(void *mem, size_t old_size, size_t new_size) diff --git a/src/lib/mempool.h b/src/lib/mempool.h index da7583d9ef..fefac79ebe 100644 --- a/src/lib/mempool.h +++ b/src/lib/mempool.h @@ -73,9 +73,18 @@ pool_t pool_datastack_create(void); old_size + 1. */ size_t pool_get_exp_grown_size(pool_t pool, size_t old_size, size_t min_size); +/* We require sizeof(type) to be <= UINT_MAX. This allows compiler to optimize + away the entire MALLOC_MULTIPLY() call on 64bit systems. */ #define p_new(pool, type, count) \ ((type *) p_malloc(pool, MALLOC_MULTIPLY((unsigned int)sizeof(type), (count))) + \ COMPILE_ERROR_IF_TRUE(sizeof(type) > UINT_MAX)) + +#define p_realloc_type(pool, mem, type, old_count, new_count) \ + ((type *) p_realloc(pool, mem, \ + MALLOC_MULTIPLY((unsigned int)sizeof(type), (old_count)), \ + MALLOC_MULTIPLY((unsigned int)sizeof(type), (new_count))) + \ + COMPILE_ERROR_IF_TRUE(sizeof(type) > UINT_MAX)) + static inline void * ATTR_MALLOC ATTR_RETURNS_NONNULL p_malloc(pool_t pool, size_t size) { diff --git a/src/lib/test-imem.c b/src/lib/test-imem.c new file mode 100644 index 0000000000..01570adb74 --- /dev/null +++ b/src/lib/test-imem.c @@ -0,0 +1,61 @@ +/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" + +struct test_struct { + uint32_t num[10]; +}; + +static void test_imem_alloc(void) +{ + struct test_struct ab, bc, cd, de; + + test_begin("imem allocs"); + + memset(ab.num, 0xab, sizeof(ab.num)); + memset(bc.num, 0xbc, sizeof(bc.num)); + memset(cd.num, 0xcd, sizeof(cd.num)); + memset(de.num, 0xde, sizeof(de.num)); + + /* regular alloc */ + struct test_struct *s1 = i_new(struct test_struct, 2); + struct test_struct *s2 = i_malloc(sizeof(struct test_struct) * 2); + s1[0] = ab; s2[0] = ab; + s1[1] = bc; s2[1] = bc; + test_assert(memcmp(s1, s2, sizeof(struct test_struct) * 2) == 0); + + /* realloc */ + s1 = i_realloc_type(s1, struct test_struct, 2, 4); + s2 = i_realloc(s2, sizeof(struct test_struct) * 2, + sizeof(struct test_struct) * 4); + s1[2] = cd; s2[2] = cd; + s1[3] = de; s2[3] = de; + test_assert(memcmp(&s1[0], &ab, sizeof(ab)) == 0); + test_assert(memcmp(&s1[1], &bc, sizeof(bc)) == 0); + test_assert(memcmp(&s1[2], &cd, sizeof(cd)) == 0); + test_assert(memcmp(&s1[3], &de, sizeof(de)) == 0); + test_assert(memcmp(s1, s2, sizeof(struct test_struct) * 4) == 0); + + /* freeing realloced memory */ + i_free(s1); + i_free(s2); + test_assert(s1 == NULL); + test_assert(s2 == NULL); + + /* allcating new memory with realloc */ + s1 = i_realloc_type(NULL, struct test_struct, 0, 2); + s2 = i_realloc(NULL, 0, sizeof(struct test_struct) * 2); + s1[0] = ab; s2[0] = ab; + s1[1] = bc; s2[1] = bc; + test_assert(memcmp(s1, s2, sizeof(struct test_struct) * 2) == 0); + + i_free(s1); + i_free(s2); + + test_end(); +} + +void test_imem(void) +{ + test_imem_alloc(); +} diff --git a/src/lib/test-lib.inc b/src/lib/test-lib.inc index 571a74a402..8d54e3a220 100644 --- a/src/lib/test-lib.inc +++ b/src/lib/test-lib.inc @@ -20,6 +20,7 @@ TEST(test_hash_format) TEST(test_hash_method) TEST(test_hmac) TEST(test_hex_binary) +TEST(test_imem) TEST(test_ioloop) TEST(test_iso8601_date) TEST(test_iostream_pump)