# HG changeset patch
# User Yuya Nishihara <y...@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
_______________________________________________
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Reply via email to