From: Timo Sirainen Date: Wed, 20 May 2020 08:16:29 +0000 (+0300) Subject: lib: Add buffer_create_dynamic_max() X-Git-Tag: 2.3.14.rc1~103 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=024d6f96b8f56539d8e7b81120fc703864ebc359;p=thirdparty%2Fdovecot%2Fcore.git lib: Add buffer_create_dynamic_max() --- diff --git a/src/lib/buffer.c b/src/lib/buffer.c index f9a5f2659a..66f1b1b265 100644 --- a/src/lib/buffer.c +++ b/src/lib/buffer.c @@ -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 */ diff --git a/src/lib/buffer.h b/src/lib/buffer.h index 0901bc8a6b..f28969d276 100644 --- a/src/lib/buffer.h +++ b/src/lib/buffer.h @@ -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)) diff --git a/src/lib/test-buffer.c b/src/lib/test-buffer.c index 0b4417b1d1..9d9f02e5dd 100644 --- a/src/lib/test-buffer.c +++ b/src/lib/test-buffer.c @@ -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; + } +} diff --git a/src/lib/test-lib.inc b/src/lib/test-lib.inc index ec03b22c79..b9bbac617e 100644 --- a/src/lib/test-lib.inc +++ b/src/lib/test-lib.inc @@ -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)