[master] 5a55b53a0 Plug memory leaks witnessed in varnishtest

Dridi Boukelmoune dridi.boukelmoune at gmail.com
Fri Dec 27 13:41:06 UTC 2019


commit 5a55b53a0d83c892e90b8c064944a4054c076d77
Author: Dridi Boukelmoune <dridi.boukelmoune at gmail.com>
Date:   Fri Dec 27 13:34:39 2019 +0100

    Plug memory leaks witnessed in varnishtest
    
    For those that aren't leaked on purpose, that is...

diff --git a/bin/varnishtest/vtc_h2_hpack.c b/bin/varnishtest/vtc_h2_hpack.c
index a00208ad9..e16361c9f 100644
--- a/bin/varnishtest/vtc_h2_hpack.c
+++ b/bin/varnishtest/vtc_h2_hpack.c
@@ -379,12 +379,16 @@ HPK_DecHdr(struct hpk_iter *iter, struct hpk_hdr *header)
 			return (hpk_err);
 		txtcpy(&header->key, t);
 	} else {
-		if (hpk_more != str_decode(iter, &header->key))
+		if (hpk_more != str_decode(iter, &header->key)) {
+			free(header->key.ptr);
 			return (hpk_err);
+		}
 	}
 
-	if (hpk_err == str_decode(iter, &header->value))
+	if (hpk_err == str_decode(iter, &header->value)) {
+		free(header->key.ptr);
 		return (hpk_err);
+	}
 
 	if (must_index)
 		push_header(iter->ctx, header);
diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c
index 049d7dd1b..9d9a4e5f6 100644
--- a/bin/varnishtest/vtc_http2.c
+++ b/bin/varnishtest/vtc_http2.c
@@ -116,13 +116,16 @@ struct stream {
 static void
 clean_headers(struct hpk_hdr *h)
 {
-	while (h->t) {
+	unsigned n = MAX_HDR;
+
+	while (h->t && n > 0) {
 		if (h->key.len)
 			free(h->key.ptr);
 		if (h->value.len)
 			free(h->value.ptr);
 		memset(h, 0, sizeof(*h));
 		h++;
+		n--;
 	}
 }
 
@@ -284,18 +287,30 @@ do { \
 } while(0)
 
 static void
-clean_frame(struct frame **f)
+replace_frame(struct frame **fp, struct frame *new)
 {
-	AN(f);
-	if (!*f)
+	struct frame *old;
+
+	AN(fp);
+	CHECK_OBJ_ORNULL(new, FRAME_MAGIC);
+
+	old = *fp;
+	*fp = new;
+	if (old == NULL)
 		return;
 
-	CHECK_OBJ_NOTNULL(*f, FRAME_MAGIC);
+	CHECK_OBJ(old, FRAME_MAGIC);
+	if (old->type == TYPE_GOAWAY)
+		free(old->md.goaway.debug);
+	free(old->data);
+	FREE_OBJ(old);
+}
 
-	if ((*f)->type == TYPE_GOAWAY)
-		free((*f)->md.goaway.debug);
-	free((*f)->data);
-	FREE_OBJ(*f);
+static void
+clean_frame(struct frame **fp)
+{
+
+	replace_frame(fp, NULL);
 }
 
 static void
@@ -783,6 +798,7 @@ receive_frame(void *priv)
 					else
 						hdrs = s->resp;
 				}
+				clean_headers(hdrs);
 				hdrs[0].t = hpk_unset;
 				AZ(vsb);
 				vsb = VSB_new_auto();
@@ -2107,10 +2123,9 @@ rxstuff(struct stream *s)
 	}
 	clean_frame(&s->frame);
 	f = VTAILQ_LAST(&s->fq, fq_head);
+	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
 	VTAILQ_REMOVE(&s->fq, f, list);
 	AZ(pthread_mutex_unlock(&s->hp->mtx));
-
-	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
 	return (f);
 }
 
@@ -2165,14 +2180,14 @@ cmd_rxhdrs(CMD_ARGS)
 		vtc_fatal(vl, "Unknown rxhdrs spec: %s\n", *av);
 
 	do {
-		f = rxstuff(s);
-		if (!f)
-			return;
+		replace_frame(&f, rxstuff(s));
+		if (f == NULL)
+			break;
 		rcv++;
 		CHKFRAME(f->type, expect, rcv, "rxhdrs");
 		expect = TYPE_CONTINUATION;
 	} while (rcv < times || (loop && !(f->flags & END_HEADERS)));
-	s->frame = f;
+	replace_frame(&s->frame, f);
 }
 
 static void
@@ -2203,13 +2218,13 @@ cmd_rxcont(CMD_ARGS)
 		vtc_fatal(vl, "Unknown rxcont spec: %s\n", *av);
 
 	do {
-		f = rxstuff(s);
-		if (!f)
-			return;
+		replace_frame(&f, rxstuff(s));
+		if (f == NULL)
+			break;
 		rcv++;
 		CHKFRAME(f->type, TYPE_CONTINUATION, rcv, "rxcont");
 	} while (rcv < times || (loop && !(f->flags & END_HEADERS)));
-	s->frame = f;
+	replace_frame(&s->frame, f);
 }
 
 
@@ -2254,13 +2269,13 @@ cmd_rxdata(CMD_ARGS)
 		vtc_fatal(vl, "Unknown rxdata spec: %s\n", *av);
 
 	do {
-		f = rxstuff(s);
-		if (!f)
-			return;
+		replace_frame(&f, rxstuff(s));
+		if (f == NULL)
+			break;
 		rcv++;
 		CHKFRAME(f->type, TYPE_DATA, rcv, "rxhdata");
 	} while (rcv < times || (loop && !(f->flags & END_STREAM)));
-	s->frame = f;
+	replace_frame(&s->frame, f);
 }
 
 /* SECTION: stream.spec.data_10 rxreq, rxresp
@@ -2300,19 +2315,22 @@ cmd_rxmsg(CMD_ARGS)
 	end_stream = f->flags & END_STREAM;
 
 	while (!(f->flags & END_HEADERS)) {
-		f = rxstuff(s);
-		if (!f)
+		replace_frame(&f, rxstuff(s));
+		if (f == NULL)
 			return;
 		rcv++;
 		CHKFRAME(f->type, TYPE_CONTINUATION, rcv, *av);
 	}
 
-	while (!end_stream && (f = rxstuff(s)) != NULL) {
+	while (!end_stream) {
+		replace_frame(&f, rxstuff(s));
+		if (f == NULL)
+			break;
 		rcv++;
 		CHKFRAME(f->type, TYPE_DATA, rcv, *av);
 		end_stream = f->flags & END_STREAM;
 	}
-	s->frame = f;
+	replace_frame(&s->frame, f);
 }
 
 /* SECTION: stream.spec.data_12 rxpush
@@ -2553,11 +2571,7 @@ stream_thread(void *priv)
 	struct stream *s;
 
 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
-
 	parse_string(s->spec, stream_cmds, s, s->hp->vl);
-
-	clean_headers(s->req);
-	clean_headers(s->resp);
 	vtc_log(s->hp->vl, 2, "Ending stream %u", s->id);
 	return (NULL);
 }
@@ -2604,7 +2618,17 @@ stream_new(const char *name, struct http *h)
 static void
 stream_delete(struct stream *s)
 {
+	struct frame *f, *f2;
+
 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
+
+	VTAILQ_FOREACH_SAFE(f, &s->fq, list, f2) {
+		VTAILQ_REMOVE(&s->fq, f, list);
+		clean_frame(&f);
+	}
+	clean_headers(s->req);
+	clean_headers(s->resp);
+	AZ(s->frame);
 	free(s->body);
 	free(s->spec);
 	free(s->name);
@@ -2640,8 +2664,10 @@ stream_wait(struct stream *s)
 		vtc_fatal(s->hp->vl, "Stream %u returned \"%s\"", s->id,
 		    (char *)res);
 
-	VTAILQ_FOREACH_SAFE(f, &s->fq, list, f2)
+	VTAILQ_FOREACH_SAFE(f, &s->fq, list, f2) {
+		VTAILQ_REMOVE(&s->fq, f, list);
 		clean_frame(&f);
+	}
 	clean_frame(&s->frame);
 	s->tp = 0;
 	s->running = 0;
diff --git a/bin/varnishtest/vtc_main.c b/bin/varnishtest/vtc_main.c
index c61ab7c7d..f0b147265 100644
--- a/bin/varnishtest/vtc_main.c
+++ b/bin/varnishtest/vtc_main.c
@@ -370,6 +370,10 @@ tst_cb(const struct vev *ve, int what)
 			VEV_Stop(vb, jp->evt);
 			free(jp->evt);
 		}
+		if (jp->tst->ntodo == 0) {
+			free(jp->tst->script);
+			FREE_OBJ(jp->tst);
+		}
 		FREE_OBJ(jp);
 		return (1);
 	}
@@ -406,8 +410,7 @@ start_test(void)
 		VTAILQ_INSERT_TAIL(&tst_head, tp, list);
 
 	jp->tst = tp;
-	jp->tmpdir = strdup(tmpdir);
-	AN(jp->tmpdir);
+	REPLACE(jp->tmpdir, tmpdir);
 
 	AZ(pipe(p));
 	assert(p[0] > STDERR_FILENO);
diff --git a/bin/varnishtest/vtc_varnish.c b/bin/varnishtest/vtc_varnish.c
index 483690cbb..bbc80899c 100644
--- a/bin/varnishtest/vtc_varnish.c
+++ b/bin/varnishtest/vtc_varnish.c
@@ -174,11 +174,12 @@ wait_running(const struct varnish *v)
 			vtc_fatal(v->vl,
 			    "Child stopped before running: %u %s", st, r);
 		if (!strcmp(r, "Child in state running")) {
+			free(r);
+			r = NULL;
 			st = varnish_ask_cli(v, "debug.listen_address", &r);
 			if (st != CLIS_OK)
 				vtc_fatal(v->vl,
-					  "CLI status command failed: %u %s",
-					  st, r);
+				    "CLI status command failed: %u %s", st, r);
 			free(r);
 			break;
 		}
@@ -349,7 +350,9 @@ varnish_delete(struct varnish *v)
 	CHECK_OBJ_NOTNULL(v, VARNISH_MAGIC);
 	vtc_logclose(v->vl);
 	free(v->name);
+	free(v->jail);
 	free(v->workdir);
+	VSB_destroy(&v->args);
 	if (v->vsc != NULL)
 		VSC_Destroy(&v->vsc, v->vsm_vsc);
 	if (v->vsm_vsc != NULL)
diff --git a/tools/lsan.suppr b/tools/lsan.suppr
index 854eaca9f..bcdbfbfbc 100644
--- a/tools/lsan.suppr
+++ b/tools/lsan.suppr
@@ -1,5 +1,5 @@
 # varnishtest
-leak:varnishtest
+leak:parse_string
 # av
 leak:STV_Config
 # av


More information about the varnish-commit mailing list