MEDIUM: snapshots: dynamically allocate the snapshots

Now upon error we dynamically allocate the snapshot instead of overwriting
it. This way there is no more memory wasted in the proxy to hold the two
error snapshot descriptors. Also an appreciable side effect of this is that
the proxy's lock is only taken during the pointer swap, no more while copying
the buffer's contents. This saves 480 bytes of memory per proxy.
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 9695b9c..ca3bc7d 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -410,7 +410,7 @@
 
 	/* warning: these structs are huge, keep them at the bottom */
 	struct sockaddr_storage dispatch_addr;	/* the default address to connect to */
-	struct error_snapshot invalid_req, invalid_rep; /* captures of last errors */
+	struct error_snapshot *invalid_req, *invalid_rep; /* captures of last errors */
 
 	/* used only during configuration parsing */
 	int no_options;				/* PR_O_REDISP, PR_O_TRANSP, ... */
diff --git a/src/proxy.c b/src/proxy.c
index 9306637..9f9fec8 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -1356,6 +1356,15 @@
 	struct error_snapshot *es;
 	unsigned int buf_len;
 	int len1, len2;
+	unsigned int ev_id;
+
+	ev_id = HA_ATOMIC_XADD(&error_snapshot_id, 1);
+
+	es = malloc(sizeof(*es));
+	if (!es)
+		return;
+
+	es->ev_id    = ev_id;
 
 	buf_len = b_data(buf) - buf_out;
 	len1 = b_size(buf) - buf_len;
@@ -1363,9 +1372,6 @@
 		len1 = buf_len;
 	len2 = buf_len - len1;
 
-	HA_SPIN_LOCK(PROXY_LOCK, &proxy->lock);
-	es = is_back ? &proxy->invalid_rep : &proxy->invalid_req;
-
 	es->buf_len = buf_len;
 
 	if (!es->buf)
@@ -1386,7 +1392,6 @@
 	else
 		memset(&es->src, 0, sizeof(es->src));
 
-	es->ev_id = HA_ATOMIC_XADD(&error_snapshot_id, 1);
 	es->buf_wrap = b_wrap(buf) - b_peek(buf, buf_out);
 	es->buf_out  = buf_out;
 	es->buf_ofs  = buf_ofs;
@@ -1403,6 +1408,17 @@
 	else
 		memset(&es->ctx, 0, sizeof(es->ctx));
 	es->show = show;
+
+	/* note: we still lock since we have to be certain that nobody is
+	 * dumping the output while we free.
+	 */
+	HA_SPIN_LOCK(PROXY_LOCK, &proxy->lock);
+	if (is_back) {
+		es = HA_ATOMIC_XCHG(&proxy->invalid_rep, es);
+	} else {
+		es = HA_ATOMIC_XCHG(&proxy->invalid_req, es);
+	}
+	free(es);
 	HA_SPIN_UNLOCK(PROXY_LOCK, &proxy->lock);
 }
 
@@ -2012,17 +2028,17 @@
 		HA_SPIN_LOCK(PROXY_LOCK, &appctx->ctx.errors.px->lock);
 
 		if ((appctx->ctx.errors.flag & 1) == 0) {
-			es = &appctx->ctx.errors.px->invalid_req;
+			es = appctx->ctx.errors.px->invalid_req;
 			if (appctx->ctx.errors.flag & 2) // skip req
 				goto next;
 		}
 		else {
-			es = &appctx->ctx.errors.px->invalid_rep;
+			es = appctx->ctx.errors.px->invalid_rep;
 			if (appctx->ctx.errors.flag & 4) // skip resp
 				goto next;
 		}
 
-		if (!es->when.tv_sec)
+		if (!es)
 			goto next;
 
 		if (appctx->ctx.errors.iid >= 0 &&