Buffers
=======

'lib/buffers.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> [Design.Arrays.txt]
and <strings> [Design.Strings.txt]. 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. The code to initialize this
looks like:

---%<-------------------------------------------------------------------------
unsigned char buf_data[1024];
buffer_t buf;

buffer_create_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 any more complex calculations
in the size parameter of 'buffer_create_data()'. It should always be
'sizeof(data_buffer)'.

You can also create non-writable buffers with 'buffer_create_const_data()'.
Static buffers don't need to be freed.

Dynamic buffers
---------------

Dynamically growing buffers can be created with 'buffer_create_dynamic(pool,
init_size)'. Memory for 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).

(This file was created from the wiki on 2019-06-19 12:42)
