reachableroots: verify integer range of heads argument (
issue4775)
Now it raises IndexError instead of SEGV for 'wdir()' as it was before.
--- a/mercurial/parsers.c Thu Aug 13 18:29:38 2015 +0900
+++ b/mercurial/parsers.c Thu Aug 13 18:38:46 2015 +0900
@@ -1167,6 +1167,10 @@
numheads = PyList_GET_SIZE(heads);
for (i = 0; i < numheads; i++) {
revnum = PyInt_AS_LONG(PyList_GET_ITEM(heads, i));
+ if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
+ PyErr_SetString(PyExc_IndexError, "head out of range");
+ goto bail;
+ }
if (seen[revnum+1] == 0) {
tovisit[lentovisit++] = revnum;
seen[revnum+1]=1;
--- a/tests/test-parseindex.t Thu Aug 13 18:29:38 2015 +0900
+++ b/tests/test-parseindex.t Thu Aug 13 18:38:46 2015 +0900
@@ -60,9 +60,40 @@
$ cd ..
-Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
+#if no-pure
+
+Test SEGV caused by bad revision passed to reachableroots() (issue4775):
+
+ $ cd a
-#if no-pure
+ $ python <<EOF
+ > from mercurial import changelog, scmutil
+ > cl = changelog.changelog(scmutil.vfs('.hg/store'))
+ > print 'goods:'
+ > for head in [0, len(cl) - 1, -1]:
+ > print'%s: %r' % (head, cl.reachableroots(0, [head], set([0])))
+ > print 'bads:'
+ > for head in [len(cl), 10000, -2, -10000]:
+ > print '%s:' % head,
+ > try:
+ > cl.reachableroots(0, [head], set([0]))
+ > print 'uncaught buffer overflow?'
+ > except IndexError as inst:
+ > print inst
+ > EOF
+ goods:
+ 0: <baseset [0]>
+ 1: <baseset [0]>
+ -1: <baseset []>
+ bads:
+ 2: head out of range
+ 10000: head out of range
+ -2: head out of range
+ -10000: head out of range
+
+ $ cd ..
+
+Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
$ mkdir invalidparent
$ cd invalidparent