From 794cf182304c04eb5a814f0fa8a39c343c6de835 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Mon, 27 Oct 2025 18:24:45 +0500 Subject: [PATCH 1/3] Fix setstate for functools.partial C-module --- Lib/test/test_functools.py | 3 +++ Modules/_functoolsmodule.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index f7e09fd771eaf2d..ce9e7f6d57dd3c8 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -406,6 +406,7 @@ def test_setstate(self): def test_setstate_errors(self): f = self.partial(signature) + self.assertRaises(TypeError, f.__setstate__, (capture, (), {})) self.assertRaises(TypeError, f.__setstate__, (capture, (), {}, {}, None)) self.assertRaises(TypeError, f.__setstate__, [capture, (), {}, None]) @@ -413,6 +414,8 @@ def test_setstate_errors(self): self.assertRaises(TypeError, f.__setstate__, (capture, None, {}, None)) self.assertRaises(TypeError, f.__setstate__, (capture, [], {}, None)) self.assertRaises(TypeError, f.__setstate__, (capture, (), [], None)) + self.assertRaises(TypeError, f.__setstate__, (capture, (), {}, ())) + self.assertRaises(TypeError, f.__setstate__, (capture, (), {}, 'test')) def test_setstate_subclasses(self): f = self.partial(signature) diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 44b1a302d49ed21..72e4719845e6c20 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -778,7 +778,8 @@ partial_setstate(PyObject *self, PyObject *state) if (!PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) || !PyCallable_Check(fn) || !PyTuple_Check(fnargs) || - (kw != Py_None && !PyDict_Check(kw))) + (kw != Py_None && !PyDict_Check(kw))|| + (dict != Py_None && !PyDict_Check(dict))) { PyErr_SetString(PyExc_TypeError, "invalid partial state"); return NULL; From 1936299748b6e83ef280ad1eeb4a2f802eff3950 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Mon, 27 Oct 2025 18:29:55 +0500 Subject: [PATCH 2/3] Add news --- .../next/Library/2025-10-27-18-29-42.gh-issue-140590.LT9HHn.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-10-27-18-29-42.gh-issue-140590.LT9HHn.rst diff --git a/Misc/NEWS.d/next/Library/2025-10-27-18-29-42.gh-issue-140590.LT9HHn.rst b/Misc/NEWS.d/next/Library/2025-10-27-18-29-42.gh-issue-140590.LT9HHn.rst new file mode 100644 index 000000000000000..802183673cfaccf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-10-27-18-29-42.gh-issue-140590.LT9HHn.rst @@ -0,0 +1,2 @@ +Fix arguments checking for the :meth:`!functools.partial.__setstate__` that +may lead to internal state corruption and crash. Patch by Sergey Miryanov. From 2fd2fcaea19b3e667c0e5bbb0b6adc10824d86cb Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Mon, 27 Oct 2025 20:00:14 +0500 Subject: [PATCH 3/3] Update Modules/_functoolsmodule.c Co-authored-by: Mikhail Efimov --- Modules/_functoolsmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 72e4719845e6c20..5773083ff68b461 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -778,7 +778,7 @@ partial_setstate(PyObject *self, PyObject *state) if (!PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) || !PyCallable_Check(fn) || !PyTuple_Check(fnargs) || - (kw != Py_None && !PyDict_Check(kw))|| + (kw != Py_None && !PyDict_Check(kw)) || (dict != Py_None && !PyDict_Check(dict))) { PyErr_SetString(PyExc_TypeError, "invalid partial state");