[PATCH 3 of 5 STABLE] dirstate: use tuple interface to fix leak in pack_dirstate()

Yuya Nishihara yuya at tcha.org
Wed Sep 5 09:58:25 EDT 2018


# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1536148342 -32400
#      Wed Sep 05 20:52:22 2018 +0900
# Branch stable
# Node ID a55517cd5da69e41a7fafa0b46379920a5bda07f
# Parent  c1556580015504061ab7d1e48e81f5514adc60ac
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, &copymap, &pl, &now))
+	if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
+	                      &PyDict_Type, &copymap, &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


More information about the Mercurial-devel mailing list