shithub: mq

Download patch

ref: 1af7a1aced139ad7c90a053241e46f2ea2aaa2b4
parent: f0874a14c3685a08e98c3fcb1ebd81514b1e3ded
author: Ori Bernstein <ori@eigenstate.org>
date: Mon Jun 17 21:59:59 EDT 2024

mq: avoid double-advancing messages

--- a/mq.c
+++ b/mq.c
@@ -370,12 +370,12 @@
 void
 mqread(Req *r)
 {
-	char *p, *e, *b;
+	char *p, *e, *b, *d;
+	int n, mcount;
 	Aux *a;
 	Msg *m;
 	Rd *rd;
 	Mq *q;
-	int n;
 
 	if(QTYPE(r->fid->qid.path) == Qroot){
 		dirread9p(r, rootgen, r->fid->aux);
@@ -396,35 +396,40 @@
 
 	/* queued messages: pop data off */
 	rd = &q->rd[a->id];
-	m = rd->hd;
-	p = emalloc(r->ifcall.count);
-	e = p + r->ifcall.count;
+	d = emalloc(r->ifcall.count);
+	p = d;
+	e = d + r->ifcall.count;
 	r->ofcall.data = p;
-	while(1){
-		assert(rd->off >= 0 && rd->off < m->count);
+	while(rd->hd != nil && p != e){
+		m = rd->hd;
 		b = m->data + rd->off;
-		if(e - p >= m->count - rd->off){
+		n = e - p;
+		mcount = m->count;
+		assert(rd->off >= 0 && rd->off <= m->count);
+		incref(m);
+		if(n >= m->count - rd->off){
 			n = m->count - rd->off;
+			memcpy(p, b, n);
 			rd->hd = m->next;
 			rd->off = 0;
 			if(rd->hd == nil)
 				rd->tl = nil;
-			if(decref(m) == 0)
-				free(m);
+			decref(m);
 		}else{
-			n = e - p;
-			rd->off += (e - p);
+			memcpy(p, b, n);
+			rd->off += n;
 		}
-		memcpy(p, b, n);
 		p += n;
-		rd->hd = m->next;
-		m = rd->hd;
-		if(!coalesce || m == nil || e - p < m->count)
+		if(decref(m) == 0)
+			free(m);
+		if(!coalesce || n < mcount)
 			break;
 			
 	}
-	r->ofcall.count = p - r->ofcall.data;
+	assert(r->ofcall.count <= r->ifcall.count);
+	r->ofcall.count = p - d;
 	respond(r, nil);
+	free(d);
 }
 
 void