json_parse_number broken by compiler optimization

Josef 'Jeff' Sipek jeff.sipek at open-xchange.com
Thu Apr 1 20:14:57 EEST 2021


On Wed, Mar 31, 2021 at 11:26:14 -0400, Josef 'Jeff' Sipek wrote:
> On Wed, Mar 31, 2021 at 09:07:28 +0200, Christian Ehrhardt wrote:
> > On Wed, Mar 31, 2021 at 8:46 AM Christian Ehrhardt <christian.ehrhardt at canonical.com> wrote:
> > > On Tue, Mar 30, 2021 at 9:21 PM Josef 'Jeff' Sipek <jeff.sipek at open-xchange.com> wrote:
> ...
> > > > The culprit seems to be LTO.  If you disable LTO, everything should work
> > > > just fine.
> > >
> > > I've had LTO disabled and it has still shown the same effect (with my
> > > gcc 10.2.0-1).
> > > I'll give it a non-LTO retry and double check if it really changed the
> > > compile options accordingly.
> > > I'll let you know about that later on.
> > 
> > Indeed, I wonder what I tried yesterday in regard to LTO then .. :-/
> > I can confirm that disabling LTO fixes the issue for me as well and
> > for now that should be a good mitigation until the root cause is found
> > and fixed.
> 
> Sounds good.  Thanks for the confirmation.

Does the following patch make the tests pass for you?  We still need to
clean it up a bit, but I figured I'd share the work-in-progress version to
make sure we're seeing the same issues as you.  (And the obvious disclaimer:
this patch hasn't gone through the usual before-commit scrutiny, so don't
ship it.)

Thanks,

Jeff.

diff --git a/src/anvil/anvil-settings.c b/src/anvil/anvil-settings.c
--- a/src/anvil/anvil-settings.c
+++ b/src/anvil/anvil-settings.c
@@ -16,8 +16,8 @@ static struct file_listener_settings *an
 	&anvil_unix_listeners_array[0],
 	&anvil_unix_listeners_array[1]
 };
-static buffer_t anvil_unix_listeners_buf = {
-	anvil_unix_listeners, sizeof(anvil_unix_listeners), { NULL, }
+static union static_buffer anvil_unix_listeners_buf = {
+	.buf = { anvil_unix_listeners, sizeof(anvil_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -41,7 +41,7 @@ struct service_settings anvil_service_se
 	.idle_kill = UINT_MAX,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &anvil_unix_listeners_buf,
+	.unix_listeners = { { &anvil_unix_listeners_buf.buf,
 			      sizeof(anvil_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT,
diff --git a/src/auth/auth-master-connection.c b/src/auth/auth-master-connection.c
--- a/src/auth/auth-master-connection.c
+++ b/src/auth/auth-master-connection.c
@@ -108,7 +108,7 @@ master_input_request(struct auth_master_
 	const char *const *list, *const *params;
 	unsigned int id, client_pid, client_id;
 	uint8_t cookie[MASTER_AUTH_COOKIE_SIZE];
-	buffer_t buf;
+	union static_buffer buf;
 
 	/* <id> <client-pid> <client-id> <cookie> [<parameters>] */
 	list = t_strsplit_tabescaped(args);
@@ -121,7 +121,7 @@ master_input_request(struct auth_master_
 	}
 
 	buffer_create_from_data(&buf, cookie, sizeof(cookie));
-	if (hex_to_binary(list[3], &buf) < 0) {
+	if (hex_to_binary(list[3], &buf.buf) < 0) {
 		e_error(conn->event, "BUG: Master sent broken REQUEST cookie");
 		return FALSE;
 	}
diff --git a/src/auth/auth-settings.c b/src/auth/auth-settings.c
--- a/src/auth/auth-settings.c
+++ b/src/auth/auth-settings.c
@@ -32,8 +32,8 @@ static struct file_listener_settings *au
 	&auth_unix_listeners_array[4],
 	&auth_unix_listeners_array[5]
 };
-static buffer_t auth_unix_listeners_buf = {
-	auth_unix_listeners, sizeof(auth_unix_listeners), { NULL, }
+static union static_buffer auth_unix_listeners_buf = {
+	.buf = { auth_unix_listeners, sizeof(auth_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -57,7 +57,7 @@ struct service_settings auth_service_set
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &auth_unix_listeners_buf,
+	.unix_listeners = { { &auth_unix_listeners_buf.buf,
 			      sizeof(auth_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT,
@@ -72,8 +72,8 @@ static struct file_listener_settings aut
 static struct file_listener_settings *auth_worker_unix_listeners[] = {
 	&auth_worker_unix_listeners_array[0]
 };
-static buffer_t auth_worker_unix_listeners_buf = {
-	auth_worker_unix_listeners, sizeof(auth_worker_unix_listeners), { NULL, }
+static union static_buffer auth_worker_unix_listeners_buf = {
+	.buf = { auth_worker_unix_listeners, sizeof(auth_worker_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -97,7 +97,7 @@ struct service_settings auth_worker_serv
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &auth_worker_unix_listeners_buf,
+	.unix_listeners = { { &auth_worker_unix_listeners_buf.buf,
 			      sizeof(auth_worker_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/auth/mech-digest-md5.c b/src/auth/mech-digest-md5.c
--- a/src/auth/mech-digest-md5.c
+++ b/src/auth/mech-digest-md5.c
@@ -25,7 +25,7 @@ static const char *qop_names[] = { "auth
 static string_t *get_digest_challenge(struct digest_auth_request *request)
 {
 	const struct auth_settings *set = request->auth_request.set;
-	buffer_t buf;
+	union static_buffer buf;
 	string_t *str;
 	const char *const *tmp;
 	unsigned char nonce[16];
@@ -47,9 +47,9 @@ static string_t *get_digest_challenge(st
 	random_fill(nonce, sizeof(nonce));
 
 	buffer_create_from_data(&buf, nonce_base64, sizeof(nonce_base64));
-	base64_encode(nonce, sizeof(nonce), &buf);
-	buffer_append_c(&buf, '\0');
-	request->nonce = p_strdup(request->pool, buf.data);
+	base64_encode(nonce, sizeof(nonce), &buf.buf);
+	buffer_append_c(&buf.buf, '\0');
+	request->nonce = p_strdup(request->pool, buf.buf.data);
 
 	str = t_str_new(256);
 	if (*set->realms_arr == NULL) {
diff --git a/src/auth/password-scheme-pbkdf2.c b/src/auth/password-scheme-pbkdf2.c
--- a/src/auth/password-scheme-pbkdf2.c
+++ b/src/auth/password-scheme-pbkdf2.c
@@ -18,13 +18,13 @@ pbkdf_run(const char *plaintext, const c
 	  unsigned int rounds, unsigned char key_r[PBKDF2_KEY_SIZE_SHA1])
 {
 	memset(key_r, 0, PBKDF2_KEY_SIZE_SHA1);
-	buffer_t buf;
+	union static_buffer buf;
 	buffer_create_from_data(&buf, key_r, PBKDF2_KEY_SIZE_SHA1);
 
 	pkcs5_pbkdf(PKCS5_PBKDF2, hash_method_lookup("sha1"),
 		(const unsigned char *)plaintext, strlen(plaintext),
 		(const unsigned char *)salt, strlen(salt),
-		rounds, PBKDF2_KEY_SIZE_SHA1, &buf);
+		rounds, PBKDF2_KEY_SIZE_SHA1, &buf.buf);
 }
 
 void pbkdf2_generate(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
@@ -55,7 +55,7 @@ int pbkdf2_verify(const char *plaintext,
 	const char *salt;
 	unsigned int rounds;
 	unsigned char key1[PBKDF2_KEY_SIZE_SHA1], key2[PBKDF2_KEY_SIZE_SHA1];
-	buffer_t buf;
+	union static_buffer buf;
 
 	/* $1$salt$rounds$hash */
 	if (size < 3 || memcmp(raw_password, "$1$", 3) != 0) {
@@ -72,7 +72,7 @@ int pbkdf2_verify(const char *plaintext,
 	}
 	buffer_create_from_data(&buf, key1, sizeof(key1));
 	if (strlen(fields[2]) != sizeof(key1)*2 ||
-	    hex_to_binary(fields[2], &buf) < 0) {
+	    hex_to_binary(fields[2], &buf.buf) < 0) {
 		*error_r = "PBKDF2 hash not 160bit hex-encoded";
 		return -1;
 	}
diff --git a/src/auth/test-db-dict.c b/src/auth/test-db-dict.c
--- a/src/auth/test-db-dict.c
+++ b/src/auth/test-db-dict.c
@@ -23,7 +23,7 @@ void test_db_dict_parse_cache_key(void)
 	const struct db_dict_key *objects[] = {
 		&keys[3], &keys[4]
 	};
-	buffer_t keybuf, fieldbuf, objectbuf;
+	union static_buffer keybuf, fieldbuf, objectbuf;
 	ARRAY_TYPE(db_dict_key) keyarr;
 	ARRAY_TYPE(db_dict_field) fieldarr;
 	ARRAY_TYPE(db_dict_key_p) objectarr;
@@ -33,9 +33,9 @@ void test_db_dict_parse_cache_key(void)
 	buffer_create_from_const_data(&keybuf, keys, sizeof(keys));
 	buffer_create_from_const_data(&fieldbuf, fields, sizeof(fields));
 	buffer_create_from_const_data(&objectbuf, objects, sizeof(objects));
-	array_create_from_buffer(&keyarr, &keybuf, sizeof(keys[0]));
-	array_create_from_buffer(&fieldarr, &fieldbuf, sizeof(fields[0]));
-	array_create_from_buffer(&objectarr, &objectbuf, sizeof(objects[0]));
+	array_create_from_buffer(&keyarr, &keybuf.buf, sizeof(keys[0]));
+	array_create_from_buffer(&fieldarr, &fieldbuf.buf, sizeof(fields[0]));
+	array_create_from_buffer(&objectarr, &objectbuf.buf, sizeof(objects[0]));
 
 	test_assert(strcmp(db_dict_parse_cache_key(&keyarr, &fieldarr, &objectarr),
 			   "\t%d and %n\t%l\t%{foo}%r%{bar}\t%{test1}/path\t%{extra}\tpath2/%{test2}\t%{plop}") == 0);
diff --git a/src/config/config-settings.c b/src/config/config-settings.c
--- a/src/config/config-settings.c
+++ b/src/config/config-settings.c
@@ -14,8 +14,8 @@ static struct file_listener_settings con
 static struct file_listener_settings *config_unix_listeners[] = {
 	&config_unix_listeners_array[0]
 };
-static buffer_t config_unix_listeners_buf = {
-	config_unix_listeners, sizeof(config_unix_listeners), { NULL, }
+static union static_buffer config_unix_listeners_buf = {
+	.buf = { config_unix_listeners, sizeof(config_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -39,7 +39,7 @@ struct service_settings config_service_s
 	.idle_kill = UINT_MAX,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &config_unix_listeners_buf,
+	.unix_listeners = { { &config_unix_listeners_buf.buf,
 			      sizeof(config_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/config/settings-get.pl b/src/config/settings-get.pl
--- a/src/config/settings-get.pl
+++ b/src/config/settings-get.pl
@@ -23,7 +23,7 @@ print '#include "all-settings.h"'."\n";
 print '#include <stddef.h>'."\n";
 print '#include <unistd.h>'."\n";
 print '#define CONFIG_BINARY'."\n";
-print 'extern buffer_t config_all_services_buf;';
+print 'extern union static_buffer config_all_services_buf;';
 
 my @services = ();
 my @service_ifdefs = ();
@@ -139,8 +139,8 @@ for (my $i = 0; $i < scalar(@services); 
   print "#endif\n" if ($ifdef ne "");
 }
 print "};\n";
-print "buffer_t config_all_services_buf = {\n";
-print "\tconfig_all_services, sizeof(config_all_services), { NULL, }\n";
+print "union static_buffer config_all_services_buf = {\n";
+print "\t.buf = { config_all_services, sizeof(config_all_services) }\n";
 print "};\n";
 
 print "const struct setting_parser_info *all_default_roots[] = {\n";
diff --git a/src/dict/dict-settings.c b/src/dict/dict-settings.c
--- a/src/dict/dict-settings.c
+++ b/src/dict/dict-settings.c
@@ -13,8 +13,8 @@ static struct file_listener_settings dic
 static struct file_listener_settings *dict_unix_listeners[] = {
 	&dict_unix_listeners_array[0]
 };
-static buffer_t dict_unix_listeners_buf = {
-	dict_unix_listeners, sizeof(dict_unix_listeners), { NULL, }
+static union static_buffer dict_unix_listeners_buf = {
+	.buf = { dict_unix_listeners, sizeof(dict_unix_listeners) }
 };
 
 static struct file_listener_settings dict_async_unix_listeners_array[] = {
@@ -23,8 +23,8 @@ static struct file_listener_settings dic
 static struct file_listener_settings *dict_async_unix_listeners[] = {
 	&dict_async_unix_listeners_array[0]
 };
-static buffer_t dict_async_unix_listeners_buf = {
-	dict_async_unix_listeners, sizeof(dict_async_unix_listeners), { NULL, }
+static union static_buffer dict_async_unix_listeners_buf = {
+	.buf = { dict_async_unix_listeners, sizeof(dict_async_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -48,7 +48,7 @@ struct service_settings dict_service_set
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &dict_unix_listeners_buf,
+	.unix_listeners = { { &dict_unix_listeners_buf.buf,
 			      sizeof(dict_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
@@ -74,7 +74,7 @@ struct service_settings dict_async_servi
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &dict_async_unix_listeners_buf,
+	.unix_listeners = { { &dict_async_unix_listeners_buf.buf,
 			      sizeof(dict_async_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/director/director-settings.c b/src/director/director-settings.c
--- a/src/director/director-settings.c
+++ b/src/director/director-settings.c
@@ -17,9 +17,8 @@ static struct file_listener_settings *di
 	&director_unix_listeners_array[0],
 	&director_unix_listeners_array[1]
 };
-static buffer_t director_unix_listeners_buf = {
-	director_unix_listeners,
-	sizeof(director_unix_listeners), { NULL, }
+static union static_buffer director_unix_listeners_buf = {
+	.buf = { director_unix_listeners, sizeof(director_unix_listeners) }
 };
 static struct file_listener_settings director_fifo_listeners_array[] = {
 	{ "login/proxy-notify", 0, "", "" }
@@ -27,9 +26,8 @@ static struct file_listener_settings dir
 static struct file_listener_settings *director_fifo_listeners[] = {
 	&director_fifo_listeners_array[0]
 };
-static buffer_t director_fifo_listeners_buf = {
-	director_fifo_listeners,
-	sizeof(director_fifo_listeners), { NULL, }
+static union static_buffer director_fifo_listeners_buf = {
+	.buf = { director_fifo_listeners, sizeof(director_fifo_listeners) }
 };
 /* </settings checks> */
 
@@ -53,9 +51,9 @@ struct service_settings director_service
 	.idle_kill = UINT_MAX,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &director_unix_listeners_buf,
+	.unix_listeners = { { &director_unix_listeners_buf.buf,
 			      sizeof(director_unix_listeners[0]) } },
-	.fifo_listeners = { { &director_fifo_listeners_buf,
+	.fifo_listeners = { { &director_fifo_listeners_buf.buf,
 			      sizeof(director_fifo_listeners[0]) } },
 	.inet_listeners = ARRAY_INIT,
 
diff --git a/src/dns/dns-client-settings.c b/src/dns/dns-client-settings.c
--- a/src/dns/dns-client-settings.c
+++ b/src/dns/dns-client-settings.c
@@ -16,8 +16,8 @@ static struct file_listener_settings *dn
 	&dns_client_unix_listeners_array[0],
         &dns_client_unix_listeners_array[1],
 };
-static buffer_t dns_client_unix_listeners_buf = {
-	dns_client_unix_listeners, sizeof(dns_client_unix_listeners), { NULL, }
+static union static_buffer dns_client_unix_listeners_buf = {
+	.buf = { dns_client_unix_listeners, sizeof(dns_client_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -41,7 +41,7 @@ struct service_settings dns_client_servi
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &dns_client_unix_listeners_buf,
+	.unix_listeners = { { &dns_client_unix_listeners_buf.buf,
 			      sizeof(dns_client_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/doveadm/doveadm-auth.c b/src/doveadm/doveadm-auth.c
--- a/src/doveadm/doveadm-auth.c
+++ b/src/doveadm/doveadm-auth.c
@@ -414,7 +414,7 @@ cmd_auth_master_input(const char *auth_m
 {
 	struct master_login_auth *master_auth;
 	struct master_auth_request master_auth_req;
-	buffer_t buf;
+	union static_buffer buf;
 
 	i_zero(&master_auth_req);
 	master_auth_req.tag = 1;
@@ -427,7 +427,7 @@ cmd_auth_master_input(const char *auth_m
 	buffer_create_from_data(&buf, master_auth_req.cookie,
 				sizeof(master_auth_req.cookie));
 	if (strlen(input->auth_cookie) == MASTER_AUTH_COOKIE_SIZE*2)
-		(void)hex_to_binary(input->auth_cookie, &buf);
+		(void)hex_to_binary(input->auth_cookie, &buf.buf);
 
 	input->success = FALSE;
 	master_auth = master_login_auth_init(auth_master_socket_path, FALSE);
diff --git a/src/doveadm/doveadm-dict.c b/src/doveadm/doveadm-dict.c
--- a/src/doveadm/doveadm-dict.c
+++ b/src/doveadm/doveadm-dict.c
@@ -93,11 +93,15 @@ static void cmd_dict_get(struct doveadm_
 	struct dict *dict;
 	const char *key;
 
+	if (!doveadm_cmd_param_str(cctx, "key", &key)) {
+		i_error("dict-get: Missing key");
+		doveadm_exit_code = EX_USAGE;
+		return;
+	}
+
 	if (cmd_dict_init(cctx, cmd_dict_get, &dict) < 0)
 		return;
 
-	(void)doveadm_cmd_param_str(cctx, "key", &key);
-
 	doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
 	doveadm_print_header("value", "", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE);
 
@@ -132,16 +136,16 @@ static void cmd_dict_set(struct doveadm_
 	const char *error;
 	const char *key, *value = "";
 
+	if (!doveadm_cmd_param_str(cctx, "key", &key) ||
+	    !doveadm_cmd_param_str(cctx, "value", &value)) {
+		i_error("dict set: Missing parameters");
+		doveadm_exit_code = EX_USAGE;
+		return;
+	}
+
 	if (cmd_dict_init(cctx, cmd_dict_set, &dict) < 0)
 		return;
 
-	(void)doveadm_cmd_param_str(cctx, "key", &key);
-	if (!doveadm_cmd_param_str(cctx, "value", &value)) {
-		i_error("dict set: Missing value");
-		dict_deinit(&dict);
-		return;
-	}
-
 	trans = dict_transaction_begin(dict);
 	dict_set(trans, key, value);
 	if (dict_transaction_commit(&trans, &error) <= 0) {
@@ -158,11 +162,15 @@ static void cmd_dict_unset(struct dovead
 	const char *error;
 	const char *key;
 
+	if (!doveadm_cmd_param_str(cctx, "key", &key)) {
+		i_error("dict unset: Missing key");
+		doveadm_exit_code = EX_USAGE;
+		return;
+	}
+
 	if (cmd_dict_init(cctx, cmd_dict_unset, &dict) < 0)
 		return;
 
-	(void)doveadm_cmd_param_str(cctx, "key", &key);
-
 	trans = dict_transaction_begin(dict);
 	dict_unset(trans, key);
 	if (dict_transaction_commit(&trans, &error) <= 0) {
@@ -181,17 +189,16 @@ static void cmd_dict_inc(struct doveadm_
 	int64_t diff;
 	int ret;
 
+	if (!doveadm_cmd_param_str(cctx, "key", &key) ||
+	    !doveadm_cmd_param_int64(cctx, "difference", &diff)) {
+		i_error("dict-inc: Missing parameters");
+		doveadm_exit_code = EX_USAGE;
+		return;
+	}
+
 	if (cmd_dict_init(cctx, cmd_dict_inc, &dict) < 0)
 		return;
 
-	if (!doveadm_cmd_param_int64(cctx, "difference", &diff)) {
-		i_error("Missing difference");
-		doveadm_exit_code = EX_USAGE;
-		dict_deinit(&dict);
-		return;
-	}
-	(void)doveadm_cmd_param_str(cctx, "key", &key);
-
 	trans = dict_transaction_begin(dict);
 	dict_atomic_inc(trans, key, diff);
 	ret = dict_transaction_commit(&trans, &error);
@@ -213,6 +220,12 @@ static void cmd_dict_iter(struct doveadm
 	const char *prefix, *key, *const *values, *error;
 	bool header_printed = FALSE;
 
+	if (!doveadm_cmd_param_str(cctx, "prefix", &prefix)) {
+		i_error("dict-iter: Missing prefix");
+		doveadm_exit_code = EX_USAGE;
+		return;
+	}
+
 	if (cmd_dict_init_full(cctx, cmd_dict_iter, &iter_flags, &dict) < 0)
 		return;
 
@@ -221,8 +234,6 @@ static void cmd_dict_iter(struct doveadm
 	if ((iter_flags & DICT_ITERATE_FLAG_NO_VALUE) == 0)
 		doveadm_print_header_simple("value");
 
-	(void)doveadm_cmd_param_str(cctx, "prefix", &prefix);
-
 	iter = dict_iterate_init(dict, prefix, iter_flags);
 	while (dict_iterate_values(iter, &key, &values)) {
 		unsigned int values_count = str_array_length(values);
diff --git a/src/doveadm/doveadm-settings.c b/src/doveadm/doveadm-settings.c
--- a/src/doveadm/doveadm-settings.c
+++ b/src/doveadm/doveadm-settings.c
@@ -20,8 +20,8 @@ static struct file_listener_settings dov
 static struct file_listener_settings *doveadm_unix_listeners[] = {
 	&doveadm_unix_listeners_array[0]
 };
-static buffer_t doveadm_unix_listeners_buf = {
-	doveadm_unix_listeners, sizeof(doveadm_unix_listeners), { NULL, }
+static union static_buffer doveadm_unix_listeners_buf = {
+	.buf = { doveadm_unix_listeners, sizeof(doveadm_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -45,7 +45,7 @@ struct service_settings doveadm_service_
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &doveadm_unix_listeners_buf,
+	.unix_listeners = { { &doveadm_unix_listeners_buf.buf,
 			      sizeof(doveadm_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/doveadm/dsync/dsync-mailbox-tree-sync.c b/src/doveadm/dsync/dsync-mailbox-tree-sync.c
--- a/src/doveadm/dsync/dsync-mailbox-tree-sync.c
+++ b/src/doveadm/dsync/dsync-mailbox-tree-sync.c
@@ -389,7 +389,7 @@ sync_rename_node_to_temp(struct dsync_ma
 	struct dsync_mailbox_tree_sync_change *change;
 	const char *old_name, *new_name, *p;
 	char name[TEMP_MAX_NAME_LEN+1];
-	buffer_t buf;
+	union static_buffer buf;
 	size_t prefix_len, max_prefix_len;
 	unsigned int counter = 1;
 
@@ -405,22 +405,22 @@ sync_rename_node_to_temp(struct dsync_ma
 		if (max_prefix_len > (size_t)(p - node->name))
 			max_prefix_len = p - node->name;
 	}
-	str_append_max(&buf, node->name, max_prefix_len);
-	str_append_c(&buf, '-');
-	prefix_len = buf.used;
+	str_append_max(&buf.buf, node->name, max_prefix_len);
+	str_append_c(&buf.buf, '-');
+	prefix_len = buf.buf.used;
 
 	do {
-		str_truncate(&buf, prefix_len);
-		str_printfa(&buf, TEMP_SUFFIX_FORMAT, counter++);
+		str_truncate(&buf.buf, prefix_len);
+		str_printfa(&buf.buf, TEMP_SUFFIX_FORMAT, counter++);
 		/* the generated name is quite unlikely to exist,
 		   but check anyway.. */
-	} while (node_has_child(node->parent, str_c(&buf)));
+	} while (node_has_child(node->parent, str_c(&buf.buf)));
 
 	old_name = tree != ctx->local_tree ? NULL :
 		dsync_mailbox_node_get_full_name(tree, node);
 
-	*reason_r = t_strdup_printf("Renamed '%s' to '%s'", node->name, str_c(&buf));
-	node->name = p_strdup(tree->pool, str_c(&buf));
+	*reason_r = t_strdup_printf("Renamed '%s' to '%s'", node->name, str_c(&buf.buf));
+	node->name = p_strdup(tree->pool, str_c(&buf.buf));
 	node->sync_temporary_name = TRUE;
 	node->last_renamed_or_created = 0;
 	dsync_mailbox_tree_node_move_sorted(node, new_parent);
diff --git a/src/imap-hibernate/imap-hibernate-settings.c b/src/imap-hibernate/imap-hibernate-settings.c
--- a/src/imap-hibernate/imap-hibernate-settings.c
+++ b/src/imap-hibernate/imap-hibernate-settings.c
@@ -15,8 +15,8 @@ static struct file_listener_settings ima
 static struct file_listener_settings *imap_hibernate_unix_listeners[] = {
 	&imap_hibernate_unix_listeners_array[0]
 };
-static buffer_t imap_hibernate_unix_listeners_buf = {
-	imap_hibernate_unix_listeners, sizeof(imap_hibernate_unix_listeners), { NULL, }
+static union static_buffer imap_hibernate_unix_listeners_buf = {
+	.buf = { imap_hibernate_unix_listeners, sizeof(imap_hibernate_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -40,7 +40,7 @@ struct service_settings imap_hibernate_s
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &imap_hibernate_unix_listeners_buf,
+	.unix_listeners = { { &imap_hibernate_unix_listeners_buf.buf,
 			      sizeof(imap_hibernate_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/imap-login/imap-login-settings.c b/src/imap-login/imap-login-settings.c
--- a/src/imap-login/imap-login-settings.c
+++ b/src/imap-login/imap-login-settings.c
@@ -18,8 +18,8 @@ static struct inet_listener_settings *im
 	&imap_login_inet_listeners_array[0],
 	&imap_login_inet_listeners_array[1]
 };
-static buffer_t imap_login_inet_listeners_buf = {
-	imap_login_inet_listeners, sizeof(imap_login_inet_listeners), { NULL, }
+static union static_buffer imap_login_inet_listeners_buf = {
+	.buf = { imap_login_inet_listeners, sizeof(imap_login_inet_listeners) }
 };
 /* </settings checks> */
 
@@ -45,7 +45,7 @@ struct service_settings imap_login_servi
 
 	.unix_listeners = ARRAY_INIT,
 	.fifo_listeners = ARRAY_INIT,
-	.inet_listeners = { { &imap_login_inet_listeners_buf,
+	.inet_listeners = { { &imap_login_inet_listeners_buf.buf,
 			      sizeof(imap_login_inet_listeners[0]) } }
 };
 
diff --git a/src/imap-urlauth/imap-urlauth-login-settings.c b/src/imap-urlauth/imap-urlauth-login-settings.c
--- a/src/imap-urlauth/imap-urlauth-login-settings.c
+++ b/src/imap-urlauth/imap-urlauth-login-settings.c
@@ -17,9 +17,11 @@ imap_urlauth_login_unix_listeners_array[
 static struct file_listener_settings *imap_urlauth_login_unix_listeners[] = {
 	&imap_urlauth_login_unix_listeners_array[0]
 };
-static buffer_t imap_urlauth_login_unix_listeners_buf = {
-	imap_urlauth_login_unix_listeners,
-		sizeof(imap_urlauth_login_unix_listeners), { NULL, }
+static union static_buffer imap_urlauth_login_unix_listeners_buf = {
+	.buf = {
+		imap_urlauth_login_unix_listeners,
+		sizeof(imap_urlauth_login_unix_listeners),
+	}
 };
 /* </settings checks> */
 
@@ -43,7 +45,7 @@ struct service_settings imap_urlauth_log
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &imap_urlauth_login_unix_listeners_buf,
+	.unix_listeners = { { &imap_urlauth_login_unix_listeners_buf.buf,
 			      sizeof(imap_urlauth_login_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/imap-urlauth/imap-urlauth-settings.c b/src/imap-urlauth/imap-urlauth-settings.c
--- a/src/imap-urlauth/imap-urlauth-settings.c
+++ b/src/imap-urlauth/imap-urlauth-settings.c
@@ -16,8 +16,11 @@ static struct file_listener_settings ima
 static struct file_listener_settings *imap_urlauth_unix_listeners[] = {
 	&imap_urlauth_unix_listeners_array[0]
 };
-static buffer_t imap_urlauth_unix_listeners_buf = {
-	imap_urlauth_unix_listeners, sizeof(imap_urlauth_unix_listeners), { NULL, }
+static union static_buffer imap_urlauth_unix_listeners_buf = {
+	.buf = {
+		imap_urlauth_unix_listeners,
+		sizeof(imap_urlauth_unix_listeners),
+	}
 };
 /* </settings checks> */
 
@@ -41,7 +44,7 @@ struct service_settings imap_urlauth_ser
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &imap_urlauth_unix_listeners_buf,
+	.unix_listeners = { { &imap_urlauth_unix_listeners_buf.buf,
 			      sizeof(imap_urlauth_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/imap-urlauth/imap-urlauth-worker-settings.c b/src/imap-urlauth/imap-urlauth-worker-settings.c
--- a/src/imap-urlauth/imap-urlauth-worker-settings.c
+++ b/src/imap-urlauth/imap-urlauth-worker-settings.c
@@ -17,8 +17,8 @@ static struct file_listener_settings ima
 static struct file_listener_settings *imap_urlauth_worker_unix_listeners[] = {
 	&imap_urlauth_worker_unix_listeners_array[0]
 };
-static buffer_t imap_urlauth_worker_unix_listeners_buf = {
-	imap_urlauth_worker_unix_listeners, sizeof(imap_urlauth_worker_unix_listeners), { NULL, }
+static union static_buffer imap_urlauth_worker_unix_listeners_buf = {
+	.buf = { imap_urlauth_worker_unix_listeners, sizeof(imap_urlauth_worker_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -42,7 +42,7 @@ struct service_settings imap_urlauth_wor
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &imap_urlauth_worker_unix_listeners_buf,
+	.unix_listeners = { { &imap_urlauth_worker_unix_listeners_buf.buf,
 			      sizeof(imap_urlauth_worker_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/imap/imap-master-client.c b/src/imap/imap-master-client.c
--- a/src/imap/imap-master-client.c
+++ b/src/imap/imap-master-client.c
@@ -218,7 +218,7 @@ imap_master_client_input_args(struct con
 	struct client *imap_client;
 	struct mail_storage_service_input input;
 	struct imap_master_input master_input;
-	const char *error, *reason;
+	const char *error = NULL, *reason;
 	int ret;
 
 	if (imap_master_client_parse_input(args, pool, &input, &master_input,
diff --git a/src/imap/imap-settings.c b/src/imap/imap-settings.c
--- a/src/imap/imap-settings.c
+++ b/src/imap/imap-settings.c
@@ -24,8 +24,8 @@ static struct file_listener_settings *im
 	&imap_unix_listeners_array[0],
 	&imap_unix_listeners_array[1]
 };
-static buffer_t imap_unix_listeners_buf = {
-	imap_unix_listeners, sizeof(imap_unix_listeners), { NULL, }
+static union static_buffer imap_unix_listeners_buf = {
+	.buf = { imap_unix_listeners, sizeof(imap_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -49,7 +49,7 @@ struct service_settings imap_service_set
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &imap_unix_listeners_buf,
+	.unix_listeners = { { &imap_unix_listeners_buf.buf,
 			      sizeof(imap_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/indexer/indexer-settings.c b/src/indexer/indexer-settings.c
--- a/src/indexer/indexer-settings.c
+++ b/src/indexer/indexer-settings.c
@@ -16,8 +16,8 @@ static struct file_listener_settings ind
 static struct file_listener_settings *indexer_unix_listeners[] = {
 	&indexer_unix_listeners_array[0]
 };
-static buffer_t indexer_unix_listeners_buf = {
-	indexer_unix_listeners, sizeof(indexer_unix_listeners), { NULL, }
+static union static_buffer indexer_unix_listeners_buf = {
+	.buf = { indexer_unix_listeners, sizeof(indexer_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -41,7 +41,7 @@ struct service_settings indexer_service_
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &indexer_unix_listeners_buf,
+	.unix_listeners = { { &indexer_unix_listeners_buf.buf,
 			      sizeof(indexer_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT,
diff --git a/src/indexer/indexer-worker-settings.c b/src/indexer/indexer-worker-settings.c
--- a/src/indexer/indexer-worker-settings.c
+++ b/src/indexer/indexer-worker-settings.c
@@ -14,8 +14,11 @@ static struct file_listener_settings ind
 static struct file_listener_settings *indexer_worker_unix_listeners[] = {
 	&indexer_worker_unix_listeners_array[0]
 };
-static buffer_t indexer_worker_unix_listeners_buf = {
-	indexer_worker_unix_listeners, sizeof(indexer_worker_unix_listeners), { NULL, }
+static union static_buffer indexer_worker_unix_listeners_buf = {
+	.buf = {
+		indexer_worker_unix_listeners,
+		sizeof(indexer_worker_unix_listeners),
+	}
 };
 /* </settings checks> */
 
@@ -39,7 +42,7 @@ struct service_settings indexer_worker_s
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &indexer_worker_unix_listeners_buf,
+	.unix_listeners = { { &indexer_worker_unix_listeners_buf.buf,
 			      sizeof(indexer_worker_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/ipc/ipc-settings.c b/src/ipc/ipc-settings.c
--- a/src/ipc/ipc-settings.c
+++ b/src/ipc/ipc-settings.c
@@ -16,8 +16,8 @@ static struct file_listener_settings *ip
 	&ipc_unix_listeners_array[0],
 	&ipc_unix_listeners_array[1]
 };
-static buffer_t ipc_unix_listeners_buf = {
-	ipc_unix_listeners, sizeof(ipc_unix_listeners), { NULL, }
+static union static_buffer ipc_unix_listeners_buf = {
+	.buf = { ipc_unix_listeners, sizeof(ipc_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -41,7 +41,7 @@ struct service_settings ipc_service_sett
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &ipc_unix_listeners_buf,
+	.unix_listeners = { { &ipc_unix_listeners_buf.buf,
 			      sizeof(ipc_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT,
diff --git a/src/lib-dcrypt/dcrypt-openssl.c b/src/lib-dcrypt/dcrypt-openssl.c
--- a/src/lib-dcrypt/dcrypt-openssl.c
+++ b/src/lib-dcrypt/dcrypt-openssl.c
@@ -984,7 +984,8 @@ dcrypt_openssl_decrypt_point_ec_v1(struc
 				   const char *peer_key_hex, BIGNUM **point_r,
 				   const char **error_r)
 {
-	buffer_t *peer_key, *data, key, *secret;
+	buffer_t *peer_key, *data, *secret;
+	union static_buffer key;
 	bool res;
 
 	data = t_buffer_create(128);
@@ -1007,7 +1008,7 @@ dcrypt_openssl_decrypt_point_ec_v1(struc
 	buffer_create_from_const_data(&key, digest, SHA256_DIGEST_LENGTH);
 
 	/* then use this as key */
-	res = dcrypt_openssl_decrypt_point_v1(data, &key, point_r, error_r);
+	res = dcrypt_openssl_decrypt_point_v1(data, &key.buf, point_r, error_r);
 	memset(digest, 0, sizeof(digest));
 	safe_memset(digest, 0, SHA256_DIGEST_LENGTH);
 
@@ -1327,7 +1328,8 @@ dcrypt_openssl_load_private_key_dovecot_
 			return FALSE;
 		}
 
-		buffer_t *salt, secret, *data;
+		buffer_t *salt, *data;
+		union static_buffer secret;
 		salt = t_buffer_create(strlen(input[4])/2);
 		buffer_create_from_const_data(&secret, password, strlen(password));
 		data = t_buffer_create(strlen(input[7])/2);
@@ -1338,7 +1340,7 @@ dcrypt_openssl_load_private_key_dovecot_
 		}
 
 		if (!dcrypt_openssl_cipher_key_dovecot_v2(input[3],
-			DCRYPT_MODE_DECRYPT, data, &secret, salt,
+			DCRYPT_MODE_DECRYPT, data, &secret.buf, salt,
 			input[5], rounds, key_data, error_r)) {
 			return FALSE;
 		}
@@ -2096,12 +2098,12 @@ dcrypt_openssl_load_public_key_dovecot_v
 					  int len, const char **input,
 					  const char **error_r)
 {
-	buffer_t tmp;
+	union static_buffer tmp;
 	size_t keylen = strlen(input[1])/2;
 	unsigned char keybuf[keylen];
 	const unsigned char *ptr;
 	buffer_create_from_data(&tmp, keybuf, keylen);
-	hex_to_binary(input[1], &tmp);
+	hex_to_binary(input[1], &tmp.buf);
 	ptr = keybuf;
 
 	EVP_PKEY *pkey = EVP_PKEY_new();
@@ -2173,7 +2175,7 @@ dcrypt_openssl_encrypt_private_key_dovec
 	str_append_c(destination, ':');
 	random_fill(salt, sizeof(salt));
 	binary_to_hex_append(destination, salt, sizeof(salt));
-	buffer_t saltbuf;
+	union static_buffer saltbuf;
 	buffer_create_from_const_data(&saltbuf, salt, sizeof(salt));
 
 	/* so we don't have to make new version if we ever upgrade these */
@@ -2213,7 +2215,7 @@ dcrypt_openssl_encrypt_private_key_dovec
 	/* encrypt key using secret and salt */
 	buffer_t *tmp = t_buffer_create(128);
 	res = dcrypt_openssl_cipher_key_dovecot_v2(cipher,
-		DCRYPT_MODE_ENCRYPT, key, secret, &saltbuf,
+		DCRYPT_MODE_ENCRYPT, key, secret, &saltbuf.buf,
 		DCRYPT_DOVECOT_KEY_ENCRYPT_HASH,
 		DCRYPT_DOVECOT_KEY_ENCRYPT_ROUNDS, tmp, error_r);
 	safe_memset(buffer_get_modifiable_data(secret, NULL), 0, secret->used);
diff --git a/src/lib-dcrypt/istream-decrypt.c b/src/lib-dcrypt/istream-decrypt.c
--- a/src/lib-dcrypt/istream-decrypt.c
+++ b/src/lib-dcrypt/istream-decrypt.c
@@ -89,7 +89,7 @@ i_stream_decrypt_read_header_v1(struct d
 	size_t pos = sizeof(IOSTREAM_CRYPT_MAGIC);
 	size_t digest_len = 0, key_ct_len = 0, key_digest_size = 0;
 
-	buffer_t ephemeral_key;
+	union static_buffer ephemeral_key;
 	buffer_t *secret = t_buffer_create(256);
 	buffer_t *key = t_buffer_create(256);
 
@@ -191,7 +191,7 @@ i_stream_decrypt_read_header_v1(struct d
 
 	/* derive shared secret */
 	if (!dcrypt_ecdh_derive_secret_local(stream->priv_key,
-		&ephemeral_key, secret, &error)) {
+		&ephemeral_key.buf, secret, &error)) {
 		io_stream_set_error(&stream->istream.iostream,
 				    "Cannot perform ECDH: %s", error);
 		return -1;
@@ -332,7 +332,7 @@ i_stream_decrypt_key(struct decrypt_istr
 	bool have_key = FALSE;
 	unsigned char dgst[32];
 	uint32_t val;
-	buffer_t buf;
+	union static_buffer buf;
 
 	if (data == end)
 		return 0;
@@ -342,7 +342,7 @@ i_stream_decrypt_key(struct decrypt_istr
 	/* if we have a key, prefab the digest */
 	if (stream->priv_key != NULL) {
 		buffer_create_from_data(&buf, dgst, sizeof(dgst));
-		if (!dcrypt_key_id_private(stream->priv_key, "sha256", &buf,
+		if (!dcrypt_key_id_private(stream->priv_key, "sha256", &buf.buf,
 					   &error)) {
 			io_stream_set_error(&stream->istream.iostream,
 					    "Decryption error: "
@@ -446,11 +446,11 @@ i_stream_decrypt_key(struct decrypt_istr
 		/* perform ECDHE */
 		buffer_t *temp_key = t_buffer_create(256);
 		buffer_t *secret = t_buffer_create(256);
-		buffer_t peer_key;
+		union static_buffer peer_key;
 		buffer_create_from_const_data(&peer_key,
 			ephemeral_key, ep_key_len);
 		if (!dcrypt_ecdh_derive_secret_local(stream->priv_key,
-			&peer_key, secret, &error)) {
+			&peer_key.buf, secret, &error)) {
 			io_stream_set_error(&stream->istream.iostream,
 				"Key decryption error: corrupted header");
 			return -1;
@@ -459,7 +459,7 @@ i_stream_decrypt_key(struct decrypt_istr
 		/* use shared secret and peer key to generate decryption key,
 		   AES-256-CBC has 32 byte key and 16 byte IV */
 		if (!dcrypt_pbkdf2(secret->data, secret->used,
-				   peer_key.data, peer_key.used,
+				   peer_key.buf.data, peer_key.buf.used,
 				   malg, rounds, temp_key, 32+16, &error)) {
 			safe_memset(buffer_get_modifiable_data(secret, 0),
 				    0, secret->used);
@@ -916,9 +916,9 @@ i_stream_decrypt_read(struct istream_pri
 			if ((dstream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) ==
 				IO_STREAM_ENC_INTEGRITY_HMAC) {
 				unsigned char dgst[dcrypt_ctx_hmac_get_digest_length(dstream->ctx_mac)];
-				buffer_t db;
+				union static_buffer db;
 				buffer_create_from_data(&db, dgst, sizeof(dgst));
-				if (!dcrypt_ctx_hmac_final(dstream->ctx_mac, &db, &error)) {
+				if (!dcrypt_ctx_hmac_final(dstream->ctx_mac, &db.buf, &error)) {
 					io_stream_set_error(&stream->iostream,
 						"Cannot verify MAC: %s", error);
 					stream->istream.stream_errno = EINVAL;
diff --git a/src/lib-dcrypt/ostream-encrypt.c b/src/lib-dcrypt/ostream-encrypt.c
--- a/src/lib-dcrypt/ostream-encrypt.c
+++ b/src/lib-dcrypt/ostream-encrypt.c
@@ -139,7 +139,8 @@ o_stream_encrypt_send_header_v2(struct e
 static int
 o_stream_encrypt_keydata_create_v1(struct encrypt_ostream *stream)
 {
-	buffer_t *encrypted_key, *ephemeral_key, *secret, *res, buf;
+	buffer_t *encrypted_key, *ephemeral_key, *secret, *res;
+	union static_buffer buf;
 	const char *error = NULL;
 	const struct hash_method *hash = &hash_method_sha256;
 
@@ -153,7 +154,7 @@ o_stream_encrypt_keydata_create_v1(struc
 
 	/* hash the public key first */
 	buffer_create_from_data(&buf, pkhash, sizeof(pkhash));
-	if (!dcrypt_key_id_public_old(stream->pub, &buf, &error)) {
+	if (!dcrypt_key_id_public_old(stream->pub, &buf.buf, &error)) {
 		io_stream_set_error(&stream->ostream.iostream,
 				    "Key hash failed: %s", error);
 		return -1;
@@ -500,7 +501,7 @@ o_stream_encrypt_sendv(struct ostream_pr
 
 	/* buffer for encrypted data */
 	unsigned char ciphertext[IO_BLOCK_SIZE];
-	buffer_t buf;
+	union static_buffer buf;
 	buffer_create_from_data(&buf, ciphertext, sizeof(ciphertext));
 
 	/* encrypt & send all blocks of data at max ciphertext buffer's
@@ -509,12 +510,12 @@ o_stream_encrypt_sendv(struct ostream_pr
 		size_t bl, off = 0, len = iov[i].iov_len;
 		const unsigned char *ptr = iov[i].iov_base;
 		while(len > 0) {
-			buffer_set_used_size(&buf, 0);
+			buffer_set_used_size(&buf.buf, 0);
 			/* update can emite twice the size of input */
 			bl = I_MIN(sizeof(ciphertext)/2, len);
 
 			if (!dcrypt_ctx_sym_update(estream->ctx_sym, ptr + off,
-						   bl, &buf, &error)) {
+						   bl, &buf.buf, &error)) {
 				io_stream_set_error(&stream->iostream,
 						    "Encryption failure: %s",
 						    error);
@@ -524,7 +525,7 @@ o_stream_encrypt_sendv(struct ostream_pr
 				IO_STREAM_ENC_INTEGRITY_HMAC) {
 				/* update mac */
 				if (!dcrypt_ctx_hmac_update(estream->ctx_mac,
-					buf.data, buf.used, &error)) {
+					buf.buf.data, buf.buf.used, &error)) {
 					io_stream_set_error(&stream->iostream,
 						"MAC failure: %s", error);
 					return -1;
@@ -532,7 +533,7 @@ o_stream_encrypt_sendv(struct ostream_pr
 			}
 
 			/* hopefully upstream can accommodate */
-			if (o_stream_encrypt_send(estream, buf.data, buf.used) < 0) {
+			if (o_stream_encrypt_send(estream, buf.buf.data, buf.buf.used) < 0) {
 				return -1;
 			}
 
diff --git a/src/lib-imap-urlauth/imap-urlauth-backend.c b/src/lib-imap-urlauth/imap-urlauth-backend.c
--- a/src/lib-imap-urlauth/imap-urlauth-backend.c
+++ b/src/lib-imap-urlauth/imap-urlauth-backend.c
@@ -59,7 +59,7 @@ imap_urlauth_backend_trans_get_mailbox_k
 	struct mail_user *user = mail_storage_get_user(mailbox_get_storage(box));
 	struct mail_attribute_value urlauth_key;
 	const char *mailbox_key_hex = NULL;
-	buffer_t key_buf;
+	union static_buffer key_buf;
 	int ret;
 
 	*client_error_r = "Internal server error";
@@ -92,8 +92,8 @@ imap_urlauth_backend_trans_get_mailbox_k
 					IMAP_URLAUTH_KEY_LEN);
 		mailbox_key_hex = urlauth_key.value;
 		if (strlen(mailbox_key_hex) != 2*IMAP_URLAUTH_KEY_LEN ||
-		    hex_to_binary(mailbox_key_hex, &key_buf) < 0 ||
-		    key_buf.used != IMAP_URLAUTH_KEY_LEN) {
+		    hex_to_binary(mailbox_key_hex, &key_buf.buf) < 0 ||
+		    key_buf.buf.used != IMAP_URLAUTH_KEY_LEN) {
 			i_error("imap-urlauth: key found for mailbox %s is invalid",
 				mailbox_get_vname(box));
 			return -1;
diff --git a/src/lib-imap/imap-envelope.c b/src/lib-imap/imap-envelope.c
--- a/src/lib-imap/imap-envelope.c
+++ b/src/lib-imap/imap-envelope.c
@@ -223,6 +223,7 @@ bool imap_envelope_parse(const char *env
 	struct imap_parser *parser;
 	const struct imap_arg *args;
 	int ret;
+	bool success;
 
 	input = i_stream_create_from_data(envelope, strlen(envelope));
 	(void)i_stream_read(input);
@@ -233,15 +234,15 @@ bool imap_envelope_parse(const char *env
 	if (ret < 0) {
 		*error_r = t_strdup_printf("IMAP parser failed: %s",
 					   imap_parser_get_error(parser, NULL));
+		success = FALSE;
 	} else if (ret == 0) {
 		*error_r = "Empty envelope";
-		ret = -1;
+		success = FALSE;
 	} else {
-		if (!imap_envelope_parse_args(args, pool, envlp_r, error_r))
-			ret = -1;
+		success = imap_envelope_parse_args(args, pool, envlp_r, error_r);
 	}
 
 	imap_parser_unref(&parser);
 	i_stream_destroy(&input);
-	return (ret >= 0);
+	return success;
 }
diff --git a/src/lib-index/mail-index-modseq.c b/src/lib-index/mail-index-modseq.c
--- a/src/lib-index/mail-index-modseq.c
+++ b/src/lib-index/mail-index-modseq.c
@@ -327,7 +327,7 @@ mail_index_modseq_update_old_rec(struct 
 {
 	ARRAY_TYPE(seq_range) uids = ARRAY_INIT;
 	const struct seq_range *rec;
-	buffer_t uid_buf;
+	union static_buffer uid_buf;
 	unsigned int i, count;
 	uint32_t seq1, seq2;
 
@@ -346,7 +346,7 @@ mail_index_modseq_update_old_rec(struct 
 	}
 	case MAIL_TRANSACTION_FLAG_UPDATE: {
 		buffer_create_from_const_data(&uid_buf, tdata, thdr->size);
-		array_create_from_buffer(&uids, &uid_buf,
+		array_create_from_buffer(&uids, &uid_buf.buf,
 			sizeof(struct mail_transaction_flag_update));
 		break;
 	}
@@ -361,12 +361,12 @@ mail_index_modseq_update_old_rec(struct 
 		buffer_create_from_const_data(&uid_buf,
 					 CONST_PTR_OFFSET(tdata, seqset_offset),
 					 thdr->size - seqset_offset);
-		array_create_from_buffer(&uids, &uid_buf, sizeof(uint32_t)*2);
+		array_create_from_buffer(&uids, &uid_buf.buf, sizeof(uint32_t)*2);
 		break;
 	}
 	case MAIL_TRANSACTION_KEYWORD_RESET:
 		buffer_create_from_const_data(&uid_buf, tdata, thdr->size);
-		array_create_from_buffer(&uids, &uid_buf,
+		array_create_from_buffer(&uids, &uid_buf.buf,
 			sizeof(struct mail_transaction_keyword_reset));
 		break;
 	case MAIL_TRANSACTION_ATTRIBUTE_UPDATE:
diff --git a/src/lib-index/mail-index-sync-keywords.c b/src/lib-index/mail-index-sync-keywords.c
--- a/src/lib-index/mail-index-sync-keywords.c
+++ b/src/lib-index/mail-index-sync-keywords.c
@@ -76,7 +76,7 @@ static void keywords_ext_register(struct
 				  uint32_t ext_map_idx, uint32_t reset_id,
 				  uint32_t hdr_size, uint32_t keywords_count)
 {
-	buffer_t ext_intro_buf;
+	union static_buffer ext_intro_buf;
 	struct mail_transaction_ext_intro *u;
 	unsigned char ext_intro_data[sizeof(*u) +
 				     sizeof(MAIL_INDEX_EXT_KEYWORDS)-1];
@@ -86,7 +86,7 @@ static void keywords_ext_register(struct
 	buffer_create_from_data(&ext_intro_buf, ext_intro_data,
 				sizeof(ext_intro_data));
 
-	u = buffer_append_space_unsafe(&ext_intro_buf, sizeof(*u));
+	u = buffer_append_space_unsafe(&ext_intro_buf.buf, sizeof(*u));
 	u->ext_id = ext_map_idx;
 	u->reset_id = reset_id;
 	u->hdr_size = hdr_size;
@@ -100,7 +100,7 @@ static void keywords_ext_register(struct
 
 	if (ext_map_idx == (uint32_t)-1) {
 		u->name_size = strlen(MAIL_INDEX_EXT_KEYWORDS);
-		buffer_append(&ext_intro_buf, MAIL_INDEX_EXT_KEYWORDS,
+		buffer_append(&ext_intro_buf.buf, MAIL_INDEX_EXT_KEYWORDS,
 			      u->name_size);
 	}
 
diff --git a/src/lib-index/mail-index-transaction-export.c b/src/lib-index/mail-index-transaction-export.c
--- a/src/lib-index/mail-index-transaction-export.c
+++ b/src/lib-index/mail-index-transaction-export.c
@@ -247,7 +247,7 @@ mail_transaction_log_append_ext_intros(s
 	uint32_t ext_id, reset_id;
 	const struct mail_transaction_ext_reset *reset;
 	const uint32_t *reset_ids;
-	buffer_t reset_buf;
+	union static_buffer reset_buf;
 
 	if (!array_is_created(&t->ext_resizes)) {
 		resize = NULL;
@@ -285,7 +285,7 @@ mail_transaction_log_append_ext_intros(s
 
 	i_zero(&ext_reset);
 	buffer_create_from_data(&reset_buf, &ext_reset, sizeof(ext_reset));
-	buffer_set_used_size(&reset_buf, sizeof(ext_reset));
+	buffer_set_used_size(&reset_buf.buf, sizeof(ext_reset));
 
 	for (ext_id = 0; ext_id < ext_count; ext_id++) {
 		if (ext_id < reset_count)
@@ -310,7 +310,7 @@ mail_transaction_log_append_ext_intros(s
 		if (ext_reset.new_reset_id != 0) {
 			i_assert(ext_id < reset_id_count &&
 				 ext_reset.new_reset_id == reset_ids[ext_id]);
-			log_append_buffer(ctx, &reset_buf,
+			log_append_buffer(ctx, &reset_buf.buf,
 					  MAIL_TRANSACTION_EXT_RESET);
 		}
 		if (ext_id < hdrs_count && hdrs[ext_id].alloc_size > 0) {
diff --git a/src/lib-index/mail-transaction-log-append.c b/src/lib-index/mail-transaction-log-append.c
--- a/src/lib-index/mail-transaction-log-append.c
+++ b/src/lib-index/mail-transaction-log-append.c
@@ -120,7 +120,7 @@ log_append_sync_offset_if_needed(struct 
 	struct mail_transaction_header_update *u;
 	struct mail_transaction_header *hdr;
 	uint32_t offset;
-	buffer_t buf;
+	union static_buffer buf;
 	unsigned char update_data[sizeof(*u) + sizeof(offset)];
 
 	if (!ctx->index_sync_transaction) {
@@ -163,13 +163,13 @@ log_append_sync_offset_if_needed(struct 
 	i_assert(offset > file->saved_tail_offset);
 
 	buffer_create_from_data(&buf, update_data, sizeof(update_data));
-	u = buffer_append_space_unsafe(&buf, sizeof(*u));
+	u = buffer_append_space_unsafe(&buf.buf, sizeof(*u));
 	u->offset = offsetof(struct mail_index_header, log_file_tail_offset);
 	u->size = sizeof(offset);
-	buffer_append(&buf, &offset, sizeof(offset));
+	buffer_append(&buf.buf, &offset, sizeof(offset));
 
 	mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_HEADER_UPDATE,
-					buf.data, buf.used);
+					buf.buf.data, buf.buf.used);
 }
 
 static int
diff --git a/src/lib-index/mail-transaction-log-file.c b/src/lib-index/mail-transaction-log-file.c
--- a/src/lib-index/mail-transaction-log-file.c
+++ b/src/lib-index/mail-transaction-log-file.c
@@ -1769,7 +1769,7 @@ mail_transaction_log_file_mmap(struct ma
 
 	buffer_create_from_const_data(&file->mmap_buffer,
 				      file->mmap_base, file->mmap_size);
-	file->buffer = &file->mmap_buffer;
+	file->buffer = &file->mmap_buffer.buf;
 	file->buffer_offset = 0;
 	return 0;
 }
diff --git a/src/lib-index/mail-transaction-log-private.h b/src/lib-index/mail-transaction-log-private.h
--- a/src/lib-index/mail-transaction-log-private.h
+++ b/src/lib-index/mail-transaction-log-private.h
@@ -40,7 +40,7 @@ struct mail_transaction_log_file {
 	char *need_rotate;
 
 	struct mail_transaction_log_header hdr;
-	buffer_t mmap_buffer;
+	union static_buffer mmap_buffer;
 	buffer_t *buffer;
 	uoff_t buffer_offset;
 	void *mmap_base;
diff --git a/src/lib-index/mail-transaction-log-view.c b/src/lib-index/mail-transaction-log-view.c
--- a/src/lib-index/mail-transaction-log-view.c
+++ b/src/lib-index/mail-transaction-log-view.c
@@ -600,7 +600,7 @@ log_view_is_record_valid(struct mail_tra
 {
 	enum mail_transaction_type rec_type;
 	ARRAY_TYPE(seq_range) uids = ARRAY_INIT;
-	buffer_t uid_buf;
+	union static_buffer uid_buf;
 	uint32_t rec_size;
 
 	rec_type = hdr->type & MAIL_TRANSACTION_TYPE_MASK;
@@ -646,7 +646,7 @@ log_view_is_record_valid(struct mail_tra
 		break;
 	case MAIL_TRANSACTION_EXPUNGE:
 		buffer_create_from_const_data(&uid_buf, data, rec_size);
-		array_create_from_buffer(&uids, &uid_buf,
+		array_create_from_buffer(&uids, &uid_buf.buf,
 			sizeof(struct mail_transaction_expunge));
 		break;
 	case MAIL_TRANSACTION_EXPUNGE_GUID: {
@@ -670,7 +670,7 @@ log_view_is_record_valid(struct mail_tra
 	}
 	case MAIL_TRANSACTION_FLAG_UPDATE:
 		buffer_create_from_const_data(&uid_buf, data, rec_size);
-		array_create_from_buffer(&uids, &uid_buf,
+		array_create_from_buffer(&uids, &uid_buf.buf,
 			sizeof(struct mail_transaction_flag_update));
 		break;
 	case MAIL_TRANSACTION_KEYWORD_UPDATE: {
@@ -695,13 +695,13 @@ log_view_is_record_valid(struct mail_tra
 		buffer_create_from_const_data(&uid_buf,
 					 CONST_PTR_OFFSET(data, seqset_offset),
 					 rec_size - seqset_offset);
-		array_create_from_buffer(&uids, &uid_buf,
+		array_create_from_buffer(&uids, &uid_buf.buf,
 					 sizeof(uint32_t)*2);
 		break;
 	}
 	case MAIL_TRANSACTION_KEYWORD_RESET:
 		buffer_create_from_const_data(&uid_buf, data, rec_size);
-		array_create_from_buffer(&uids, &uid_buf,
+		array_create_from_buffer(&uids, &uid_buf.buf,
 			sizeof(struct mail_transaction_keyword_reset));
 		break;
 	case MAIL_TRANSACTION_EXT_INTRO: {
diff --git a/src/lib-index/test-mail-index-modseq.c b/src/lib-index/test-mail-index-modseq.c
--- a/src/lib-index/test-mail-index-modseq.c
+++ b/src/lib-index/test-mail-index-modseq.c
@@ -54,7 +54,7 @@ static void test_mail_index_modseq_get_n
 
 	view2 = mail_index_view_open(index);
 	for (uint64_t modseq = 1; modseq <= 7; modseq++) {
-		uint32_t log_seq;
+		uint32_t log_seq = 0;
 		uoff_t log_offset;
 
 		test_assert_idx(mail_index_modseq_get_next_log_offset(view2, modseq, &log_seq, &log_offset) == (tests[modseq].log_seq != 0), modseq);
diff --git a/src/lib-mail/istream-binary-converter.c b/src/lib-mail/istream-binary-converter.c
--- a/src/lib-mail/istream-binary-converter.c
+++ b/src/lib-mail/istream-binary-converter.c
@@ -84,7 +84,7 @@ static void stream_encode_base64(struct 
 {
 	struct istream_private *stream = &bstream->istream;
 	const unsigned char *data = _data;
-	buffer_t buf;
+	union static_buffer buf;
 	void *dest;
 	size_t encode_size, max_encoded_size;
 	unsigned char base64_block[BASE64_BLOCK_INPUT_SIZE];
@@ -119,8 +119,8 @@ static void stream_encode_base64(struct 
 
 		dest = i_stream_alloc(stream, BASE64_BLOCK_SIZE);
 		buffer_create_from_data(&buf, dest, BASE64_BLOCK_SIZE);
-		base64_encode(base64_block, base64_block_len, &buf);
-		stream->pos += buf.used;
+		base64_encode(base64_block, base64_block_len, &buf.buf);
+		stream->pos += buf.buf.used;
 		bstream->base64_block_pos++;
 		bstream->base64_delayed_len = 0;
 	}
@@ -146,8 +146,8 @@ static void stream_encode_base64(struct 
 		max_encoded_size = MAX_BASE64_ENCODED_SIZE(encode_size);
 		dest = i_stream_alloc(stream, max_encoded_size);
 		buffer_create_from_data(&buf, dest, max_encoded_size);
-		base64_encode(data, encode_size, &buf);
-		stream->pos += buf.used;
+		base64_encode(data, encode_size, &buf.buf);
+		stream->pos += buf.buf.used;
 		bstream->base64_block_pos += encode_blocks;
 
 		data += encode_size;
diff --git a/src/lib-mail/test-message-header-encode.c b/src/lib-mail/test-message-header-encode.c
--- a/src/lib-mail/test-message-header-encode.c
+++ b/src/lib-mail/test-message-header-encode.c
@@ -79,7 +79,7 @@ static bool verify_b(const char *str, un
 {
 	unsigned int line_start = i, start, j, char_count = 0;
 	char bufdata[1000];
-	buffer_t buf;
+	union static_buffer buf;
 
 	buffer_create_from_data(&buf, bufdata, sizeof(bufdata));
 	if (str_begins(str+i, "\n\t")) {
@@ -97,8 +97,8 @@ static bool verify_b(const char *str, un
 			if (str[i] == '\0')
 				return FALSE;
 		}
-		buffer_set_used_size(&buf, 0);
-		if (base64_decode(str+start, i-start, NULL, &buf) < 0)
+		buffer_set_used_size(&buf.buf, 0);
+		if (base64_decode(str+start, i-start, NULL, &buf.buf) < 0)
 			return FALSE;
 		i++;
 
@@ -110,12 +110,12 @@ static bool verify_b(const char *str, un
 			starts_with_a = FALSE;
 			j = 1;
 		}
-		for (; j < buf.used; j += 2) {
+		for (; j < buf.buf.used; j += 2) {
 			if (bufdata[j] != '\xc3' || bufdata[j+1] != '\xa4')
 				return FALSE;
 			char_count++;
 		}
-		if (j != buf.used)
+		if (j != buf.buf.used)
 			return FALSE;
 
 		if (str[i++] != '=')
diff --git a/src/lib-otp/otp-parse.c b/src/lib-otp/otp-parse.c
--- a/src/lib-otp/otp-parse.c
+++ b/src/lib-otp/otp-parse.c
@@ -35,7 +35,7 @@ static inline bool otp_check_tail(const 
 int otp_read_hex(const char *data, const char **endptr, unsigned char *hash)
 {
 	string_t *str;
-	buffer_t buf;
+	union static_buffer buf;
 	unsigned int i = 0;
 
 	if (data == NULL)
@@ -65,12 +65,12 @@ int otp_read_hex(const char *data, const
 	if (i < OTP_HASH_SIZE * 2)
 		return -1;
 
-	return hex_to_binary(str_c(str), &buf);
+	return hex_to_binary(str_c(str), &buf.buf);
 }
 
 #define add_word() do { \
 	tmp = otp_lookup_word(str_c(word)); \
-	buffer_append(&buf, &tmp, sizeof(tmp)); \
+	buffer_append(&buf.buf, &tmp, sizeof(tmp)); \
 	count++; \
 } while (0)
 
@@ -81,7 +81,7 @@ otp_read_words(const char *data, const c
 	unsigned int len = 0, count = 0;
 	unsigned int parity = 0, bits[OTP_WORDS_NUMBER], tmp;
 	string_t *word;
-	buffer_t buf;
+	union static_buffer buf;
 
 	if (data == NULL)
 		return -1;
diff --git a/src/lib-storage/index/index-mail.c b/src/lib-storage/index/index-mail.c
--- a/src/lib-storage/index/index-mail.c
+++ b/src/lib-storage/index/index-mail.c
@@ -205,14 +205,14 @@ static bool index_mail_get_fixed_field(s
 				       void *data, size_t data_size)
 {
 	const unsigned int field_idx = mail->ibox->cache_fields[field].idx;
-	buffer_t buf;
+	union static_buffer buf;
 	bool ret;
 
 	buffer_create_from_data(&buf, data, data_size);
-	if (index_mail_cache_lookup_field(mail, &buf, field_idx) <= 0)
+	if (index_mail_cache_lookup_field(mail, &buf.buf, field_idx) <= 0)
 		ret = FALSE;
 	else {
-		i_assert(buf.used == data_size);
+		i_assert(buf.buf.used == data_size);
 		ret = TRUE;
 	}
 	return ret;
diff --git a/src/lib-storage/mail.c b/src/lib-storage/mail.c
--- a/src/lib-storage/mail.c
+++ b/src/lib-storage/mail.c
@@ -467,17 +467,17 @@ void mail_set_cache_corrupted(struct mai
 void mail_generate_guid_128_hash(const char *guid, guid_128_t guid_128_r)
 {
 	unsigned char sha1_sum[SHA1_RESULTLEN];
-	buffer_t buf;
+	union static_buffer buf;
 
 	if (guid_128_from_string(guid, guid_128_r) < 0) {
 		/* not 128bit hex. use a hash of it instead. */
 		buffer_create_from_data(&buf, guid_128_r, GUID_128_SIZE);
-		buffer_set_used_size(&buf, 0);
+		buffer_set_used_size(&buf.buf, 0);
 		sha1_get_digest(guid, strlen(guid), sha1_sum);
 #if SHA1_RESULTLEN < GUID_128_SIZE
 #  error not possible
 #endif
-		buffer_append(&buf,
+		buffer_append(&buf.buf,
 			      sha1_sum + SHA1_RESULTLEN - GUID_128_SIZE,
 			      GUID_128_SIZE);
 	}
diff --git a/src/lib/askpass.c b/src/lib/askpass.c
--- a/src/lib/askpass.c
+++ b/src/lib/askpass.c
@@ -56,11 +56,11 @@ static void askpass_str(const char *prom
 
 void askpass(const char *prompt, char *buf, size_t buf_size)
 {
-	buffer_t str;
+	union static_buffer str;
 
 	buffer_create_from_data(&str, buf, buf_size);
-	askpass_str(prompt, &str);
-	buffer_append_c(&str, '\0');
+	askpass_str(prompt, &str.buf);
+	buffer_append_c(&str.buf, '\0');
 }
 
 const char *t_askpass(const char *prompt)
diff --git a/src/lib/buffer.c b/src/lib/buffer.c
--- a/src/lib/buffer.c
+++ b/src/lib/buffer.c
@@ -7,8 +7,7 @@
 
 struct real_buffer {
 	/* public: */
-	const unsigned char *r_buffer;
-	size_t used;
+	struct buffer buf;
 
 	/* private: */
 	unsigned char *w_buffer;
@@ -19,7 +18,7 @@ struct real_buffer {
 	bool alloced:1;
 	bool dynamic:1;
 };
-typedef int buffer_check_sizes[COMPILE_ERROR_IF_TRUE(sizeof(struct real_buffer) > sizeof(buffer_t)) ?1:1];
+typedef int buffer_check_sizes[COMPILE_ERROR_IF_TRUE(sizeof(struct real_buffer) != sizeof(union static_buffer)) ? 1 : 1];
 
 static void buffer_alloc(struct real_buffer *buf, size_t size)
 {
@@ -36,7 +35,7 @@ static void buffer_alloc(struct real_buf
 		buf->w_buffer = p_realloc(buf->pool, buf->w_buffer, buf->alloc, size);
 	buf->alloc = size;
 
-	buf->r_buffer = buf->w_buffer;
+	buf->buf.data = buf->w_buffer;
 	buf->alloced = TRUE;
 }
 
@@ -51,11 +50,11 @@ buffer_check_limits(struct real_buffer *
 
 	new_size = pos + data_size;
 
-	if (new_size > buf->used && buf->used < buf->dirty) {
+	if (new_size > buf->buf.used && buf->buf.used < buf->dirty) {
 		/* clear used..dirty area */
 		size_t max = I_MIN(I_MIN(buf->alloc, buf->dirty), new_size);
 
-		memset(buf->w_buffer + buf->used, 0, max - buf->used);
+		memset(buf->w_buffer + buf->buf.used, 0, max - buf->buf.used);
 	}
 
 	/* always keep +1 byte allocated available in case str_c() is called
@@ -75,7 +74,7 @@ buffer_check_limits(struct real_buffer *
 							  new_size + extra));
 	}
 #if 0
-	else if (new_size > buf->used && buf->alloced &&
+	else if (new_size > buf->buf.used && buf->alloced &&
 		 !buf->pool->alloconly_pool && !buf->pool->datastack_pool) {
 		void *new_buf;
 
@@ -87,27 +86,26 @@ buffer_check_limits(struct real_buffer *
 		p_free(buf->pool, buf->w_buffer);
 
 		buf->w_buffer = new_buf;
-		buf->r_buffer = new_buf;
+		buf->buf.data = new_buf;
 	}
 #endif
 
-	if (new_size > buf->used)
-		buf->used = new_size;
-	i_assert(buf->used <= buf->alloc);
+	if (new_size > buf->buf.used)
+		buf->buf.used = new_size;
+	i_assert(buf->buf.used <= buf->alloc);
 	i_assert(buf->w_buffer != NULL);
 }
 
 #undef buffer_create_from_data
-void buffer_create_from_data(buffer_t *buffer, void *data, size_t size)
+void buffer_create_from_data(union static_buffer *buffer,
+			     void *data, size_t size)
 {
 	struct real_buffer *buf;
 
-	i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
-
 	buf = (struct real_buffer *)buffer;
 	i_zero(buf);
 	buf->alloc = buf->max_size = size;
-	buf->r_buffer = buf->w_buffer = data;
+	buf->buf.data = 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
 	   memory */
@@ -115,18 +113,16 @@ void buffer_create_from_data(buffer_t *b
 }
 
 #undef buffer_create_from_const_data
-void buffer_create_from_const_data(buffer_t *buffer,
+void buffer_create_from_const_data(union static_buffer *buffer,
 				   const void *data, size_t size)
 {
 	struct real_buffer *buf;
 
-	i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
-
 	buf = (struct real_buffer *)buffer;
 	i_zero(buf);
 
-	buf->used = buf->alloc = buf->max_size = size;
-	buf->r_buffer = data;
+	buf->buf.used = buf->alloc = buf->max_size = size;
+	buf->buf.data = data;
 	i_assert(buf->w_buffer == NULL);
 }
 
@@ -218,7 +214,7 @@ void buffer_insert(buffer_t *_buf, size_
 {
 	struct real_buffer *buf = (struct real_buffer *)_buf;
 
-	if (pos >= buf->used)
+	if (pos >= buf->buf.used)
 		buffer_write(_buf, pos, data, data_size);
 	else {
 		buffer_copy(_buf, pos + data_size, _buf, pos, SIZE_MAX);
@@ -231,9 +227,9 @@ void buffer_delete(buffer_t *_buf, size_
 	struct real_buffer *buf = (struct real_buffer *)_buf;
 	size_t end_size;
 
-	if (pos >= buf->used)
+	if (pos >= buf->buf.used)
 		return;
-	end_size = buf->used - pos;
+	end_size = buf->buf.used - pos;
 
 	if (size < end_size) {
 		/* delete from between */
@@ -254,11 +250,11 @@ void buffer_replace(buffer_t *_buf, size
 	struct real_buffer *buf = (struct real_buffer *)_buf;
 	size_t end_size;
 
-	if (pos >= buf->used) {
+	if (pos >= buf->buf.used) {
 		buffer_write(_buf, pos, data, data_size);
 		return;
 	}
-	end_size = buf->used - pos;
+	end_size = buf->buf.used - pos;
 
 	if (size < end_size) {
 		end_size -= size;
@@ -299,7 +295,7 @@ void buffer_insert_zero(buffer_t *_buf, 
 {
 	struct real_buffer *buf = (struct real_buffer *)_buf;
 
-	if (pos >= buf->used)
+	if (pos >= buf->buf.used)
 		buffer_write_zero(_buf, pos, data_size);
 	else {
 		buffer_copy(_buf, pos + data_size, _buf, pos, SIZE_MAX);
@@ -314,21 +310,21 @@ void buffer_copy(buffer_t *_dest, size_t
 	const struct real_buffer *src = (const struct real_buffer *)_src;
 	size_t max_size;
 
-	i_assert(src_pos <= src->used);
+	i_assert(src_pos <= src->buf.used);
 
-	max_size = src->used - src_pos;
+	max_size = src->buf.used - src_pos;
 	if (copy_size > max_size)
 		copy_size = max_size;
 
 	buffer_check_limits(dest, dest_pos, copy_size);
-	i_assert(src->r_buffer != NULL);
+	i_assert(src->buf.data != NULL);
 
 	if (src == dest) {
 		memmove(dest->w_buffer + dest_pos,
-			src->r_buffer + src_pos, copy_size);
+			CONST_PTR_OFFSET(src->buf.data, src_pos), copy_size);
 	} else {
 		memcpy(dest->w_buffer + dest_pos,
-		       src->r_buffer + src_pos, copy_size);
+		       CONST_PTR_OFFSET(src->buf.data, src_pos), copy_size);
 	}
 }
 
@@ -356,8 +352,8 @@ void *buffer_get_modifiable_data(const b
 	const struct real_buffer *buf = (const struct real_buffer *)_buf;
 
 	if (used_size_r != NULL)
-		*used_size_r = buf->used;
-	i_assert(buf->used == 0 || buf->w_buffer != NULL);
+		*used_size_r = buf->buf.used;
+	i_assert(buf->buf.used == 0 || buf->w_buffer != NULL);
 	return buf->w_buffer;
 }
 
@@ -367,10 +363,10 @@ void buffer_set_used_size(buffer_t *_buf
 
 	i_assert(used_size <= buf->alloc);
 
-	if (buf->used > buf->dirty)
-		buf->dirty = buf->used;
+	if (buf->buf.used > buf->dirty)
+		buf->dirty = buf->buf.used;
 
-	buf->used = used_size;
+	buf->buf.used = used_size;
 }
 
 size_t buffer_get_size(const buffer_t *_buf)
@@ -398,8 +394,8 @@ size_t buffer_get_avail_size(const buffe
 {
 	const struct real_buffer *buf = (const struct real_buffer *)_buf;
 
-	i_assert(buf->alloc >= buf->used);
-	return ((buf->dynamic ? SIZE_MAX : buf->alloc) - buf->used);
+	i_assert(buf->alloc >= buf->buf.used);
+	return ((buf->dynamic ? SIZE_MAX : buf->alloc) - buf->buf.used);
 }
 
 bool buffer_cmp(const buffer_t *buf1, const buffer_t *buf2)
diff --git a/src/lib/buffer.h b/src/lib/buffer.h
--- a/src/lib/buffer.h
+++ b/src/lib/buffer.h
@@ -3,8 +3,12 @@
 
 struct buffer {
 	const void *data;
-	const size_t used;
-	void *priv[6];
+	size_t used;
+};
+
+union static_buffer {
+	struct buffer buf;
+	void *priv[8];
 };
 
 /* WARNING: Be careful with functions that return pointers to data.
@@ -14,9 +18,10 @@ struct buffer {
 
 /* Create a modifiable buffer from given data. Writes past this size will
    i_panic(). */
-void buffer_create_from_data(buffer_t *buffer, void *data, size_t size);
+void buffer_create_from_data(union static_buffer *buffer,
+			     void *data, size_t size);
 /* Create a non-modifiable buffer from given data. */
-void buffer_create_from_const_data(buffer_t *buffer,
+void buffer_create_from_const_data(union static_buffer *buffer,
 				   const void *data, size_t size);
 #define buffer_create_from_data(b,d,s) \
 	TYPE_CHECKS(void, \
diff --git a/src/lib/guid.c b/src/lib/guid.c
--- a/src/lib/guid.c
+++ b/src/lib/guid.c
@@ -111,12 +111,12 @@ bool guid_128_equals(const guid_128_t gu
 
 int guid_128_from_string(const char *str, guid_128_t guid_r)
 {
-	buffer_t buf;
+	union static_buffer buf;
 
 	buffer_create_from_data(&buf, guid_r, GUID_128_SIZE);
 	return strlen(str) == GUID_128_SIZE*2 &&
-		hex_to_binary(str, &buf) == 0 &&
-		buf.used == GUID_128_SIZE ? 0 : -1;
+		hex_to_binary(str, &buf.buf) == 0 &&
+		buf.buf.used == GUID_128_SIZE ? 0 : -1;
 }
 
 const char *guid_128_to_string(const guid_128_t guid)
diff --git a/src/lib/iostream-rawlog.c b/src/lib/iostream-rawlog.c
--- a/src/lib/iostream-rawlog.c
+++ b/src/lib/iostream-rawlog.c
@@ -25,21 +25,21 @@ static void
 rawlog_write_timestamp(struct rawlog_iostream *rstream, bool line_ends)
 {
 	unsigned char data[MAX_INT_STRLEN + 1 + 6 + 1 + 3];
-	buffer_t buf;
+	union static_buffer buf;
 
 	if ((rstream->flags & IOSTREAM_RAWLOG_FLAG_TIMESTAMP) == 0)
 		return;
 
 	buffer_create_from_data(&buf, data, sizeof(data));
-	str_printfa(&buf, "%"PRIdTIME_T".%06u ",
+	str_printfa(&buf.buf, "%"PRIdTIME_T".%06u ",
 		    ioloop_timeval.tv_sec,
 		    (unsigned int)ioloop_timeval.tv_usec);
 	if ((rstream->flags & IOSTREAM_RAWLOG_FLAG_BUFFERED) != 0) {
-		str_append_c(&buf, rstream->input ? 'I' : 'O');
-		str_append_c(&buf, line_ends ? ':' : '>');
-		str_append_c(&buf, ' ');
+		str_append_c(&buf.buf, rstream->input ? 'I' : 'O');
+		str_append_c(&buf.buf, line_ends ? ':' : '>');
+		str_append_c(&buf.buf, ' ');
 	}
-	o_stream_nsend(rstream->rawlog_output, buf.data, buf.used);
+	o_stream_nsend(rstream->rawlog_output, buf.buf.data, buf.buf.used);
 }
 
 void iostream_rawlog_init(struct rawlog_iostream *rstream,
diff --git a/src/lib/istream-base64-decoder.c b/src/lib/istream-base64-decoder.c
--- a/src/lib/istream-base64-decoder.c
+++ b/src/lib/istream-base64-decoder.c
@@ -40,7 +40,7 @@ i_stream_base64_try_decode_block(struct 
 	struct istream_private *stream = &bstream->istream;
 	const unsigned char *data;
 	size_t size, avail, pos;
-	buffer_t buf;
+	union static_buffer buf;
 
 	data = i_stream_get_data(stream->parent, &size);
 	if (size == 0)
@@ -50,7 +50,7 @@ i_stream_base64_try_decode_block(struct 
 		return -2;
 
 	buffer_create_from_data(&buf, stream->w_buffer + stream->pos, avail);
-	if (base64_decode_more(&bstream->decoder, data, size, &pos, &buf) < 0) {
+	if (base64_decode_more(&bstream->decoder, data, size, &pos, &buf.buf) < 0) {
 		io_stream_set_error(&stream->iostream,
 			"Invalid base64 data: 0x%s",
 			binary_to_hex(data+pos, I_MIN(size-pos, 8)));
@@ -58,7 +58,7 @@ i_stream_base64_try_decode_block(struct 
 		return -1;
 	}
 
-	stream->pos += buf.used;
+	stream->pos += buf.buf.used;
 	i_stream_skip(stream->parent, pos);
 	return pos > 0 ? 1 : 0;
 }
diff --git a/src/lib/istream-base64-encoder.c b/src/lib/istream-base64-encoder.c
--- a/src/lib/istream-base64-encoder.c
+++ b/src/lib/istream-base64-encoder.c
@@ -38,7 +38,7 @@ i_stream_base64_try_encode(struct base64
 	struct base64_encoder *b64enc = &bstream->encoder;
 	const unsigned char *data;
 	size_t size, pos, out_size, avail;
-	buffer_t buf;
+	union static_buffer buf;
 
 	data = i_stream_get_data(stream->parent, &size);
 	if (size == 0)
@@ -49,10 +49,10 @@ i_stream_base64_try_encode(struct base64
 		return -2;
 
 	buffer_create_from_data(&buf, stream->w_buffer + stream->pos, avail);
-	base64_encode_more(b64enc, data, size, &pos, &buf);
-	i_assert(buf.used > 0);
+	base64_encode_more(b64enc, data, size, &pos, &buf.buf);
+	i_assert(buf.buf.used > 0);
 
-	stream->pos += buf.used;
+	stream->pos += buf.buf.used;
 	i_stream_skip(stream->parent, pos);
 	return 1;
 }
@@ -63,7 +63,7 @@ i_stream_base64_finish_encode(struct bas
 	struct istream_private *stream = &bstream->istream;
 	struct base64_encoder *b64enc = &bstream->encoder;
 	size_t out_size, buffer_avail;
-	buffer_t buf;
+	union static_buffer buf;
 
 	out_size = base64_encode_get_size(b64enc, 0);
 	if (out_size == 0) {
@@ -77,11 +77,11 @@ i_stream_base64_finish_encode(struct bas
 
 	buffer_create_from_data(&buf, stream->w_buffer + stream->pos,
 				buffer_avail);
-	if (base64_encode_finish(b64enc, &buf))
+	if (base64_encode_finish(b64enc, &buf.buf))
 		stream->istream.eof = TRUE;
-	i_assert(buf.used > 0);
+	i_assert(buf.buf.used > 0);
 
-	stream->pos += buf.used;
+	stream->pos += buf.buf.used;
 	return 1;
 }
 
diff --git a/src/lib/istream-jsonstr.c b/src/lib/istream-jsonstr.c
--- a/src/lib/istream-jsonstr.c
+++ b/src/lib/istream-jsonstr.c
@@ -79,7 +79,7 @@ i_stream_json_unescape(const unsigned ch
 	case 'u': {
 		char chbuf[5] = {0};
 		unichar_t chr,chr2 = 0;
-		buffer_t buf;
+		union static_buffer buf;
 		if (len < 5)
 			return 5;
 		buffer_create_from_data(&buf, dest, MAX_UTF8_LEN);
@@ -103,9 +103,9 @@ i_stream_json_unescape(const unsigned ch
 		}
 		if (!uni_is_valid_ucs4(chr))
 			return -1;
-		uni_ucs4_to_utf8_c(chr, &buf);
+		uni_ucs4_to_utf8_c(chr, &buf.buf);
 		*src_size_r = 5 + (chr2>0?6:0);
-		*dest_size_r = buf.used;
+		*dest_size_r = buf.buf.used;
 		return 0;
 	}
 	default:
diff --git a/src/lib/str.c b/src/lib/str.c
--- a/src/lib/str.c
+++ b/src/lib/str.c
@@ -18,14 +18,14 @@ string_t *str_new(pool_t pool, size_t in
 
 string_t *str_new_const(pool_t pool, const char *str, size_t len)
 {
-	string_t *ret;
+	union static_buffer *ret;
 
 	i_assert(str[len] == '\0');
 
-	ret = p_new(pool, buffer_t, 1);
+	ret = p_new(pool, union static_buffer, 1);
 	buffer_create_from_const_data(ret, str, len + 1);
-	str_truncate(ret, len);
-	return ret;
+	str_truncate(&ret->buf, len);
+	return &ret->buf;
 }
 
 string_t *t_str_new(size_t initial_size)
diff --git a/src/lib/test-array.c b/src/lib/test-array.c
--- a/src/lib/test-array.c
+++ b/src/lib/test-array.c
@@ -359,26 +359,26 @@ enum fatal_test_state fatal_array(unsign
 	}
 	case 3: {
 		ARRAY(uint8_t) arr;
-		uint8_t value = 0;
+		uint8_t *value = t_malloc0(1);
 
 		t_array_init(&arr, 2);
-		array_push_back(&arr, &value);
+		array_push_back(&arr, value);
 		test_expect_fatal_string("Buffer write out of range");
 		/* this is supposed to assert-crash before it even attempts to
 		   access value */
-		array_append(&arr, &value, UINT_MAX);
+		array_append(&arr, value, UINT_MAX);
 		return FATAL_TEST_FAILURE;
 	}
 	case 4: {
 		ARRAY(uint32_t) arr;
-		uint32_t value = 0;
+		uint32_t *value = t_malloc0(1);
 
 		t_array_init(&arr, 2);
-		array_push_back(&arr, &value);
+		array_push_back(&arr, value);
 		test_expect_fatal_string("Buffer write out of range");
 		/* this is supposed to assert-crash before it even attempts to
 		   access value */
-		array_append(&arr, &value, UINT_MAX);
+		array_append(&arr, value, UINT_MAX);
 		return FATAL_TEST_FAILURE;
 	}
 	}
diff --git a/src/lib/test-base64.c b/src/lib/test-base64.c
--- a/src/lib/test-base64.c
+++ b/src/lib/test-base64.c
@@ -66,7 +66,7 @@ static void test_base64_decode(void)
 		  "\x81\xd1\x82\x2e", 0 },
 	};
 	string_t *str;
-	buffer_t buf;
+	union static_buffer buf;
 	unsigned int i;
 	int ret;
 
@@ -83,7 +83,7 @@ static void test_base64_decode(void)
 					(max_decoded_size == 0 ? NULL :
 					 t_malloc0(max_decoded_size)),
 					max_decoded_size);
-		str = &buf;
+		str = &buf.buf;
 		ret = base64_decode(tests[i].input, strlen(tests[i].input),
 				    NULL, str);
 
@@ -190,7 +190,7 @@ static void test_base64url_decode(void)
 		  "\x81\xd1\x82\x2e", 0 },
 	};
 	string_t *str;
-	buffer_t buf;
+	union static_buffer buf;
 	unsigned int i;
 	int ret;
 
@@ -207,7 +207,7 @@ static void test_base64url_decode(void)
 					(max_decoded_size == 0 ? NULL :
 					 t_malloc0(max_decoded_size)),
 					max_decoded_size);
-		str = &buf;
+		str = &buf.buf;
 		ret = base64url_decode(0, tests[i].input,
 				       strlen(tests[i].input), str);
 
@@ -865,7 +865,7 @@ tests_base64_decode_lowlevel[] = {
 static void test_base64_decode_lowlevel(void)
 {
 	string_t *str;
-	buffer_t buf;
+	union static_buffer buf;
 	unsigned int i;
 
 	test_begin("base64 decode low-level");
@@ -887,7 +887,7 @@ static void test_base64_decode_lowlevel(
 					(max_decoded_size == 0 ? NULL :
 					 t_malloc0(max_decoded_size)),
 					max_decoded_size);
-		str = &buf;
+		str = &buf.buf;
 		base64_decode_init(&dec, test->scheme, test->flags);
 		ret = base64_decode_more(&dec, test->input, strlen(test->input),
 					 &src_pos, str);
@@ -924,7 +924,7 @@ test_base64_random_lowlevel_one_block(co
 	struct base64_decoder dec;
 	void *space;
 	size_t enc_size;
-	buffer_t buf;
+	union static_buffer buf;
 	int ret;
 
 	buffer_set_used_size(buf1, 0);
@@ -935,9 +935,9 @@ test_base64_random_lowlevel_one_block(co
 	space = buffer_append_space_unsafe(buf1, enc_size);
 	buffer_create_from_data(&buf, space, enc_size);
 
-	if (!base64_encode_more(&enc, in_buf, in_buf_size, NULL, &buf))
+	if (!base64_encode_more(&enc, in_buf, in_buf_size, NULL, &buf.buf))
 		test_assert_idx(FALSE, test_idx);
-	if (!base64_encode_finish(&enc, &buf))
+	if (!base64_encode_finish(&enc, &buf.buf))
 		test_assert_idx(FALSE, test_idx);
 
 	test_assert(base64_get_full_encoded_size(&enc, in_buf_size) ==
@@ -947,7 +947,7 @@ test_base64_random_lowlevel_one_block(co
 	space = buffer_append_space_unsafe(buf2, in_buf_size);
 	buffer_create_from_data(&buf, space, in_buf_size);
 
-	ret = base64_decode_more(&dec, buf1->data, buf1->used, NULL, &buf);
+	ret = base64_decode_more(&dec, buf1->data, buf1->used, NULL, &buf.buf);
 	if (ret >= 0)
 		ret = base64_decode_finish(&dec);
 
@@ -972,7 +972,7 @@ test_base64_random_lowlevel_stream(const
 	int ret;
 	size_t out_space, out_full_size;
 	void *out_data;
-	buffer_t out;
+	union static_buffer out;
 
 	/* Encode */
 
@@ -1013,14 +1013,14 @@ test_base64_random_lowlevel_stream(const
 
 		out_size = base64_encode_get_size(&enc, buf_ch);
 
-		eres = base64_encode_more(&enc, buf_p, buf_ch, &src_pos, &out);
+		eres = base64_encode_more(&enc, buf_p, buf_ch, &src_pos, &out.buf);
 		test_assert_idx((eres && src_pos == buf_ch) ||
 				(!eres && src_pos < buf_ch), test_idx);
-		test_assert_idx(out.used <= out_size, test_idx);
+		test_assert_idx(out.buf.used <= out_size, test_idx);
 		buf_p += src_pos;
-		i_assert(out_space >= out.used);
-		out_space -= out.used;
-		buffer_set_used_size(buf1, used + out.used);
+		i_assert(out_space >= out.buf.used);
+		out_space -= out.buf.used;
+		buffer_set_used_size(buf1, used + out.buf.used);
 	}
 	test_assert_idx(base64_encode_finish(&enc, buf1), test_idx);
 
@@ -1066,15 +1066,15 @@ test_base64_random_lowlevel_stream(const
 		if (buf_ch > left)
 			buf_ch = left;
 		ret = base64_decode_more(&dec, buf_p, buf_ch,
-					 &src_pos, &out);
+					 &src_pos, &out.buf);
 		test_assert_idx(ret >= 0, test_idx);
 		if (ret < 0) {
 			break;
 		}
 		buf_p += src_pos;
-		i_assert(out_space >= out.used);
-		out_space -= out.used;
-		buffer_set_used_size(buf2, used + out.used);
+		i_assert(out_space >= out.buf.used);
+		out_space -= out.buf.used;
+		buffer_set_used_size(buf2, used + out.buf.used);
 	}
 	test_assert_idx(ret >= 0, test_idx);
 
diff --git a/src/lib/test-buffer.c b/src/lib/test-buffer.c
--- a/src/lib/test-buffer.c
+++ b/src/lib/test-buffer.c
@@ -231,56 +231,56 @@ static void test_buffer_truncate_bits(vo
 	test_begin("buffer_test_truncate_bits");
 
 	struct {
-		buffer_t input;
+		union static_buffer input;
 		size_t bits;
-		buffer_t output;
+		union static_buffer output;
 	} test_cases[] = {
-                { { "\xff\xff\xff", 3, {0} },  0, { "",  0, {0} } },
-                { { "\xff\xff\xff", 3, {0} },  1, { "\x01", 1, {0} } },
-                { { "\xff\xff\xff", 3, {0} },  2, { "\x03", 1, {0} } },
-                { { "\xff\xff\xff", 3, {0} },  3, { "\x07", 1, {0} } },
-                { { "\xff\xff\xff", 3, {0} },  4, { "\x0f", 1, {0} } },
-                { { "\xff\xff\xff", 3, {0} },  5, { "\x1f", 1, {0} } },
-                { { "\xff\xff\xff", 3, {0} },  6, { "\x3f", 1, {0} } },
-                { { "\xff\xff\xff", 3, {0} },  7, { "\x7f", 1, {0} } },
-                { { "\xff\xff\xff", 3, {0} },  8, { "\xff", 1, {0} } },
-                { { "\xff\xff\xff", 3, {0} },  9, { "\x01\xff", 2, {0} } },
-                { { "\xff\xff\xff", 3, {0} }, 10, { "\x03\xff", 2, {0} } },
-                { { "\xff\xff\xff", 3, {0} }, 11, { "\x07\xff", 2, {0} } },
-                { { "\xff\xff\xff", 3, {0} }, 12, { "\x0f\xff", 2, {0} } },
-                { { "\xff\xff\xff", 3, {0} }, 13, { "\x1f\xff", 2, {0} } },
-                { { "\xff\xff\xff", 3, {0} }, 14, { "\x3f\xff", 2, {0} } },
-                { { "\xff\xff\xff", 3, {0} }, 15, { "\x7f\xff", 2, {0} } },
-                { { "0123456789", 10, {0} }, 16, { "01",  2, {0} } },
-                { { "0123456789", 10, {0} }, 24, { "012",  3, {0} } },
-                { { "0123456789", 10, {0} }, 32, { "0123",  4, {0} } },
-                { { "0123456789", 10, {0} }, 40, { "01234",  5, {0} } },
-                { { "0123456789", 10, {0} }, 48, { "012345",  6, {0} } },
-                { { "0123456789", 10, {0} }, 56, { "0123456",  7, {0} } },
-                { { "0123456789", 10, {0} }, 64, { "01234567",  8, {0} } },
-                { { "0123456789", 10, {0} }, 72, { "012345678",  9, {0} } },
-		{ { "0123456789", 10, {0} }, 80, { "0123456789", 10, {0} } },
+                { .input.buf = { "\xff\xff\xff", 3 },  0, .output.buf = { "",  0 } },
+                { .input.buf = { "\xff\xff\xff", 3 },  1, .output.buf = { "\x01", 1 } },
+                { .input.buf = { "\xff\xff\xff", 3 },  2, .output.buf = { "\x03", 1 } },
+                { .input.buf = { "\xff\xff\xff", 3 },  3, .output.buf = { "\x07", 1 } },
+                { .input.buf = { "\xff\xff\xff", 3 },  4, .output.buf = { "\x0f", 1 } },
+                { .input.buf = { "\xff\xff\xff", 3 },  5, .output.buf = { "\x1f", 1 } },
+                { .input.buf = { "\xff\xff\xff", 3 },  6, .output.buf = { "\x3f", 1 } },
+                { .input.buf = { "\xff\xff\xff", 3 },  7, .output.buf = { "\x7f", 1 } },
+                { .input.buf = { "\xff\xff\xff", 3 },  8, .output.buf = { "\xff", 1 } },
+                { .input.buf = { "\xff\xff\xff", 3 },  9, .output.buf = { "\x01\xff", 2 } },
+                { .input.buf = { "\xff\xff\xff", 3 }, 10, .output.buf = { "\x03\xff", 2 } },
+                { .input.buf = { "\xff\xff\xff", 3 }, 11, .output.buf = { "\x07\xff", 2 } },
+                { .input.buf = { "\xff\xff\xff", 3 }, 12, .output.buf = { "\x0f\xff", 2 } },
+                { .input.buf = { "\xff\xff\xff", 3 }, 13, .output.buf = { "\x1f\xff", 2 } },
+                { .input.buf = { "\xff\xff\xff", 3 }, 14, .output.buf = { "\x3f\xff", 2 } },
+                { .input.buf = { "\xff\xff\xff", 3 }, 15, .output.buf = { "\x7f\xff", 2 } },
+                { .input.buf = { "0123456789", 10 }, 16, .output.buf = { "01",  2 } },
+                { .input.buf = { "0123456789", 10 }, 24, .output.buf = { "012",  3 } },
+                { .input.buf = { "0123456789", 10 }, 32, .output.buf = { "0123",  4 } },
+                { .input.buf = { "0123456789", 10 }, 40, .output.buf = { "01234",  5 } },
+                { .input.buf = { "0123456789", 10 }, 48, .output.buf = { "012345",  6 } },
+                { .input.buf = { "0123456789", 10 }, 56, .output.buf = { "0123456",  7 } },
+                { .input.buf = { "0123456789", 10 }, 64, .output.buf = { "01234567",  8 } },
+                { .input.buf = { "0123456789", 10 }, 72, .output.buf = { "012345678",  9 } },
+		{ .input.buf = { "0123456789", 10 }, 80, .output.buf = { "0123456789", 10 } },
 
-		{ { "\x58\x11\xed\x02\x4d\x87\x4a\xe2\x5c\xb2\xfa\x69\xf0\xa9\x46\x2e\x04\xca\x5d\x82", 20, {0} },
+		{ .input.buf = { "\x58\x11\xed\x02\x4d\x87\x4a\xe2\x5c\xb2\xfa\x69\xf0\xa9\x46\x2e\x04\xca\x5d\x82", 20 },
 		  13,
-		  { "\x0b\x02", 2, {0} }
+		  .output.buf = { "\x0b\x02", 2 }
 		},
 
 		/* special test cases for auth policy */
 
-		{ { "\x34\x40\xc8\xc9\x3a\xb6\xe7\xc4\x3f\xc1\xc3\x4d\xd5\x56\xa3\xea\xfb\x5a\x33\x57\xac\x11\x39\x2c\x71\xcb\xee\xbb\xc8\x66\x2f\x64", 32, {0} },
+		{ .input.buf = { "\x34\x40\xc8\xc9\x3a\xb6\xe7\xc4\x3f\xc1\xc3\x4d\xd5\x56\xa3\xea\xfb\x5a\x33\x57\xac\x11\x39\x2c\x71\xcb\xee\xbb\xc8\x66\x2f\x64", 32 },
 		  12,
-		  { "\x03\x44", 2, {0} }
+		  .output.buf = { "\x03\x44", 2 }
 		},
 
-		{ { "\x49\xe5\x8a\x88\x76\xd3\x25\x68\xc9\x89\x4a\xe0\x64\xe4\x04\xf4\xf9\x13\xec\x88\x97\x47\x30\x7f\x3f\xcd\x8f\x74\x4f\x40\xd1\x25", 32, {0} },
+		{ .input.buf = { "\x49\xe5\x8a\x88\x76\xd3\x25\x68\xc9\x89\x4a\xe0\x64\xe4\x04\xf4\xf9\x13\xec\x88\x97\x47\x30\x7f\x3f\xcd\x8f\x74\x4f\x40\xd1\x25", 32 },
                   12,
-                  { "\x04\x9e", 2, {0} }
+                  .output.buf = { "\x04\x9e", 2 }
                 },
 
-		{ { "\x08\x3c\xdc\x14\x61\x80\x1c\xe8\x43\x81\x98\xfa\xc0\x64\x04\x7a\xa2\x73\x25\x6e\xe6\x4b\x85\x42\xd0\xe2\x78\xd7\x91\xb4\x89\x3f", 32, {0} },
+		{ .input.buf = { "\x08\x3c\xdc\x14\x61\x80\x1c\xe8\x43\x81\x98\xfa\xc0\x64\x04\x7a\xa2\x73\x25\x6e\xe6\x4b\x85\x42\xd0\xe2\x78\xd7\x91\xb4\x89\x3f", 32 },
                   12,
-                  { "\x00\x83", 2, {0} }
+                  .output.buf = { "\x00\x83", 2 }
                 },
 
 	};
@@ -289,9 +289,9 @@ static void test_buffer_truncate_bits(vo
 
 	for(size_t i = 0; i < N_ELEMENTS(test_cases); i++) {
 		buffer_set_used_size(buf, 0);
-		buffer_copy(buf, 0, &test_cases[i].input, 0, SIZE_MAX);
+		buffer_copy(buf, 0, &test_cases[i].input.buf, 0, SIZE_MAX);
 		buffer_truncate_rshift_bits(buf, test_cases[i].bits);
-		test_assert_idx(buffer_cmp(buf, &test_cases[i].output) == TRUE, i);
+		test_assert_idx(buffer_cmp(buf, &test_cases[i].output.buf) == TRUE, i);
 	}
 
 	test_end();
diff --git a/src/lib/test-strnum.c b/src/lib/test-strnum.c
--- a/src/lib/test-strnum.c
+++ b/src/lib/test-strnum.c
@@ -183,7 +183,7 @@ static void test_str_to_uintmax_oct(void
 	test_begin("str_to_uintmax_oct in range");
 	while (i < sizeof(uintmax_t)*CHAR_BIT) {
 		uintmax_t value_back;
-		const char *endp;
+		const char *endp = NULL;
 
 		value = (value << 1) + 1;
 		if (value >= 64)
diff --git a/src/lib/test-time-util.c b/src/lib/test-time-util.c
--- a/src/lib/test-time-util.c
+++ b/src/lib/test-time-util.c
@@ -288,7 +288,7 @@ static void test_timestamp(const char *t
 
 	/* %G - ISO 8601 year */
 	test_assert_idx(strlen(t[0]) == 4, idx);
-	unsigned v;
+	unsigned v = 0;
 	test_assert_idx(str_to_uint(t[0], &v) == 0, idx);
 	test_assert_idx(1000 <= v, idx);
 	test_assert_idx(v <= 3000, idx);
diff --git a/src/lmtp/lmtp-settings.c b/src/lmtp/lmtp-settings.c
--- a/src/lmtp/lmtp-settings.c
+++ b/src/lmtp/lmtp-settings.c
@@ -23,8 +23,8 @@ static struct file_listener_settings lmt
 static struct file_listener_settings *lmtp_unix_listeners[] = {
 	&lmtp_unix_listeners_array[0]
 };
-static buffer_t lmtp_unix_listeners_buf = {
-	lmtp_unix_listeners, sizeof(lmtp_unix_listeners), { NULL, }
+static union static_buffer lmtp_unix_listeners_buf = {
+	.buf = { lmtp_unix_listeners, sizeof(lmtp_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -48,7 +48,7 @@ struct service_settings lmtp_service_set
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &lmtp_unix_listeners_buf,
+	.unix_listeners = { { &lmtp_unix_listeners_buf.buf,
 			      sizeof(lmtp_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/log/log-settings.c b/src/log/log-settings.c
--- a/src/log/log-settings.c
+++ b/src/log/log-settings.c
@@ -14,9 +14,8 @@ static struct file_listener_settings log
 static struct file_listener_settings *log_unix_listeners[] = {
 	&log_unix_listeners_array[0]
 };
-static buffer_t log_unix_listeners_buf = {
-	log_unix_listeners,
-	sizeof(log_unix_listeners), { NULL, }
+static union static_buffer log_unix_listeners_buf = {
+	.buf = { log_unix_listeners, sizeof(log_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -40,7 +39,7 @@ struct service_settings log_service_sett
 	.idle_kill = UINT_MAX,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &log_unix_listeners_buf,
+	.unix_listeners = { { &log_unix_listeners_buf.buf,
 			      sizeof(log_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT,
diff --git a/src/login-common/sasl-server.c b/src/login-common/sasl-server.c
--- a/src/login-common/sasl-server.c
+++ b/src/login-common/sasl-server.c
@@ -253,7 +253,7 @@ anvil_check_too_many_connections(struct 
 {
 	struct anvil_request *req;
 	const char *query, *cookie;
-	buffer_t buf;
+	union static_buffer buf;
 
 	req = i_new(struct anvil_request, 1);
 	req->client = client;
@@ -262,7 +262,7 @@ anvil_check_too_many_connections(struct 
 	buffer_create_from_data(&buf, req->cookie, sizeof(req->cookie));
 	cookie = auth_client_request_get_cookie(request);
 	if (strlen(cookie) == MASTER_AUTH_COOKIE_SIZE*2)
-		(void)hex_to_binary(cookie, &buf);
+		(void)hex_to_binary(cookie, &buf.buf);
 
 	if (client->virtual_user == NULL ||
 	    client->set->mail_max_userip_connections == 0) {
diff --git a/src/master/master-settings.c b/src/master/master-settings.c
--- a/src/master/master-settings.c
+++ b/src/master/master-settings.c
@@ -228,7 +228,7 @@ static const struct master_settings mast
 #ifndef CONFIG_BINARY
 	.services = ARRAY_INIT
 #else
-	.services = { { &config_all_services_buf,
+	.services = { { &config_all_services_buf.buf,
 			     sizeof(struct service_settings *) } },
 #endif
 };
diff --git a/src/old-stats/stats-settings.c b/src/old-stats/stats-settings.c
--- a/src/old-stats/stats-settings.c
+++ b/src/old-stats/stats-settings.c
@@ -13,8 +13,8 @@ static struct file_listener_settings old
 static struct file_listener_settings *old_stats_unix_listeners[] = {
 	&old_stats_unix_listeners_array[0]
 };
-static buffer_t old_stats_unix_listeners_buf = {
-	old_stats_unix_listeners, sizeof(old_stats_unix_listeners), { NULL, }
+static union static_buffer old_stats_unix_listeners_buf = {
+	.buf = { old_stats_unix_listeners, sizeof(old_stats_unix_listeners) }
 };
 static struct file_listener_settings old_stats_fifo_listeners_array[] = {
 	{ "old-stats-mail", 0600, "", "" },
@@ -24,9 +24,8 @@ static struct file_listener_settings *ol
 	&old_stats_fifo_listeners_array[0],
 	&old_stats_fifo_listeners_array[1]
 };
-static buffer_t old_stats_fifo_listeners_buf = {
-	old_stats_fifo_listeners,
-	sizeof(old_stats_fifo_listeners), { NULL, }
+static union static_buffer old_stats_fifo_listeners_buf = {
+	.buf = { old_stats_fifo_listeners, sizeof(old_stats_fifo_listeners) }
 };
 /* </settings checks> */
 
@@ -50,9 +49,9 @@ struct service_settings old_stats_servic
 	.idle_kill = UINT_MAX,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &old_stats_unix_listeners_buf,
+	.unix_listeners = { { &old_stats_unix_listeners_buf.buf,
 			      sizeof(old_stats_unix_listeners[0]) } },
-	.fifo_listeners = { { &old_stats_fifo_listeners_buf,
+	.fifo_listeners = { { &old_stats_fifo_listeners_buf.buf,
 			      sizeof(old_stats_fifo_listeners[0]) } },
 	.inet_listeners = ARRAY_INIT,
 
diff --git a/src/plugins/fts-lucene/Snowball.cc b/src/plugins/fts-lucene/Snowball.cc
--- a/src/plugins/fts-lucene/Snowball.cc
+++ b/src/plugins/fts-lucene/Snowball.cc
@@ -116,10 +116,10 @@ CL_NS_DEF2(analysis,snowball)
 	unsigned char utf8text[LUCENE_MAX_WORD_LEN*5+1];
 	unsigned int len = I_MIN(LUCENE_MAX_WORD_LEN, token->termLength());
 
-	buffer_t buf = { 0, 0, { 0, 0, 0, 0, 0 } };
+	union static_buffer buf;
 	i_assert(sizeof(wchar_t) == sizeof(unichar_t));
 	buffer_create_from_data(&buf, utf8text, sizeof(utf8text));
-	uni_ucs4_to_utf8((const unichar_t *)token->termBuffer(), len, &buf);
+	uni_ucs4_to_utf8((const unichar_t *)token->termBuffer(), len, &buf.buf);
 
     const sb_symbol* stemmed = sb_stemmer_stem(stemmer, utf8text, buf.used);
 	if ( stemmed == NULL )
diff --git a/src/plugins/fts-lucene/fts-backend-lucene.c b/src/plugins/fts-lucene/fts-backend-lucene.c
--- a/src/plugins/fts-lucene/fts-backend-lucene.c
+++ b/src/plugins/fts-lucene/fts-backend-lucene.c
@@ -87,7 +87,7 @@ fts_backend_select(struct lucene_fts_bac
 	guid_128_t guid;
 	unsigned char guid_hex[MAILBOX_GUID_HEX_LENGTH];
 	wchar_t wguid_hex[MAILBOX_GUID_HEX_LENGTH];
-	buffer_t buf;
+	union static_buffer buf;
 	unsigned int i;
 
 	i_assert(box != NULL);
@@ -99,7 +99,7 @@ fts_backend_select(struct lucene_fts_bac
 	if (fts_lucene_get_mailbox_guid(box, guid) < 0)
 		return -1;
 	buffer_create_from_data(&buf, guid_hex, MAILBOX_GUID_HEX_LENGTH);
-	binary_to_hex_append(&buf, guid, GUID_128_SIZE);
+	binary_to_hex_append(&buf.buf, guid, GUID_128_SIZE);
 	for (i = 0; i < N_ELEMENTS(wguid_hex); i++)
 		wguid_hex[i] = guid_hex[i];
 
diff --git a/src/plugins/fts-lucene/lucene-wrapper.cc b/src/plugins/fts-lucene/lucene-wrapper.cc
--- a/src/plugins/fts-lucene/lucene-wrapper.cc
+++ b/src/plugins/fts-lucene/lucene-wrapper.cc
@@ -215,12 +215,12 @@ void lucene_utf8_n_to_tchar(const unsign
 			    wchar_t *dest, size_t destsize)
 {
 	ARRAY_TYPE(unichars) dest_arr;
-	buffer_t buf = { 0, 0, { 0, 0, 0, 0, 0 } };
+	union static_buffer buf;
 
 	i_assert(sizeof(wchar_t) == sizeof(unichar_t));
 
 	buffer_create_from_data(&buf, dest, sizeof(wchar_t) * destsize);
-	array_create_from_buffer(&dest_arr, &buf, sizeof(wchar_t));
+	array_create_from_buffer(&dest_arr, &buf.buf, sizeof(wchar_t));
 	if (uni_utf8_to_ucs4_n(src, srcsize, &dest_arr) < 0)
 		i_unreached();
 	i_assert(array_count(&dest_arr)+1 == destsize);
@@ -656,7 +656,7 @@ int lucene_index_build_deinit(struct luc
 static int
 wcharguid_to_guid(guid_128_t dest, const wchar_t *src)
 {
-	buffer_t buf = { 0, 0, { 0, 0, 0, 0, 0 } };
+	union static_buffer buf;
 	char src_chars[GUID_128_SIZE*2 + 1];
 	unsigned int i;
 
@@ -672,7 +672,7 @@ wcharguid_to_guid(guid_128_t dest, const
 	src_chars[i] = '\0';
 
 	buffer_create_from_data(&buf, dest, GUID_128_SIZE);
-	return hex_to_binary(src_chars, &buf);
+	return hex_to_binary(src_chars, &buf.buf);
 }
 
 static int
@@ -926,12 +926,12 @@ int lucene_index_rescan(struct lucene_in
 static void guid128_to_wguid(const guid_128_t guid,
 			     wchar_t wguid_hex[MAILBOX_GUID_HEX_LENGTH + 1])
 {
-	buffer_t buf = { 0, 0, { 0, 0, 0, 0, 0 } };
+	union static_buffer buf;
 	unsigned char guid_hex[MAILBOX_GUID_HEX_LENGTH];
 	unsigned int i;
 
 	buffer_create_from_data(&buf, guid_hex, MAILBOX_GUID_HEX_LENGTH);
-	binary_to_hex_append(&buf, guid, GUID_128_SIZE);
+	binary_to_hex_append(&buf.buf, guid, GUID_128_SIZE);
 	for (i = 0; i < MAILBOX_GUID_HEX_LENGTH; i++)
 		wguid_hex[i] = guid_hex[i];
 	wguid_hex[i] = '\0';
diff --git a/src/plugins/fts/fts-expunge-log.c b/src/plugins/fts/fts-expunge-log.c
--- a/src/plugins/fts/fts-expunge-log.c
+++ b/src/plugins/fts/fts-expunge-log.c
@@ -56,7 +56,7 @@ struct fts_expunge_log_read_ctx {
 	struct fts_expunge_log *log;
 
 	struct istream *input;
-	buffer_t buffer;
+	union static_buffer buffer;
 	struct fts_expunge_log_read_record read_rec;
 
 	bool failed;
@@ -501,7 +501,7 @@ fts_expunge_log_read_next(struct fts_exp
 	/* create the UIDs array by pointing it directly into input
 	   stream's buffer */
 	buffer_create_from_const_data(&ctx->buffer, rec + 1, uids_size);
-	array_create_from_buffer(&ctx->read_rec.uids, &ctx->buffer,
+	array_create_from_buffer(&ctx->read_rec.uids, &ctx->buffer.buf,
 				 sizeof(struct seq_range));
 
 	i_stream_skip(ctx->input, rec->record_size);
diff --git a/src/pop3-login/client.c b/src/pop3-login/client.c
--- a/src/pop3-login/client.c
+++ b/src/pop3-login/client.c
@@ -227,7 +227,7 @@ static char *get_apop_challenge(struct p
 {
 	unsigned char buffer[16];
 	unsigned char buffer_base64[MAX_BASE64_ENCODED_SIZE(sizeof(buffer)) + 1];
-	buffer_t buf;
+	union static_buffer buf;
 
 	if (sasl_server_find_available_mech(&client->common, "APOP") == NULL) {
 		/* disabled, no need to present the challenge */
@@ -239,14 +239,14 @@ static char *get_apop_challenge(struct p
 
 	random_fill(buffer, sizeof(buffer));
 	buffer_create_from_data(&buf, buffer_base64, sizeof(buffer_base64));
-	base64_encode(buffer, sizeof(buffer), &buf);
-	buffer_append_c(&buf, '\0');
+	base64_encode(buffer, sizeof(buffer), &buf.buf);
+	buffer_append_c(&buf.buf, '\0');
 
 	return i_strdup_printf("<%x.%x.%lx.%s@%s>",
 			       client->apop_server_pid,
 			       client->apop_connect_uid,
 			       (unsigned long)ioloop_time,
-			       (const char *)buf.data, my_hostname);
+			       (const char *)buf.buf.data, my_hostname);
 }
 
 static void pop3_client_notify_auth_ready(struct client *client)
diff --git a/src/pop3-login/pop3-login-settings.c b/src/pop3-login/pop3-login-settings.c
--- a/src/pop3-login/pop3-login-settings.c
+++ b/src/pop3-login/pop3-login-settings.c
@@ -18,8 +18,8 @@ static struct inet_listener_settings *po
 	&pop3_login_inet_listeners_array[0],
 	&pop3_login_inet_listeners_array[1]
 };
-static buffer_t pop3_login_inet_listeners_buf = {
-	pop3_login_inet_listeners, sizeof(pop3_login_inet_listeners), { NULL, }
+static union static_buffer pop3_login_inet_listeners_buf = {
+	.buf = { pop3_login_inet_listeners, sizeof(pop3_login_inet_listeners) }
 };
 
 /* </settings checks> */
@@ -45,7 +45,7 @@ struct service_settings pop3_login_servi
 
 	.unix_listeners = ARRAY_INIT,
 	.fifo_listeners = ARRAY_INIT,
-	.inet_listeners = { { &pop3_login_inet_listeners_buf,
+	.inet_listeners = { { &pop3_login_inet_listeners_buf.buf,
 			      sizeof(pop3_login_inet_listeners[0]) } }
 };
 
diff --git a/src/pop3/main.c b/src/pop3/main.c
--- a/src/pop3/main.c
+++ b/src/pop3/main.c
@@ -257,7 +257,7 @@ login_client_connected(const struct mast
 	struct mail_storage_service_input input;
 	enum mail_auth_request_flags flags = login_client->auth_req.flags;
 	const char *error;
-	buffer_t input_buf;
+	union static_buffer input_buf;
 
 	i_zero(&input);
 	input.module = input.service = "pop3";
@@ -284,7 +284,7 @@ login_client_connected(const struct mast
 		master_service_client_connection_destroyed(master_service);
 		return;
 	}
-	add_input(client, &input_buf);
+	add_input(client, &input_buf.buf);
 	/* client may be destroyed now */
 }
 
diff --git a/src/pop3/pop3-settings.c b/src/pop3/pop3-settings.c
--- a/src/pop3/pop3-settings.c
+++ b/src/pop3/pop3-settings.c
@@ -20,8 +20,8 @@ static struct file_listener_settings pop
 static struct file_listener_settings *pop3_unix_listeners[] = {
 	&pop3_unix_listeners_array[0]
 };
-static buffer_t pop3_unix_listeners_buf = {
-	pop3_unix_listeners, sizeof(pop3_unix_listeners), { NULL, }
+static union static_buffer pop3_unix_listeners_buf = {
+	.buf = { pop3_unix_listeners, sizeof(pop3_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -45,7 +45,7 @@ struct service_settings pop3_service_set
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &pop3_unix_listeners_buf,
+	.unix_listeners = { { &pop3_unix_listeners_buf.buf,
 			      sizeof(pop3_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT
diff --git a/src/replication/aggregator/aggregator-settings.c b/src/replication/aggregator/aggregator-settings.c
--- a/src/replication/aggregator/aggregator-settings.c
+++ b/src/replication/aggregator/aggregator-settings.c
@@ -13,8 +13,8 @@ static struct file_listener_settings agg
 static struct file_listener_settings *aggregator_unix_listeners[] = {
 	&aggregator_unix_listeners_array[0]
 };
-static buffer_t aggregator_unix_listeners_buf = {
-	aggregator_unix_listeners, sizeof(aggregator_unix_listeners), { NULL, }
+static union static_buffer aggregator_unix_listeners_buf = {
+	.buf = { aggregator_unix_listeners, sizeof(aggregator_unix_listeners) }
 };
 
 static struct file_listener_settings aggregator_fifo_listeners_array[] = {
@@ -23,8 +23,8 @@ static struct file_listener_settings agg
 static struct file_listener_settings *aggregator_fifo_listeners[] = {
 	&aggregator_fifo_listeners_array[0]
 };
-static buffer_t aggregator_fifo_listeners_buf = {
-	aggregator_fifo_listeners, sizeof(aggregator_fifo_listeners), { NULL, }
+static union static_buffer aggregator_fifo_listeners_buf = {
+	.buf = { aggregator_fifo_listeners, sizeof(aggregator_fifo_listeners) }
 };
 /* </settings checks> */
 
@@ -48,9 +48,9 @@ struct service_settings aggregator_servi
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &aggregator_unix_listeners_buf,
+	.unix_listeners = { { &aggregator_unix_listeners_buf.buf,
 			      sizeof(aggregator_unix_listeners[0]) } },
-	.fifo_listeners = { { &aggregator_fifo_listeners_buf,
+	.fifo_listeners = { { &aggregator_fifo_listeners_buf.buf,
 			      sizeof(aggregator_fifo_listeners[0]) } },
 	.inet_listeners = ARRAY_INIT
 };
diff --git a/src/replication/replicator/replicator-settings.c b/src/replication/replicator/replicator-settings.c
--- a/src/replication/replicator/replicator-settings.c
+++ b/src/replication/replicator/replicator-settings.c
@@ -15,8 +15,8 @@ static struct file_listener_settings *re
 	&replicator_unix_listeners_array[0],
 	&replicator_unix_listeners_array[1]
 };
-static buffer_t replicator_unix_listeners_buf = {
-	replicator_unix_listeners, sizeof(replicator_unix_listeners), { NULL, }
+static union static_buffer replicator_unix_listeners_buf = {
+	.buf = { replicator_unix_listeners, sizeof(replicator_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -40,7 +40,7 @@ struct service_settings replicator_servi
 	.idle_kill = UINT_MAX,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &replicator_unix_listeners_buf,
+	.unix_listeners = { { &replicator_unix_listeners_buf.buf,
 			      sizeof(replicator_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT,
diff --git a/src/stats/stats-settings.c b/src/stats/stats-settings.c
--- a/src/stats/stats-settings.c
+++ b/src/stats/stats-settings.c
@@ -25,8 +25,8 @@ static struct file_listener_settings *st
 	&stats_unix_listeners_array[0],
 	&stats_unix_listeners_array[1],
 };
-static buffer_t stats_unix_listeners_buf = {
-	stats_unix_listeners, sizeof(stats_unix_listeners), { NULL, }
+static union static_buffer stats_unix_listeners_buf = {
+	.buf = { stats_unix_listeners, sizeof(stats_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -50,7 +50,7 @@ struct service_settings stats_service_se
 	.idle_kill = UINT_MAX,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &stats_unix_listeners_buf,
+	.unix_listeners = { { &stats_unix_listeners_buf.buf,
 			      sizeof(stats_unix_listeners[0]) } },
 	.inet_listeners = ARRAY_INIT,
 };
diff --git a/src/submission-login/submission-login-settings.c b/src/submission-login/submission-login-settings.c
--- a/src/submission-login/submission-login-settings.c
+++ b/src/submission-login/submission-login-settings.c
@@ -21,8 +21,11 @@ static struct inet_listener_settings sub
 static struct inet_listener_settings *submission_login_inet_listeners[] = {
 	&submission_login_inet_listeners_array[0]
 };
-static buffer_t submission_login_inet_listeners_buf = {
-	submission_login_inet_listeners, sizeof(submission_login_inet_listeners), { 0, }
+static union static_buffer submission_login_inet_listeners_buf = {
+	.buf = {
+		submission_login_inet_listeners,
+		sizeof(submission_login_inet_listeners),
+	}
 };
 
 /* </settings checks> */
@@ -48,7 +51,7 @@ struct service_settings submission_login
 
 	.unix_listeners = ARRAY_INIT,
 	.fifo_listeners = ARRAY_INIT,
-	.inet_listeners = { { &submission_login_inet_listeners_buf,
+	.inet_listeners = { { &submission_login_inet_listeners_buf.buf,
 			      sizeof(submission_login_inet_listeners[0]) } }
 };
 
diff --git a/src/submission/main.c b/src/submission/main.c
--- a/src/submission/main.c
+++ b/src/submission/main.c
@@ -224,7 +224,7 @@ login_client_connected(const struct mast
 	struct mail_storage_service_input input;
 	enum mail_auth_request_flags flags = login_client->auth_req.flags;
 	const char *error;
-	buffer_t input_buf;
+	union static_buffer input_buf;
 
 	i_zero(&input);
 	input.module = input.service = "submission";
@@ -243,7 +243,7 @@ login_client_connected(const struct mast
 	buffer_create_from_const_data(&input_buf, login_client->data,
 				      login_client->auth_req.data_size);
 	if (client_create_from_input(&input, login_client->fd, login_client->fd,
-				     &input_buf, &error) < 0) {
+				     &input_buf.buf, &error) < 0) {
 		int fd = login_client->fd;
 		i_error("%s", error);
 		i_close_fd(&fd);
diff --git a/src/submission/submission-settings.c b/src/submission/submission-settings.c
--- a/src/submission/submission-settings.c
+++ b/src/submission/submission-settings.c
@@ -21,8 +21,8 @@ static struct file_listener_settings sub
 static struct file_listener_settings *submission_unix_listeners[] = {
 	&submission_unix_listeners_array[0]
 };
-static buffer_t submission_unix_listeners_buf = {
-	submission_unix_listeners, sizeof(submission_unix_listeners), { 0, }
+static union static_buffer submission_unix_listeners_buf = {
+	.buf = { submission_unix_listeners, sizeof(submission_unix_listeners) }
 };
 /* </settings checks> */
 
@@ -46,7 +46,7 @@ struct service_settings submission_servi
 	.idle_kill = 0,
 	.vsz_limit = UOFF_T_MAX,
 
-	.unix_listeners = { { &submission_unix_listeners_buf,
+	.unix_listeners = { { &submission_unix_listeners_buf.buf,
 			      sizeof(submission_unix_listeners[0]) } },
 	.fifo_listeners = ARRAY_INIT,
 	.inet_listeners = ARRAY_INIT


More information about the dovecot mailing list