# HG changeset patch # User Yuya Nishihara # Date 2018-09-05 11:52:22 # Node ID adacefb0b7ea4abbb802edbf9f83e89f68998f8b # Parent ad76032d27da158dc0a067a3a1199104261b7476 dirstate: use tuple interface to fix leak in pack_dirstate() Spotted by ASAN. Unlike PyTuple_GET_ITEM(), PySequence_ITEM() returns a new reference. This bug could be fixed by inserting Py_CLEAR() and Py_XDECREF() appropriately, but I think requiring a tuple object is simpler and less error-prone. The cext version is jumped to 10 since 6..9 are used in the default branch. We'll need to bump it again at merge. diff --git a/mercurial/cext/parsers.c b/mercurial/cext/parsers.c --- a/mercurial/cext/parsers.c +++ b/mercurial/cext/parsers.c @@ -382,12 +382,12 @@ static PyObject *pack_dirstate(PyObject char *p, *s; int now; - if (!PyArg_ParseTuple(args, "O!O!Oi:pack_dirstate", &PyDict_Type, &map, - &PyDict_Type, ©map, &pl, &now)) + if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map, + &PyDict_Type, ©map, &PyTuple_Type, &pl, &now)) return NULL; - if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) { - PyErr_SetString(PyExc_TypeError, "expected 2-element sequence"); + if (PyTuple_Size(pl) != 2) { + PyErr_SetString(PyExc_TypeError, "expected 2-element tuple"); return NULL; } @@ -416,14 +416,14 @@ static PyObject *pack_dirstate(PyObject p = PyBytes_AS_STRING(packobj); - pn = PySequence_ITEM(pl, 0); + pn = PyTuple_GET_ITEM(pl, 0); if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) { PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash"); goto bail; } memcpy(p, s, l); p += 20; - pn = PySequence_ITEM(pl, 1); + pn = PyTuple_GET_ITEM(pl, 1); if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) { PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash"); goto bail; @@ -713,7 +713,7 @@ void dirs_module_init(PyObject *mod); void manifest_module_init(PyObject *mod); void revlog_module_init(PyObject *mod); -static const int version = 5; +static const int version = 10; static void module_init(PyObject *mod) { diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -1392,9 +1392,9 @@ class dirstatemap(object): l = len(st) if l == 40: - self._parents = st[:20], st[20:40] + self._parents = (st[:20], st[20:40]) elif l == 0: - self._parents = [nullid, nullid] + self._parents = (nullid, nullid) else: raise error.Abort(_('working directory state appears ' 'damaged!')) diff --git a/mercurial/policy.py b/mercurial/policy.py --- a/mercurial/policy.py +++ b/mercurial/policy.py @@ -69,7 +69,7 @@ def _importfrom(pkgname, modname): (r'cext', r'bdiff'): 3, (r'cext', r'mpatch'): 1, (r'cext', r'osutil'): 4, - (r'cext', r'parsers'): 5, + (r'cext', r'parsers'): 10, } # map import request to other package or module