summaryrefslogtreecommitdiffstats
path: root/doc/wiki/Design.Buffers.txt
diff options
context:
space:
mode:
Diffstat (limited to 'doc/wiki/Design.Buffers.txt')
-rw-r--r--doc/wiki/Design.Buffers.txt65
1 files changed, 65 insertions, 0 deletions
diff --git a/doc/wiki/Design.Buffers.txt b/doc/wiki/Design.Buffers.txt
new file mode 100644
index 0000000..03542dc
--- /dev/null
+++ b/doc/wiki/Design.Buffers.txt
@@ -0,0 +1,65 @@
+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)