BUG/MAJOR: trash must always be the size of a buffer

Before it was possible to resize the buffers using global.tune.bufsize,
the trash has always been the size of a buffer by design. Unfortunately,
the recent buffer sizing at runtime forgot to adjust the trash, resulting
in it being too short for content rewriting if buffers were enlarged from
the default value.

The bug was encountered in 1.4 so the fix must be backported there.
diff --git a/src/acl.c b/src/acl.c
index 54c4e15..8ec046f 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -1271,7 +1271,7 @@
 	opaque = 0;
 	pattern = NULL;
 	args[1] = "";
-	while (fgets(trash, sizeof(trash), file) != NULL) {
+	while (fgets(trash, trashlen, file) != NULL) {
 		line++;
 		c = trash;
 
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 49d1dbe..b3ae050 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -528,6 +528,8 @@
 		global.tune.bufsize = atol(args[1]);
 		if (global.tune.maxrewrite >= global.tune.bufsize / 2)
 			global.tune.maxrewrite = global.tune.bufsize / 2;
+		trashlen = global.tune.bufsize;
+		trash = realloc(trash, trashlen);
 	}
 	else if (!strcmp(args[0], "tune.maxrewrite")) {
 		if (*(args[1]) == 0) {
@@ -1032,7 +1034,7 @@
 					continue;
 				if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
 					/* prepare error message just in case */
-					snprintf(trash, sizeof(trash),
+					snprintf(trash, trashlen,
 						 "error near '%s' in '%s' section", args[0], "global");
 					rc = kwl->kw[index].parse(args, CFG_GLOBAL, NULL, NULL, &errmsg);
 					if (rc < 0) {
@@ -3016,7 +3018,7 @@
 			goto out;
 		}
 
-		expr = sample_parse_expr(args, &myidx, trash, sizeof(trash));
+		expr = sample_parse_expr(args, &myidx, trash, trashlen);
 		if (!expr) {
 			Alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], trash);
 			err_code |= ERR_ALERT | ERR_FATAL;
@@ -5255,7 +5257,7 @@
 					continue;
 				if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
 					/* prepare error message just in case */
-					snprintf(trash, sizeof(trash),
+					snprintf(trash, trashlen,
 						 "error near '%s' in %s section", args[0], cursection);
 					rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, &errmsg);
 					if (rc < 0) {
diff --git a/src/checks.c b/src/checks.c
index 3604e5a..78ec4ad 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -237,7 +237,7 @@
 
 		int health, rise, fall, state;
 
-		chunk_init(&msg, trash, sizeof(trash));
+		chunk_init(&msg, trash, trashlen);
 
 		/* FIXME begin: calculate local version of the health/rise/fall/state */
 		health = s->health;
@@ -401,7 +401,7 @@
 		 */
 		xferred = redistribute_pending(s);
 
-		chunk_init(&msg, trash, sizeof(trash));
+		chunk_init(&msg, trash, trashlen);
 
 		if (s->state & SRV_MAINTAIN) {
 			chunk_printf(&msg,
@@ -483,7 +483,7 @@
 		 */
 		xferred = check_for_pending(s);
 
-		chunk_init(&msg, trash, sizeof(trash));
+		chunk_init(&msg, trash, trashlen);
 
 		if (old_state & SRV_MAINTAIN) {
 			chunk_printf(&msg,
@@ -529,7 +529,7 @@
 	 */
 	xferred = redistribute_pending(s);
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 
 	chunk_printf(&msg,
 		"Load-balancing on %sServer %s/%s is disabled",
@@ -565,7 +565,7 @@
 	 */
 	xferred = check_for_pending(s);
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 
 	chunk_printf(&msg,
 		"Load-balancing on %sServer %s/%s is enabled again",
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 43cc275..b95418e 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -573,7 +573,7 @@
 
 	if (show) {
 		struct chunk msg;
-		chunk_init(&msg, trash, sizeof(trash));
+		chunk_init(&msg, trash, trashlen);
 		if (!stats_dump_table_head_to_buffer(&msg, si, px, px))
 			return;
 		stats_dump_table_entry_to_buffer(&msg, si, px, ts);
@@ -922,7 +922,7 @@
 			}
 
 			/* return server's effective weight at the moment */
-			snprintf(trash, sizeof(trash), "%d (initial %d)\n", sv->uweight, sv->iweight);
+			snprintf(trash, trashlen, "%d (initial %d)\n", sv->uweight, sv->iweight);
 			bi_putstr(si->ib, trash);
 			return 1;
 		}
@@ -1385,7 +1385,7 @@
 			if (buffer_almost_full(si->ib))
 				break;
 
-			reql = bo_getline(si->ob, trash, sizeof(trash));
+			reql = bo_getline(si->ob, trash, trashlen);
 			if (reql <= 0) { /* closed or EOL not found */
 				if (reql == 0)
 					break;
@@ -1561,7 +1561,7 @@
 	struct chunk msg;
 	unsigned int up;
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 
 	switch (si->applet.state) {
 	case STAT_ST_INIT:
@@ -1677,7 +1677,7 @@
 	struct session *s = si->applet.private;
 	struct chunk msg;
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 
 	switch (si->applet.state) {
 	case STAT_ST_INIT:
@@ -1781,7 +1781,7 @@
 	struct chunk msg;
 	unsigned int up;
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 
 	switch (si->applet.state) {
 	case STAT_ST_INIT:
@@ -2151,7 +2151,7 @@
 	struct listener *l;
 	struct chunk msg;
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 
 	switch (si->applet.ctx.stats.px_st) {
 	case STAT_PX_ST_INIT:
@@ -3205,7 +3205,7 @@
 	extern const char *monthname[12];
 	char pn[INET6_ADDRSTRLEN];
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 	sess = si->applet.ctx.sess.target;
 
 	if (si->applet.ctx.sess.section > 0 && si->applet.ctx.sess.uid != sess->uniq_id) {
@@ -3459,7 +3459,7 @@
 		return 1;
 	}
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 
 	switch (si->applet.state) {
 	case STAT_ST_INIT:
@@ -3680,7 +3680,7 @@
 		return 1;
 	}
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 
 	while (si->applet.state != STAT_ST_FIN) {
 		switch (si->applet.state) {
@@ -3875,7 +3875,7 @@
 	if (unlikely(si->ib->flags & (BF_WRITE_ERROR|BF_SHUTW)))
 		return 1;
 
-	chunk_init(&msg, trash, sizeof(trash));
+	chunk_init(&msg, trash, trashlen);
 
 	if (!si->applet.ctx.errors.px) {
 		/* the function had not been called yet, let's prepare the
diff --git a/src/haproxy.c b/src/haproxy.c
index 2afbb3b..8d3e6e3 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -143,7 +143,8 @@
 static int oldpids_sig; /* use USR1 or TERM */
 
 /* this is used to drain data, and as a temporary buffer for sprintf()... */
-char trash[BUFSIZE];
+char *trash = NULL;
+int trashlen = BUFSIZE;
 
 /* this buffer is always the same size as standard buffers and is used for
  * swapping data inside a buffer.
@@ -301,7 +302,7 @@
 
 		send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
 		while (s) {
-			snprintf(trash, sizeof(trash),
+			snprintf(trash, trashlen,
 				 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
 				 p->id, s->id,
 				 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
@@ -313,18 +314,18 @@
 
 		/* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */
 		if (!p->srv) {
-			snprintf(trash, sizeof(trash),
+			snprintf(trash, trashlen,
 				 "SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
 				 p->id,
 				 p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
 		} else if (p->srv_act == 0) {
-			snprintf(trash, sizeof(trash),
+			snprintf(trash, trashlen,
 				 "SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
 				 p->id,
 				 (p->srv_bck) ? "is running on backup servers" : "has no server available",
 				 p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
 		} else {
-			snprintf(trash, sizeof(trash),
+			snprintf(trash, trashlen,
 				 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
 				 " Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
 				 p->id, p->srv_act, p->srv_bck,
@@ -359,6 +360,8 @@
 	char *progname;
 	char *change_dir = NULL;
 
+	trash = malloc(trashlen);
+
 	/* NB: POSIX does not make it mandatory for gethostname() to NULL-terminate
 	 * the string in case of truncation, and at least FreeBSD appears not to do
 	 * it.
diff --git a/src/peers.c b/src/peers.c
index 5456410..f39c7df 100644
--- a/src/peers.c
+++ b/src/peers.c
@@ -231,7 +231,7 @@
 				si->applet.st0 = PEER_SESSION_GETVERSION;
 				/* fall through */
 			case PEER_SESSION_GETVERSION:
-				reql = bo_getline(si->ob, trash, sizeof(trash));
+				reql = bo_getline(si->ob, trash, trashlen);
 				if (reql <= 0) { /* closed or EOL not found */
 					if (reql == 0)
 						goto out;
@@ -262,7 +262,7 @@
 				si->applet.st0 = PEER_SESSION_GETHOST;
 				/* fall through */
 			case PEER_SESSION_GETHOST:
-				reql = bo_getline(si->ob, trash, sizeof(trash));
+				reql = bo_getline(si->ob, trash, trashlen);
 				if (reql <= 0) { /* closed or EOL not found */
 					if (reql == 0)
 						goto out;
@@ -292,7 +292,7 @@
 			case PEER_SESSION_GETPEER: {
 				struct peer *curpeer;
 				char *p;
-				reql = bo_getline(si->ob, trash, sizeof(trash));
+				reql = bo_getline(si->ob, trash, trashlen);
 				if (reql <= 0) { /* closed or EOL not found */
 					if (reql == 0)
 						goto out;
@@ -345,7 +345,7 @@
 				size_t key_size;
 				char *p;
 
-				reql = bo_getline(si->ob, trash, sizeof(trash));
+				reql = bo_getline(si->ob, trash, trashlen);
 				if (reql <= 0) { /* closed or EOL not found */
 					if (reql == 0)
 						goto out;
@@ -446,7 +446,7 @@
 			case PEER_SESSION_SENDSUCCESS:{
 				struct peer_session *ps = (struct peer_session *)si->applet.private;
 
-				repl = snprintf(trash, sizeof(trash), "%d\n", PEER_SESSION_SUCCESSCODE);
+				repl = snprintf(trash, trashlen, "%d\n", PEER_SESSION_SUCCESSCODE);
 				repl = bi_putblk(si->ib, trash, repl);
 				if (repl <= 0) {
 					if (repl == -1)
@@ -497,7 +497,7 @@
 				struct peer_session *ps = (struct peer_session *)si->applet.private;
 
 				/* Send headers */
-				repl = snprintf(trash, sizeof(trash),
+				repl = snprintf(trash, trashlen,
 				                PEER_SESSION_PROTO_NAME " 1.0\n%s\n%s %d\n%s %lu %d\n",
 				                ps->peer->id,
 				                localpeer,
@@ -506,7 +506,7 @@
 				                ps->table->table->type,
 				                (int)ps->table->table->key_size);
 
-				if (repl >= sizeof(trash)) {
+				if (repl >= trashlen) {
 					si->applet.st0 = PEER_SESSION_END;
 					goto switchstate;
 				}
@@ -529,7 +529,7 @@
 				if (si->ib->flags & BF_WRITE_PARTIAL)
 					ps->statuscode = PEER_SESSION_CONNECTEDCODE;
 
-				reql = bo_getline(si->ob, trash, sizeof(trash));
+				reql = bo_getline(si->ob, trash, trashlen);
 				if (reql <= 0) { /* closed or EOL not found */
 					if (reql == 0)
 						goto out;
@@ -904,7 +904,7 @@
 							}
 
 							ts = eb32_entry(eb, struct stksess, upd);
-							msglen = peer_prepare_datamsg(ts, ps, trash, sizeof(trash));
+							msglen = peer_prepare_datamsg(ts, ps, trash, trashlen);
 							if (msglen) {
 								/* message to buffer */
 								repl = bi_putblk(si->ib, trash, msglen);
@@ -938,7 +938,7 @@
 							}
 
 							ts = eb32_entry(eb, struct stksess, upd);
-							msglen = peer_prepare_datamsg(ts, ps, trash, sizeof(trash));
+							msglen = peer_prepare_datamsg(ts, ps, trash, trashlen);
 							if (msglen) {
 								/* message to buffer */
 								repl = bi_putblk(si->ib, trash, msglen);
@@ -996,7 +996,7 @@
 						}
 
 						ts = eb32_entry(eb, struct stksess, upd);
-						msglen = peer_prepare_datamsg(ts, ps, trash, sizeof(trash));
+						msglen = peer_prepare_datamsg(ts, ps, trash, trashlen);
 						if (msglen) {
 							/* message to buffer */
 							repl = bi_putblk(si->ib, trash, msglen);
@@ -1016,7 +1016,7 @@
 				goto out;
 			}
 			case PEER_SESSION_EXIT:
-				repl = snprintf(trash, sizeof(trash), "%d\n", si->applet.st1);
+				repl = snprintf(trash, trashlen, "%d\n", si->applet.st1);
 
 				if (bi_putblk(si->ib, trash, repl) == -1)
 					goto out;
diff --git a/src/proto_http.c b/src/proto_http.c
index f18ae72..5250f23 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -390,14 +390,14 @@
 static void http_silent_debug(int line, struct session *s)
 {
 	int size = 0;
-	size += snprintf(trash + size, sizeof(trash) - size,
+	size += snprintf(trash + size, trashlen - size,
 			 "[%04d] req: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p o=%p sm=%d fw=%ld tf=%08x\n",
 			 line,
 			 s->si[0].state, s->si[0].fd, s->txn.req.msg_state, s->req->flags, s->req->analysers,
 			 s->req->data, s->req->size, s->req->l, s->req->w, s->req->r, s->req->p, s->req->o, s->req->to_forward, s->txn.flags);
 	write(-1, trash, size);
 	size = 0;
-	size += snprintf(trash + size, sizeof(trash) - size,
+	size += snprintf(trash + size, trashlen - size,
 			 " %04d  rep: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p o=%p sm=%d fw=%ld\n",
 			 line,
 			 s->si[1].state, s->si[1].fd, s->txn.rsp.msg_state, s->rep->flags, s->rep->analysers,
@@ -766,7 +766,7 @@
 	/* 1: create the response header */
 	rdr.len = strlen(HTTP_302);
 	rdr.str = trash;
-	rdr.size = sizeof(trash);
+	rdr.size = trashlen;
 	memcpy(rdr.str, HTTP_302, rdr.len);
 
 	srv = target_srv(&s->target);
@@ -2888,7 +2888,7 @@
 			realm = do_stats?STATS_DEFAULT_REALM:px->id;
 
 		sprintf(trash, (txn->flags & TX_USE_PX_CONN) ? HTTP_407_fmt : HTTP_401_fmt, realm);
-		chunk_initlen(&msg, trash, sizeof(trash), strlen(trash));
+		chunk_initlen(&msg, trash, trashlen, strlen(trash));
 		txn->status = 401;
 		stream_int_retnclose(req->prod, &msg);
 		/* on 401 we still count one error, because normal browsing
@@ -2996,7 +2996,7 @@
 		}
 
 		if (ret) {
-			struct chunk rdr = { .str = trash, .size = sizeof(trash), .len = 0 };
+			struct chunk rdr = { .str = trash, .size = trashlen, .len = 0 };
 			const char *msg_fmt;
 
 			/* build redirect message */
@@ -3657,7 +3657,7 @@
 	hdr_val += hdr_name_len;
 	*hdr_val++ = ':';
 	*hdr_val++ = ' ';
-	hdr_val += strlcpy2(hdr_val, srv_name, trash + sizeof(trash) - hdr_val);
+	hdr_val += strlcpy2(hdr_val, srv_name, trash + trashlen - hdr_val);
 	http_header_add_tail2(&txn->req, &txn->hdr_idx, trash, hdr_val - trash);
 
 	return 0;
@@ -7290,7 +7290,7 @@
 	len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
 		      dir, (unsigned  short)t->req->prod->fd, (unsigned short)t->req->cons->fd);
 	max = end - start;
-	UBOUND(max, sizeof(trash) - len - 1);
+	UBOUND(max, trashlen - len - 1);
 	len += strlcpy2(trash + len, start, max + 1);
 	trash[len++] = '\n';
 	if (write(1, trash, len) < 0) /* shut gcc warning */;
diff --git a/src/sock_raw.c b/src/sock_raw.c
index b7edbfc..db38cd5 100644
--- a/src/sock_raw.c
+++ b/src/sock_raw.c
@@ -529,7 +529,7 @@
 		 * (which is recomputed every time since it's constant). If
 		 * it is positive, it means we have to send from the start.
 		 */
-		ret = make_proxy_line(trash, sizeof(trash),
+		ret = make_proxy_line(trash, trashlen,
 				      &b->prod->addr.from, &b->prod->addr.to);
 		if (!ret)
 			return -1;