dirstate: use tuple interface to fix leak in pack_dirstate() stable
authorYuya Nishihara <yuya@tcha.org>
Wed, 05 Sep 2018 20:52:22 +0900
branchstable
changeset 39422 adacefb0b7ea
parent 39421 ad76032d27da
child 39423 ca77788c81bc
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.
mercurial/cext/parsers.c
mercurial/dirstate.py
mercurial/policy.py
--- a/mercurial/cext/parsers.c	Wed Sep 05 22:10:41 2018 +0900
+++ b/mercurial/cext/parsers.c	Wed Sep 05 20:52:22 2018 +0900
@@ -382,12 +382,12 @@
 	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 @@
 
 	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 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)
 {
--- a/mercurial/dirstate.py	Wed Sep 05 22:10:41 2018 +0900
+++ b/mercurial/dirstate.py	Wed Sep 05 20:52:22 2018 +0900
@@ -1392,9 +1392,9 @@
 
             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!'))
--- a/mercurial/policy.py	Wed Sep 05 22:10:41 2018 +0900
+++ b/mercurial/policy.py	Wed Sep 05 20:52:22 2018 +0900
@@ -69,7 +69,7 @@
     (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