shithub: git9

Download patch

ref: b38b770691bdd012bd66c9f51da7af2b41c46e7a
parent: 43b4a73ee9c12c10d1ce50a1bb17c567b2fd7508
author: Ori Bernstein <[email protected]>
date: Sun Jan 17 21:35:24 EST 2021

ref range: fix segfault, avoid sysfatal (thanks igor.boehm)

When reading an invalid commit, we would segfault due to
nilling out p, and then indexing the commit object. This
change keeps the old object pointer around so we can read
through it.

While we're here, return an error instead of a sysfatal
when we get a screwy repo.

--- a/ref.c
+++ b/ref.c
@@ -396,7 +396,7 @@
 static int
 range(Eval *ev)
 {
-	Object *a, *b, *p, **all;
+	Object *a, *b, *p, *q, **all;
 	int nall, *idx, mark;
 	Objset keep, skip;
 
@@ -419,30 +419,38 @@
 		idx = earealloc(idx, (nall + 1), sizeof(int));
 		all[nall] = p;
 		idx[nall] = 0;
-		if(p == a || p->commit->nparent == 0 && a == &zcommit){
+		if(p == a || p->commit->nparent == 0 && a == &zcommit)
 			if((nall = unwind(ev, all, idx, nall, &p, &keep, 1)) == -1)
 				break;
-		}else if(p->commit->nparent == 0){
+		else if(p->commit->nparent == 0)
 			if((nall = unwind(ev, all, idx, nall, &p, &skip, 0)) == -1)
 				break;
-		}else if(oshas(&keep, p->hash)){
+		else if(oshas(&keep, p->hash))
 			if((nall = unwind(ev, all, idx, nall, &p, &keep, 1)) == -1)
 				break;
-		}else if(oshas(&skip, p->hash)){
+		else if(oshas(&skip, p->hash))
 			if((nall = unwind(ev, all, idx, nall, &p, &skip, 0)) == -1)
 				break;
-		}
 		if(p->commit->nparent == 0)
 			break;
-		if((p = readobject(p->commit->parent[idx[nall]])) == nil)
-			sysfatal("bad commit %H", p->commit->parent[idx[nall]]);
-		if(p->type != GCommit)
-			sysfatal("not commit: %H", p->hash);
+		if((q = readobject(p->commit->parent[idx[nall]])) == nil){
+			werrstr("bad commit %H", p->commit->parent[idx[nall]]);
+			goto error;
+		}
+		if(q->type != GCommit){
+			werrstr("not commit: %H", q->hash);
+			goto error;
+		}
+		unref(p);
+		p = q;
 		nall++;
 	}
 	free(all);
 	qsort(ev->stk + mark, ev->nstk - mark, sizeof(Object*), objdatecmp);
 	return 0;
+error:
+	free(all);
+	return -1;
 }
 
 int