]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
global: Replace open-coded allocation size arithmetic with overflow-safe helpers
authorDexter.k <164054284+rootvector2@users.noreply.github.com>
Fri, 20 Feb 2026 09:34:13 +0000 (09:34 +0000)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 6 Mar 2026 11:17:18 +0000 (11:17 +0000)
Replace several instances of multi-term allocation size arithmetic
(e.g. a + b + c) with small helper MALLOC_ADD3() macro built on
existing MALLOC_ADD().

This keeps overflow handling centralized, improves consistency across
the codebase, and makes size computations easier to audit.

No behavioral changes intended.

src/anvil/connect-limit.c
src/lib-imap/imap-match.c
src/lib-settings/settings-parser.c
src/lib-storage/index/index-mail-headers.c
src/lib/data-stack.c
src/lib/hash2.c
src/lib/malloc-overflow.h
src/lib/stats-dist.c
src/lib/strescape.c
src/lib/strfuncs.c
src/lib/test-imem.c

index f3a934a792673fa6a5d075e13a62aa48098c795f..30686a3076ab7c7fbfa686aa9a91ebe5950fcb51 100644 (file)
@@ -271,12 +271,14 @@ alt_username_field_ref(struct connect_limit *limit, const char *name)
                i_free(field->name);
                field->name = i_strdup(name);
 
+               size_t old_size = MALLOC_MULTIPLY(
+                       sizeof(limit->alt_username_hashes[0]), old_count);
+               size_t new_size = MALLOC_MULTIPLY(
+                       sizeof(limit->alt_username_hashes[0]),
+                       I_MAX((idx+1), old_count));
                limit->alt_username_hashes =
                        i_realloc(limit->alt_username_hashes,
-                                 sizeof(limit->alt_username_hashes[0]) *
-                                 old_count,
-                                 sizeof(limit->alt_username_hashes[0]) *
-                                 I_MAX((idx+1), old_count));
+                                old_size, new_size);
                if (!hash_table_is_created(limit->alt_username_hashes[idx])) {
                        hash_table_create(&limit->alt_username_hashes[idx],
                                          default_pool, 0, str_hash, strcmp);
index 7e94a275293ed659fd76d8efca68969bd5aed416..95919649ecea95631accc8fc598dfb97307e2f93 100644 (file)
@@ -134,8 +134,9 @@ imap_match_init_multiple_real(pool_t pool, const char *const *patterns,
        patterns_count = i;
 
        /* now we know how much memory we need */
-       glob = p_malloc(pool, sizeof(struct imap_match_glob) +
-                       patterns_data_len);
+       size_t glob_alloc_size =
+               MALLOC_ADD(sizeof(struct imap_match_glob), patterns_data_len);
+       glob = p_malloc(pool, glob_alloc_size);
        glob->pool = pool;
        glob->sep = separator;
 
index 6b1b3993b51a170d0fcfc551a2b20ea43ddc41c6..0735519baeb7311f0492b18ccb28a4e2a87616ee 100644 (file)
@@ -316,8 +316,9 @@ int settings_parse_read_file(const char *path, const char *value_path,
        }
        size_t prefix_len = strlen(prefix);
        size_t value_path_len = strlen(value_path);
-       char *buf = p_malloc(pool, prefix_len + value_path_len + 1 +
-                            st.st_size + 1);
+       size_t buf_size = MALLOC_ADD3(prefix_len, value_path_len, 1);
+       buf_size = MALLOC_ADD3(buf_size, (size_t)st.st_size, 1);
+       char *buf = p_malloc(pool, buf_size);
        memcpy(buf, prefix, prefix_len);
        memcpy(buf + prefix_len, value_path, value_path_len);
        buf[prefix_len + value_path_len] = '\n';
@@ -520,8 +521,10 @@ const char *settings_file_get_value(pool_t pool,
        const char *path = file->path != NULL ? file->path : "";
        size_t path_len = strlen(path);
        size_t content_len = strlen(file->content);
+       size_t value_size = MALLOC_ADD3(path_len, 1, content_len);
+       value_size = MALLOC_ADD(value_size, 1);
 
-       char *value = p_malloc(pool, path_len + 1 + content_len + 1);
+       char *value = p_malloc(pool, value_size);
        memcpy(value, path, path_len);
        value[path_len] = '\n';
        memcpy(value + path_len + 1, file->content, content_len);
index 06d4147509769527771a66d59f816faeab47da18..0adffd0822f538617c9e1c644e542a0b2a9c9d89 100644 (file)
@@ -766,7 +766,7 @@ static int unfold_header(pool_t pool, const char **_str)
                return 0;
 
        /* @UNSAFE */
-       new_str = p_malloc(pool, i + strlen(str+i) + 1);
+       new_str = p_malloc(pool, MALLOC_ADD3(i, strlen(str+i), 1));
        memcpy(new_str, str, i);
        for (j = i; str[i] != '\0'; i++) {
                if (str[i] == '\n') {
index 09766b804c29978ceedc29ce88af079c8b84e819..eae0ea77aef4b664801b4a3da473306c05e5e42e 100644 (file)
@@ -378,7 +378,7 @@ static struct stack_block *mem_block_alloc(size_t min_size)
 
        /* nearest_power() returns 2^n values, so alloc_size can't be
           anywhere close to SIZE_MAX */
-       block = malloc(SIZEOF_MEMBLOCK + alloc_size);
+       block = malloc(MALLOC_ADD(SIZEOF_MEMBLOCK, alloc_size));
        if (unlikely(block == NULL)) {
                if (outofmem) {
                        if (min_size > outofmem_area.block.left)
index a8a23e02596472f21086c896285447f6f66edb32..23918fe78f1f0a0b7cf557a5099fe98b73656221 100644 (file)
@@ -169,8 +169,9 @@ void *hash2_insert_hash(struct hash2_table *hash, unsigned int key_hash)
                value->next = NULL;
                memset(value + 1, 0, hash->value_size);
        } else {
-               value = p_malloc(hash->value_pool,
-                                sizeof(*value) + hash->value_size);
+               size_t value_alloc_size =
+                       MALLOC_ADD(sizeof(*value), hash->value_size);
+               value = p_malloc(hash->value_pool, value_alloc_size);
        }
        value->key_hash = key_hash;
 
index ab15e8e9ff7e77fdceb6884f66cd38afc9fa806a..0afcac9a0f0ee592d41ba2e1265d9896f50dcdc6 100644 (file)
@@ -51,4 +51,9 @@ malloc_add_check(size_t a, size_t b, size_t sizeof_a, size_t sizeof_b,
        malloc_add_check(a, b, sizeof(a), sizeof(size_t), __FILE__, __LINE__) // NOLINT(bugprone-sizeof-expression)
 #endif
 
+/* Minimal convenience wrapper for common allocation size arithmetic.
+   Built on MALLOC_ADD() to keep overflow handling centralized. */
+#define MALLOC_ADD3(a, b, c) \
+       MALLOC_ADD(MALLOC_ADD((a), (b)), (c))
+
 #endif
index 882bde1a4badbd13f3158c0d2dad0d9dda73a2dc..e03cb3a1941ca52472ac65d5ec2642157fc3e697 100644 (file)
@@ -27,9 +27,9 @@ struct stats_dist *stats_dist_init_with_size(unsigned int sample_count)
 {
        i_assert(sample_count > 0);
 
-       struct stats_dist *stats =
-               i_malloc(sizeof(struct stats_dist) +
-                        sizeof(uint64_t) * sample_count);
+       size_t samples_size = MALLOC_MULTIPLY(sizeof(uint64_t), sample_count);
+       size_t alloc_size = MALLOC_ADD(sizeof(struct stats_dist), samples_size);
+       struct stats_dist *stats = i_malloc(alloc_size);
        stats->sample_count = sample_count;
        return stats;
 }
index bfa4473c71c5846df0adae54c16187f2102c36bd..ded3d4bf17af515eab19ad48cc14f06ce403a73c 100644 (file)
@@ -303,9 +303,10 @@ static char **p_strsplit_tabescaped_inplace(pool_t pool, char *data)
                return p_new(pool, char *, 1);
 
        alloc_count = 32;
+       size_t array_size = MALLOC_MULTIPLY(sizeof(char *), alloc_count);
        array = pool == unsafe_data_stack_pool ?
-               t_malloc_no0(sizeof(char *) * alloc_count) :
-               p_malloc(pool, sizeof(char *) * alloc_count);
+               t_malloc_no0(array_size) :
+               p_malloc(pool, array_size);
 
        array[0] = data; count = 1;
        char *need_unescape = NULL;
@@ -319,10 +320,12 @@ static char **p_strsplit_tabescaped_inplace(pool_t pool, char *data)
                }
                if (count+1 >= alloc_count) {
                        new_alloc_count = nearest_power(alloc_count+1);
+                       size_t old_size =
+                               MALLOC_MULTIPLY(sizeof(char *), alloc_count);
+                       size_t new_size =
+                               MALLOC_MULTIPLY(sizeof(char *), new_alloc_count);
                        array = p_realloc(pool, array,
-                                         sizeof(char *) * alloc_count,
-                                         sizeof(char *) *
-                                         new_alloc_count);
+                                         old_size, new_size);
                        alloc_count = new_alloc_count;
                }
                *data++ = '\0';
index bb63de6d564f752f258e9f95cfaa52a7bcef35e0..2b346f61ec13d98addc2950990111b16747e448c 100644 (file)
@@ -758,10 +758,12 @@ split_str_slow(pool_t pool, const char *data, const char *separators, bool space
                        /* separator found */
                        if (count+1 >= alloc_count) {
                                new_alloc_count = nearest_power(alloc_count+1);
+                               size_t old_size =
+                                       MALLOC_MULTIPLY(sizeof(char *), alloc_count);
+                               size_t new_size =
+                                       MALLOC_MULTIPLY(sizeof(char *), new_alloc_count);
                                array = p_realloc(pool, array,
-                                                 sizeof(char *) * alloc_count,
-                                                 sizeof(char *) *
-                                                 new_alloc_count);
+                                                 old_size, new_size);
                                alloc_count = new_alloc_count;
                        }
 
@@ -807,10 +809,12 @@ split_str_fast(pool_t pool, const char *data, char sep)
                /* separator found */
                if (count+1 >= alloc_count) {
                        new_alloc_count = nearest_power(alloc_count+1);
+                       size_t old_size =
+                               MALLOC_MULTIPLY(sizeof(char *), alloc_count);
+                       size_t new_size =
+                               MALLOC_MULTIPLY(sizeof(char *), new_alloc_count);
                        array = p_realloc(pool, array,
-                                         sizeof(char *) * alloc_count,
-                                         sizeof(char *) *
-                                         new_alloc_count);
+                                         old_size, new_size);
                        alloc_count = new_alloc_count;
                }
                *str++ = '\0';
index cfbeafebe3cfcf28c81d91258fa0949a981e18a9..1051384563e4871f468a1c8846510c182ad44b2b 100644 (file)
@@ -19,15 +19,17 @@ static void test_imem_alloc(void)
 
        /* regular alloc */
        struct test_struct *s1 = i_new(struct test_struct, 2);
-       struct test_struct *s2 = i_malloc(sizeof(struct test_struct) * 2);
+       struct test_struct *s2 = i_malloc(
+               MALLOC_MULTIPLY(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);
+       s2 = i_realloc(s2,
+               MALLOC_MULTIPLY(sizeof(struct test_struct), 2),
+               MALLOC_MULTIPLY(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);
@@ -44,7 +46,8 @@ static void test_imem_alloc(void)
 
        /* allocating new memory with realloc */
        s1 = i_realloc_type(NULL, struct test_struct, 0, 2);
-       s2 = i_realloc(NULL, 0, sizeof(struct test_struct) * 2);
+       s2 = i_realloc(NULL, 0,
+               MALLOC_MULTIPLY(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);