Buffers¶
lib/buffer.h
describes Dovecot’s buffer API. Unless your code
happens to be VERY performance critical, you shouldn’t handle writing to
buffers/arrays manually, but instead use the buffer API’s safe functions
to guarantee that your code can’t write past the buffer and cause a
security hole.
Dovecot’s buffers are the basic building block for arrays and strings. Use them instead if they make more sense than buffers.
There are a two different ways to create buffers: statically and dynamically allocated.
Static buffers¶
You can create statically allocated buffers with
buffer_create_data()
. Trying to write past the given buffer size
will panic. Static buffers don’t need to be freed.
The code to initialize static buffers looks like:
unsigned char buf_data[1024];
buffer_t buf;
buffer_create_from_data(&buf, buf_data, sizeof(buf_data));
Trying to write more than 1024 bytes to the buffer will cause an assert-crash, so these buffers shouldn’t be used unless you know exactly what the maximum buffer size is.
To avoid accidental buffer overflows, don’t use complex
calculations in the size parameter of buffer_create_from_data()
. It
should always be sizeof(data_buffer)
.
You can also create non-writable buffers with
buffer_create_from_const_data()
.
Dynamic buffers¶
Dynamically growing buffers can be created with
buffer_create_dynamic(pool, init_size)
. Memory for the buffer is
allocated from the given pool. When memory needs to be grown, it’s grown
exponentially (2^n), with some exceptions to avoid growing the given
memory pool unless necessary. The initial buffer size is always a guess
- try to make it large enough that buffer wouldn’t be grown most of the
time, but not so large that it wastes memory.
You should be careful with memory returned by
buffer_get_space_unsafe()
and buffer_append_space_unsafe()
. This
returned memory should be accessed immediately afterwards and it must
not be accessed anymore after other buffer_*()
calls, because they
may reallocate the buffer and move it elsewhere in memory.
Buffers always look like they’re filled with NUL bytes. If you write
past the end of buffer, all the inserted bytes are filled with NULs. If
you shrink the buffer with buffer_set_used_size()
and again write
past the end of used size, all the old data is again gone and filled
with NULs. If you for some reason want to just temporarily shrink the
buffer size and then change it back, you can use
buffer_set_used_size()
to grow it back to its original size (but no
larger).