From f7c623bbb97e17d613c6e080393f10f302b89b82 Mon Sep 17 00:00:00 2001 From: Shamil Abdulaev Date: Tue, 1 Sep 2026 16:20:44 +0300 Subject: [PATCH 1/4] Fix tp_clear slot signature for operator.methodcaller --- .../Library/2026-09-01-12-00-00.gh-issue-156762.Qk3Vt1.rst | 4 ++++ Modules/_operator.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-09-01-12-00-00.gh-issue-156762.Qk3Vt1.rst diff --git a/Misc/NEWS.d/next/Library/2026-09-01-12-00-00.gh-issue-156762.Qk3Vt1.rst b/Misc/NEWS.d/next/Library/2026-09-01-12-00-00.gh-issue-156762.Qk3Vt1.rst new file mode 100644 index 000000000000000..f6f9bb038f4909d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-01-12-00-00.gh-issue-156762.Qk3Vt1.rst @@ -0,0 +1,4 @@ +Fix undefined behaviour in :class:`operator.methodcaller`: its +:c:member:`~PyTypeObject.tp_clear` slot function returned ``void`` instead of +``int``, so the garbage collector called it through an incompatible function +type. Patched by Shamil Abdulaev. diff --git a/Modules/_operator.c b/Modules/_operator.c index 417403dc4c10c11..a0843971efe13e6 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -1740,7 +1740,7 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)mc; } -static void +static int methodcaller_clear(PyObject *op) { methodcallerobject *mc = methodcallerobject_CAST(op); @@ -1749,6 +1749,7 @@ methodcaller_clear(PyObject *op) Py_CLEAR(mc->kwds); Py_CLEAR(mc->vectorcall_args); Py_CLEAR(mc->vectorcall_kwnames); + return 0; } static void From 076c0cde578d1365e28460bf361a33c6caf035e7 Mon Sep 17 00:00:00 2001 From: Shamil Abdulaev Date: Fri, 11 Sep 2026 15:44:14 +0300 Subject: [PATCH 2/4] test(operator): cover methodcaller cyclic GC --- Lib/test/test_operator.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py index 1f89986c777ced8..b58a43e8b76065b 100644 --- a/Lib/test/test_operator.py +++ b/Lib/test/test_operator.py @@ -2,6 +2,7 @@ import inspect import pickle import sys +import weakref from decimal import Decimal from fractions import Fraction @@ -511,6 +512,20 @@ def return_arguments(self, *args, **kwds): f = operator.methodcaller('return_arguments', *many_positional_arguments, **many_kw_arguments) self.assertEqual(f(a), (many_positional_arguments, many_kw_arguments)) + def test_methodcaller_cyclic_gc(self): + operator = self.module + + class C: + pass + + c = C() + ref = weakref.ref(c) + c.m = operator.methodcaller('foo', c) + del c + + support.gc_collect() + self.assertIsNone(ref()) + def test_inplace(self): operator = self.module class C(object): From 73d41a9112a42aa798ed20930cd115604ce07e3e Mon Sep 17 00:00:00 2001 From: Shamil Date: Sun, 13 Sep 2026 10:36:56 +0300 Subject: [PATCH 3/4] Update Lib/test/test_operator.py Co-authored-by: Victor Stinner --- Lib/test/test_operator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py index b58a43e8b76065b..68c8aadeb50823b 100644 --- a/Lib/test/test_operator.py +++ b/Lib/test/test_operator.py @@ -513,6 +513,7 @@ def return_arguments(self, *args, **kwds): self.assertEqual(f(a), (many_positional_arguments, many_kw_arguments)) def test_methodcaller_cyclic_gc(self): + # gh-156762: Check for undefined behavior on calling methodcaller_clear() operator = self.module class C: From 50f96fab5ddaff5998ebfe7646467141626914d8 Mon Sep 17 00:00:00 2001 From: Shamil Abdulaev Date: Sun, 13 Sep 2026 10:44:30 +0300 Subject: [PATCH 4/4] chore(news): move methodcaller entry to Core_and_Builtins --- .../2026-09-13-10-43-24.gh-issue-156762.Kbf2mo.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Misc/NEWS.d/next/{Library/2026-09-01-12-00-00.gh-issue-156762.Qk3Vt1.rst => Core_and_Builtins/2026-09-13-10-43-24.gh-issue-156762.Kbf2mo.rst} (100%) diff --git a/Misc/NEWS.d/next/Library/2026-09-01-12-00-00.gh-issue-156762.Qk3Vt1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-13-10-43-24.gh-issue-156762.Kbf2mo.rst similarity index 100% rename from Misc/NEWS.d/next/Library/2026-09-01-12-00-00.gh-issue-156762.Qk3Vt1.rst rename to Misc/NEWS.d/next/Core_and_Builtins/2026-09-13-10-43-24.gh-issue-156762.Kbf2mo.rst