]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Add buffer_create_dynamic_max()
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 20 May 2020 08:16:29 +0000 (11:16 +0300)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 15 Jan 2021 17:26:51 +0000 (17:26 +0000)
src/lib/buffer.c
src/lib/buffer.h
src/lib/test-buffer.c
src/lib/test-lib.inc

index f9a5f2659a62e481189f8b50972211ad624feceb..66f1b1b26572c4e2cc910345b560930bfb23bec1 100644 (file)
@@ -12,7 +12,7 @@ struct real_buffer {
 
        /* private: */
        unsigned char *w_buffer;
-       size_t dirty, alloc;
+       size_t dirty, alloc, max_size;
 
        pool_t pool;
 
@@ -46,7 +46,7 @@ buffer_check_limits(struct real_buffer *buf, size_t pos, size_t data_size)
        unsigned int extra;
        size_t new_size;
 
-       if (unlikely(SIZE_MAX - pos < data_size))
+       if (unlikely(buf->max_size - pos < data_size))
                i_panic("Buffer write out of range (%zu + %zu)", pos, data_size);
 
        new_size = pos + data_size;
@@ -106,7 +106,7 @@ void buffer_create_from_data(buffer_t *buffer, void *data, size_t size)
 
        buf = (struct real_buffer *)buffer;
        i_zero(buf);
-       buf->alloc = size;
+       buf->alloc = buf->max_size = size;
        buf->r_buffer = buf->w_buffer = data;
        /* clear the whole memory area. unnecessary usually, but if the
           buffer is used by e.g. str_c() it tries to access uninitialized
@@ -125,12 +125,18 @@ void buffer_create_from_const_data(buffer_t *buffer,
        buf = (struct real_buffer *)buffer;
        i_zero(buf);
 
-       buf->used = buf->alloc = size;
+       buf->used = buf->alloc = buf->max_size = size;
        buf->r_buffer = data;
        i_assert(buf->w_buffer == NULL);
 }
 
 buffer_t *buffer_create_dynamic(pool_t pool, size_t init_size)
+{
+       return buffer_create_dynamic_max(pool, init_size, SIZE_MAX);
+}
+
+buffer_t *buffer_create_dynamic_max(pool_t pool, size_t init_size,
+                                   size_t max_size)
 {
        struct real_buffer *buf;
 
@@ -146,6 +152,7 @@ buffer_t *buffer_create_dynamic(pool_t pool, size_t init_size)
        buf = p_new(pool, struct real_buffer, 1);
        buf->pool = pool;
        buf->dynamic = TRUE;
+       buf->max_size = max_size;
        /* buffer_alloc() reserves +1 for str_c() NIL, so add +1 here to
           init_size so we can actually write that much to the buffer without
           realloc */
index 0901bc8a6b6782150250221ec86ad996b25c9a43..f28969d276a3ec632d8d7f9661857822f2629679 100644 (file)
@@ -4,7 +4,7 @@
 struct buffer {
        const void *data;
        const size_t used;
-       void *priv[5];
+       void *priv[6];
 };
 
 /* WARNING: Be careful with functions that return pointers to data.
@@ -30,6 +30,10 @@ void buffer_create_from_const_data(buffer_t *buffer,
 /* Creates a dynamically growing buffer. Whenever write would exceed the
    current size it's grown. */
 buffer_t *buffer_create_dynamic(pool_t pool, size_t init_size);
+/* Create a dynamically growing buffer with a maximum size. Writes past the
+   maximum size will i_panic(). */
+buffer_t *buffer_create_dynamic_max(pool_t pool, size_t init_size,
+                                   size_t max_size);
 
 #define t_buffer_create(init_size) \
        buffer_create_dynamic(pool_datastack_create(), (init_size))
index 0b4417b1d15b267690d2a3c9c537c7ca2480e36c..9d9f02e5ddd0b05aa8dd44555b5da685e73a7e13 100644 (file)
@@ -335,3 +335,26 @@ void test_buffer(void)
        test_buffer_truncate_bits();
        test_buffer_replace();
 }
+
+enum fatal_test_state fatal_buffer(unsigned int stage)
+{
+       buffer_t *buf;
+
+       switch (stage) {
+       case 0:
+               test_begin("fatal buffer_create_dynamic_max()");
+               buf = buffer_create_dynamic_max(default_pool, 1, 5);
+               buffer_append(buf, "12345", 5);
+               test_expect_fatal_string("Buffer write out of range");
+               buffer_append_c(buf, 'x');
+               return FATAL_TEST_FAILURE;
+       case 1:
+               buf = buffer_create_dynamic_max(default_pool, 1, 5);
+               test_expect_fatal_string("Buffer write out of range");
+               buffer_append(buf, "123456", 6);
+               return FATAL_TEST_FAILURE;
+       default:
+               test_end();
+               return FATAL_TEST_FINISHED;
+       }
+}
index ec03b22c793f6af2b1b745032b1c5e6e0b1e3540..b9bbac617ec2267ecb8e5a953c9a26bb5bcc0885 100644 (file)
@@ -12,6 +12,7 @@ TEST(test_bits)
 TEST(test_bsearch_insert_pos)
 TEST(test_buffer)
 TEST(test_buffer_append_full)
+FATAL(fatal_buffer)
 TEST(test_byteorder)
 TEST(test_connection)
 TEST(test_crc32)