summaryrefslogtreecommitdiffstats
path: root/Modules/_functoolsmodule.c
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2016-02-02 16:45:59 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2016-02-02 16:45:59 (GMT)
commit71b71763c5ae3fca539c3faff69ebdeaeaa84a80 (patch)
tree3e197a637d3f7ba249d0172be7f718ec3fde3842 /Modules/_functoolsmodule.c
parent1d269c106740e855cb53f91a27ed85aaf1cf84f5 (diff)
downloadcpython-71b71763c5ae3fca539c3faff69ebdeaeaa84a80.zip
cpython-71b71763c5ae3fca539c3faff69ebdeaeaa84a80.tar.gz
cpython-71b71763c5ae3fca539c3faff69ebdeaeaa84a80.tar.bz2
Issue #25945: Fixed bugs in functools.partial.
Fixed a crash when unpickle the functools.partial object with wrong state. Fixed a leak in failed functools.partial constructor. "args" and "keywords" attributes of functools.partial have now always types tuple and dict correspondingly.
Diffstat (limited to 'Modules/_functoolsmodule.c')
-rw-r--r--Modules/_functoolsmodule.c66
1 files changed, 41 insertions, 25 deletions
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index 2ba92ba..2ad556d 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -128,7 +128,6 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
Py_INCREF(func);
pto->args = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
if (pto->args == NULL) {
- pto->kw = NULL;
Py_DECREF(pto);
return NULL;
}
@@ -138,10 +137,6 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
return NULL;
}
-
- pto->weakreflist = NULL;
- pto->dict = NULL;
-
return (PyObject *)pto;
}
@@ -162,11 +157,11 @@ static PyObject *
partial_call(partialobject *pto, PyObject *args, PyObject *kw)
{
PyObject *ret;
- PyObject *argappl = NULL, *kwappl = NULL;
+ PyObject *argappl, *kwappl;
assert (PyCallable_Check(pto->fn));
assert (PyTuple_Check(pto->args));
- assert (pto->kw == Py_None || PyDict_Check(pto->kw));
+ assert (PyDict_Check(pto->kw));
if (PyTuple_GET_SIZE(pto->args) == 0) {
argappl = args;
@@ -178,11 +173,12 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kw)
argappl = PySequence_Concat(pto->args, args);
if (argappl == NULL)
return NULL;
+ assert(PyTuple_Check(argappl));
}
- if (pto->kw == Py_None) {
+ if (PyDict_Size(pto->kw) == 0) {
kwappl = kw;
- Py_XINCREF(kw);
+ Py_XINCREF(kwappl);
} else {
kwappl = PyDict_Copy(pto->kw);
if (kwappl == NULL) {
@@ -289,25 +285,45 @@ PyObject *
partial_setstate(partialobject *pto, PyObject *state)
{
PyObject *fn, *fnargs, *kw, *dict;
- if (!PyArg_ParseTuple(state, "OOOO",
- &fn, &fnargs, &kw, &dict))
+
+ if (!PyTuple_Check(state) ||
+ !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
+ !PyCallable_Check(fn) ||
+ !PyTuple_Check(fnargs) ||
+ (kw != Py_None && !PyDict_Check(kw)))
+ {
+ PyErr_SetString(PyExc_TypeError, "invalid partial state");
return NULL;
- Py_XDECREF(pto->fn);
- Py_XDECREF(pto->args);
- Py_XDECREF(pto->kw);
- Py_XDECREF(pto->dict);
- pto->fn = fn;
- pto->args = fnargs;
- pto->kw = kw;
- if (dict != Py_None) {
- pto->dict = dict;
- Py_INCREF(dict);
- } else {
- pto->dict = NULL;
}
+
+ if(!PyTuple_CheckExact(fnargs))
+ fnargs = PySequence_Tuple(fnargs);
+ else
+ Py_INCREF(fnargs);
+ if (fnargs == NULL)
+ return NULL;
+
+ if (kw == Py_None)
+ kw = PyDict_New();
+ else if(!PyDict_CheckExact(kw))
+ kw = PyDict_Copy(kw);
+ else
+ Py_INCREF(kw);
+ if (kw == NULL) {
+ Py_DECREF(fnargs);
+ return NULL;
+ }
+
Py_INCREF(fn);
- Py_INCREF(fnargs);
- Py_INCREF(kw);
+ if (dict == Py_None)
+ dict = NULL;
+ else
+ Py_INCREF(dict);
+
+ Py_SETREF(pto->fn, fn);
+ Py_SETREF(pto->args, fnargs);
+ Py_SETREF(pto->kw, kw);
+ Py_SETREF(pto->dict, dict);
Py_RETURN_NONE;
}