diff -r a9c9e4054f3f Lib/test/test_capi.py --- a/Lib/test/test_capi.py Mon Feb 08 09:26:57 2016 +0200 +++ b/Lib/test/test_capi.py Mon Feb 08 15:03:34 2016 +0200 @@ -236,6 +236,9 @@ class CAPITest(unittest.TestCase): 'return_result_with_error.* ' 'returned a result with an error set') + def test_buildvalue_N(self): + _testcapi.test_buildvalue_N() + @unittest.skipUnless(threading, 'Threading required for this test.') class TestPendingCalls(unittest.TestCase): diff -r a9c9e4054f3f Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Mon Feb 08 09:26:57 2016 +0200 +++ b/Modules/_testcapimodule.c Mon Feb 08 15:03:34 2016 +0200 @@ -872,6 +872,84 @@ test_L_code(PyObject *self) #endif /* ifdef HAVE_LONG_LONG */ +static int +test_buildvalue_N_error(const char *fmt) +{ + PyObject *arg, *res; + + arg = PyList_New(0); + if (arg == NULL) { + return -1; + } + + Py_INCREF(arg); + res = Py_BuildValue(fmt, "a", arg); + if (res == NULL) { + return -1; + } + Py_DECREF(res); + if (Py_REFCNT(arg) != 1) { + PyErr_Format(TestError, "test_buildvalue_N: " + "arg was not decrefed in successful " + "Py_BuildValue(\"%s\")", fmt); + return -1; + } + + Py_INCREF(arg); + res = Py_BuildValue(fmt, "\x80", arg); + if (res != NULL || !PyErr_Occurred()) { + PyErr_Format(TestError, "test_buildvalue_N: " + "Py_BuildValue(\"%s\") didn't complain", fmt); + return -1; + } + PyErr_Clear(); + if (Py_REFCNT(arg) != 1) { + PyErr_Format(TestError, "test_buildvalue_N: " + "arg was not decrefed in failed " + "Py_BuildValue(\"%s\")", fmt); + return -1; + } + Py_DECREF(arg); + return 0; +} + +static PyObject * +test_buildvalue_N(PyObject *self, PyObject *args) +{ + PyObject *arg, *res; + + arg = PyList_New(0); + Py_INCREF(arg); + res = Py_BuildValue("N", arg); + if (res == NULL) { + return NULL; + } + if (res != arg) { + return raiseTestError("test_buildvalue_N", + "Py_BuildValue(\"N\") returned wrong result"); + } + if (Py_REFCNT(arg) != 2) { + return raiseTestError("test_buildvalue_N", + "arg was not decrefed in Py_BuildValue(\"N\")"); + } + Py_DECREF(res); + Py_DECREF(arg); + + if (test_buildvalue_N_error("sN") < 0) + return NULL; + if (test_buildvalue_N_error("(sN)") < 0) + return NULL; + if (test_buildvalue_N_error("[sN]") < 0) + return NULL; + if (test_buildvalue_N_error("{sN}") < 0) + return NULL; + if (test_buildvalue_N_error("{()s(())N}") < 0) + return NULL; + + Py_RETURN_NONE; +} + + /* Test tuple argument processing */ static PyObject * getargs_tuple(PyObject *self, PyObject *args) @@ -3653,6 +3731,7 @@ static PyMethodDef TestMethods[] = { {"test_pep3118_obsolete_write_locks", (PyCFunction)test_pep3118_obsolete_write_locks, METH_NOARGS}, #endif {"getbuffer_with_null_view", getbuffer_with_null_view, METH_O}, + {"test_buildvalue_N", test_buildvalue_N, METH_VARARGS}, {"getargs_tuple", getargs_tuple, METH_VARARGS}, {"getargs_keywords", (PyCFunction)getargs_keywords, METH_VARARGS|METH_KEYWORDS}, diff -r a9c9e4054f3f Python/modsupport.c --- a/Python/modsupport.c Mon Feb 08 09:26:57 2016 +0200 +++ b/Python/modsupport.c Mon Feb 08 15:03:34 2016 +0200 @@ -71,40 +71,60 @@ do_mkdict(const char **p_format, va_list int itemfailed = 0; if (n < 0) return NULL; - if ((d = PyDict_New()) == NULL) - return NULL; /* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */ + if ((d = PyDict_New()) == NULL) { + itemfailed = 1; + } for (i = 0; i < n; i+= 2) { PyObject *k, *v; - int err; - k = do_mkvalue(p_format, p_va, flags); + + if (itemfailed) { + PyObject *exception, *value, *tb; + PyErr_Fetch(&exception, &value, &tb); + k = do_mkvalue(p_format, p_va, flags); + PyErr_Restore(exception, value, tb); + } + else { + k = do_mkvalue(p_format, p_va, flags); + } if (k == NULL) { itemfailed = 1; Py_INCREF(Py_None); k = Py_None; } - v = do_mkvalue(p_format, p_va, flags); + if (itemfailed) { + PyObject *exception, *value, *tb; + PyErr_Fetch(&exception, &value, &tb); + v = do_mkvalue(p_format, p_va, flags); + PyErr_Restore(exception, value, tb); + } + else { + v = do_mkvalue(p_format, p_va, flags); + } if (v == NULL) { itemfailed = 1; Py_INCREF(Py_None); v = Py_None; } - err = PyDict_SetItem(d, k, v); + if (d != NULL && PyDict_SetItem(d, k, v) < 0) { + itemfailed = 1; + } Py_DECREF(k); Py_DECREF(v); - if (err < 0 || itemfailed) { - Py_DECREF(d); - return NULL; - } } - if (d != NULL && **p_format != endchar) { + if (itemfailed) { + /* Error was set when itemfailed was set to 1 */ + Py_XDECREF(d); + return NULL; + } + if (**p_format != endchar) { Py_DECREF(d); - d = NULL; PyErr_SetString(PyExc_SystemError, "Unmatched paren in format"); + return NULL; } - else if (endchar) + if (endchar) ++*p_format; return d; } @@ -117,24 +137,40 @@ do_mklist(const char **p_format, va_list int itemfailed = 0; if (n < 0) return NULL; - v = PyList_New(n); - if (v == NULL) - return NULL; /* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */ + v = PyList_New(n); + if (v == NULL) { + itemfailed = 1; + } for (i = 0; i < n; i++) { - PyObject *w = do_mkvalue(p_format, p_va, flags); + PyObject *w; + + if (itemfailed) { + PyObject *exception, *value, *tb; + PyErr_Fetch(&exception, &value, &tb); + w = do_mkvalue(p_format, p_va, flags); + PyErr_Restore(exception, value, tb); + } + else { + w = do_mkvalue(p_format, p_va, flags); + } if (w == NULL) { itemfailed = 1; Py_INCREF(Py_None); w = Py_None; } - PyList_SET_ITEM(v, i, w); + if (v != NULL) { + PyList_SET_ITEM(v, i, w); + } + else { + Py_DECREF(w); + } } if (itemfailed) { - /* do_mkvalue() should have already set an error */ - Py_DECREF(v); + /* Error was set when itemfailed was set to 1 */ + Py_XDECREF(v); return NULL; } if (**p_format != endchar) { @@ -156,10 +192,11 @@ do_mktuple(const char **p_format, va_lis int itemfailed = 0; if (n < 0) return NULL; - if ((v = PyTuple_New(n)) == NULL) - return NULL; /* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */ + if ((v = PyTuple_New(n)) == NULL) { + itemfailed = 1; + } for (i = 0; i < n; i++) { PyObject *w; @@ -177,11 +214,16 @@ do_mktuple(const char **p_format, va_lis Py_INCREF(Py_None); w = Py_None; } - PyTuple_SET_ITEM(v, i, w); + if (v != NULL) { + PyTuple_SET_ITEM(v, i, w); + } + else { + Py_DECREF(w); + } } if (itemfailed) { - /* do_mkvalue() should have already set an error */ - Py_DECREF(v); + /* Error was set when itemfailed was set to 1 */ + Py_XDECREF(v); return NULL; } if (**p_format != endchar) {