cpython: 0285173d81b4 (original) (raw)
--- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -16,6 +16,11 @@ except ImportError:
Skip this test if the _testcapi module isn't available.
_testcapi = support.import_module('_testcapi') +class CAPITest(unittest.TestCase): +
+ @unittest.skipUnless(threading, 'Threading required for this test.') class TestPendingCalls(unittest.TestCase): @@ -132,7 +137,7 @@ def test_main(): except _testcapi.error: raise support.TestFailed, sys.exc_info()[1]
if name == "main": test_main()
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 2.7.12? Core and Builtins ----------------- +- Issue #26168: Fixed possible refleaks in failing Py_BuildValue() with the "N"
--- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -931,6 +931,100 @@ test_L_code(PyObject self) #endif / ifdef HAVE_LONG_LONG */ static PyObject * +return_none(void *unused) +{
+} + +static PyObject * +raise_error(void *unused) +{
+} + +static int +test_buildvalue_N_error(const char *fmt) +{
- Py_INCREF(arg);
- res = Py_BuildValue(fmt, return_none, NULL, arg);
- if (res == NULL) {
return -1;[](#l3.32)
- }
- Py_DECREF(res);
- if (Py_REFCNT(arg) != 1) {
PyErr_Format(TestError, "test_buildvalue_N: "[](#l3.36)
"arg was not decrefed in successful "[](#l3.37)
"Py_BuildValue(\"%s\")", fmt);[](#l3.38)
return -1;[](#l3.39)
- }
- Py_INCREF(arg);
- res = Py_BuildValue(fmt, raise_error, NULL, arg);
- if (res != NULL || !PyErr_Occurred()) {
PyErr_Format(TestError, "test_buildvalue_N: "[](#l3.45)
"Py_BuildValue(\"%s\") didn't complain", fmt);[](#l3.46)
return -1;[](#l3.47)
- }
- PyErr_Clear();
- if (Py_REFCNT(arg) != 1) {
PyErr_Format(TestError, "test_buildvalue_N: "[](#l3.51)
"arg was not decrefed in failed "[](#l3.52)
"Py_BuildValue(\"%s\")", fmt);[](#l3.53)
return -1;[](#l3.54)
- }
- Py_DECREF(arg);
- return 0;
+} + +static PyObject * +test_buildvalue_N(PyObject *self, PyObject *noargs) +{
- arg = PyList_New(0);
- if (arg == NULL) {
return NULL;[](#l3.67)
- }
- Py_INCREF(arg);
- res = Py_BuildValue("N", arg);
- if (res == NULL) {
return NULL;[](#l3.72)
- }
- if (res != arg) {
return raiseTestError("test_buildvalue_N",[](#l3.75)
"Py_BuildValue(\"N\") returned wrong result");[](#l3.76)
- }
- if (Py_REFCNT(arg) != 2) {
return raiseTestError("test_buildvalue_N",[](#l3.79)
"arg was not decrefed in Py_BuildValue(\"N\")");[](#l3.80)
- }
- Py_DECREF(res);
- Py_DECREF(arg);
- if (test_buildvalue_N_error("O&N") < 0)
return NULL;[](#l3.86)
- if (test_buildvalue_N_error("(O&N)") < 0)
return NULL;[](#l3.88)
- if (test_buildvalue_N_error("[O&N]") < 0)
return NULL;[](#l3.90)
- if (test_buildvalue_N_error("{O&N}") < 0)
return NULL;[](#l3.92)
- if (test_buildvalue_N_error("{()O&(())N}") < 0)
return NULL;[](#l3.94)
+} + + +static PyObject * get_args(PyObject *self, PyObject *args) { if (args == NULL) { @@ -2414,6 +2508,7 @@ static PyMethodDef TestMethods[] = { {"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS, PyDoc_STR("This is a pretty normal docstring.")},
- {"test_buildvalue_N", test_buildvalue_N, METH_NOARGS}, {"get_args", get_args, METH_VARARGS}, {"get_kwargs", (PyCFunction)get_kwargs, METH_VARARGS|METH_KEYWORDS}, {"getargs_tuple", getargs_tuple, METH_VARARGS},
--- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -156,48 +156,83 @@ static PyObject do_mkdict(const char, static PyObject do_mkvalue(const char, va_list *, int); +static void +do_ignore(const char **p_format, va_list *p_va, int endchar, int n, int flags) +{
- PyObject *v;
- int i;
- assert(PyErr_Occurred());
- v = PyTuple_New(n);
- for (i = 0; i < n; i++) {
PyObject *exception, *value, *tb, *w;[](#l4.15)
PyErr_Fetch(&exception, &value, &tb);[](#l4.16)
w = do_mkvalue(p_format, p_va, flags);[](#l4.17)
PyErr_Restore(exception, value, tb);[](#l4.18)
if (w != NULL) {[](#l4.19)
if (v != NULL) {[](#l4.20)
PyTuple_SET_ITEM(v, i, w);[](#l4.21)
}[](#l4.22)
else {[](#l4.23)
Py_DECREF(w);[](#l4.24)
}[](#l4.25)
}[](#l4.26)
- }
- Py_XDECREF(v);
- if (**p_format != endchar) {
PyErr_SetString(PyExc_SystemError,[](#l4.30)
"Unmatched paren in format");[](#l4.31)
return;[](#l4.32)
- }
- if (endchar)
++*p_format;[](#l4.35)
+} + static PyObject * do_mkdict(const char **p_format, va_list *p_va, int endchar, int n, int flags) { PyObject *d; int i;
- if (n % 2) {
PyErr_SetString(PyExc_SystemError,[](#l4.48)
"Bad dict format");[](#l4.49)
do_ignore(p_format, p_va, endchar, n, flags);[](#l4.50) return NULL;[](#l4.51)
- } /* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */
- if ((d = PyDict_New()) == NULL) {
do_ignore(p_format, p_va, endchar, n, flags);[](#l4.56)
return NULL;[](#l4.57)
- } for (i = 0; i < n; i+= 2) { PyObject *k, *v;
int err;[](#l4.61)
+ k = do_mkvalue(p_format, p_va, flags); if (k == NULL) {
itemfailed = 1;[](#l4.65)
Py_INCREF(Py_None);[](#l4.66)
k = Py_None;[](#l4.67)
}[](#l4.68)
v = do_mkvalue(p_format, p_va, flags);[](#l4.69)
if (v == NULL) {[](#l4.70)
itemfailed = 1;[](#l4.71)
Py_INCREF(Py_None);[](#l4.72)
v = Py_None;[](#l4.73)
}[](#l4.74)
err = PyDict_SetItem(d, k, v);[](#l4.75)
Py_DECREF(k);[](#l4.76)
Py_DECREF(v);[](#l4.77)
if (err < 0 || itemfailed) {[](#l4.78)
do_ignore(p_format, p_va, endchar, n - i - 1, flags);[](#l4.79) Py_DECREF(d);[](#l4.80) return NULL;[](#l4.81) }[](#l4.82)
v = do_mkvalue(p_format, p_va, flags);[](#l4.83)
if (v == NULL || PyDict_SetItem(d, k, v) < 0) {[](#l4.84)
do_ignore(p_format, p_va, endchar, n - i - 2, flags);[](#l4.85)
Py_DECREF(k);[](#l4.86)
Py_XDECREF(v);[](#l4.87)
Py_DECREF(d);[](#l4.88)
return NULL;[](#l4.89)
}[](#l4.90)
Py_DECREF(k);[](#l4.91)
}Py_DECREF(v);[](#l4.92)
d = NULL;[](#l4.97) PyErr_SetString(PyExc_SystemError,[](#l4.98) "Unmatched paren in format");[](#l4.99)
@@ -207,29 +242,24 @@ do_mklist(const char **p_format, va_list { PyObject *v; int i;
- int itemfailed = 0; if (n < 0) return NULL;
- v = PyList_New(n);
- if (v == NULL)
/* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */return NULL;[](#l4.116)
- v = PyList_New(n);
- if (v == NULL) {
do_ignore(p_format, p_va, endchar, n, flags);[](#l4.121)
return NULL;[](#l4.122)
- } for (i = 0; i < n; i++) { PyObject *w = do_mkvalue(p_format, p_va, flags); if (w == NULL) {
itemfailed = 1;[](#l4.127)
Py_INCREF(Py_None);[](#l4.128)
w = Py_None;[](#l4.129)
do_ignore(p_format, p_va, endchar, n - i - 1, flags);[](#l4.130)
Py_DECREF(v);[](#l4.131)
} -return NULL;[](#l4.132) }[](#l4.133) PyList_SET_ITEM(v, i, w);[](#l4.134)
- if (itemfailed) {
/* do_mkvalue() should have already set an error */[](#l4.138)
Py_DECREF(v);[](#l4.139)
return NULL;[](#l4.140)
- } if (**p_format != endchar) { Py_DECREF(v); PyErr_SetString(PyExc_SystemError,
@@ -257,27 +287,23 @@ do_mktuple(const char **p_format, va_lis { PyObject *v; int i;
- int itemfailed = 0; if (n < 0) return NULL;
- if ((v = PyTuple_New(n)) == NULL)
/* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */return NULL;[](#l4.153)
- if ((v = PyTuple_New(n)) == NULL) {
do_ignore(p_format, p_va, endchar, n, flags);[](#l4.157)
return NULL;[](#l4.158)
- } for (i = 0; i < n; i++) { PyObject *w = do_mkvalue(p_format, p_va, flags); if (w == NULL) {
itemfailed = 1;[](#l4.163)
Py_INCREF(Py_None);[](#l4.164)
w = Py_None;[](#l4.165)