/* private: */
unsigned char *w_buffer;
- size_t dirty, alloc;
+ size_t dirty, alloc, max_size;
pool_t pool;
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;
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
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;
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 */
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.
/* 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))
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;
+ }
+}
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)