# HG changeset patch # User Yuya Nishihara # Date 2015-08-13 09:38:46 # Node ID 44705659da94f8080886277dd6b2ec3bf17ce93a # Parent c8d41c9c23c7e53fcc37b01cdd34f661dc1ff848 reachableroots: verify integer range of heads argument (issue4775) Now it raises IndexError instead of SEGV for 'wdir()' as it was before. diff --git a/mercurial/parsers.c b/mercurial/parsers.c --- a/mercurial/parsers.c +++ b/mercurial/parsers.c @@ -1167,6 +1167,10 @@ static PyObject *reachableroots(indexObj 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; diff --git a/tests/test-parseindex.t b/tests/test-parseindex.t --- a/tests/test-parseindex.t +++ b/tests/test-parseindex.t @@ -60,9 +60,40 @@ We approximate that by reducing the read $ 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 < 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: + 1: + -1: + 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