From 506f0db15ea04f918b4c4598a7ad5c86aaadda61 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sun, 7 Jun 2026 22:22:31 +0200 Subject: [PATCH] gh-151060: Fix sum() deallocating a float subclass as an exact float The complex-total fast path in builtin_sum_impl() guarded with PyFloat_Check() (which accepts subclasses) but freed the item with _Py_DECREF_SPECIALIZED(item, _PyFloat_ExactDealloc), which assumes an exact float. A float subclass instance reaching refcount 0 in that loop aborts on an assertion in debug builds, and in release builds skips the subclass tp_dealloc (type refcount leak, __del__ never runs, subclass object pushed onto the float freelist). Use PyFloat_CheckExact() instead, matching the float-total branch, so subclass instances fall through to the generic PyNumber_Add() path. Co-Authored-By: Claude Opus 4.8 (1M context) --- Lib/test/test_builtin.py | 12 ++++++++++++ .../2026-06-07-22-03-20.gh-issue-151060.tdexEE.rst | 2 ++ Python/bltinmodule.c | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-07-22-03-20.gh-issue-151060.tdexEE.rst diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 1d2c105ac047e18..38599cc3afb9c12 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -2229,6 +2229,18 @@ def __getitem__(self, index): self.assertComplexesAreIdentical(sum([1.0, complex(1, -0.0)]), complex(2, -0.0)) + def test_sum_float_subclass(self): + # gh-151060: the C fast-sum loop must not free a float subclass with + # the exact-float deallocator. A generator keeps each item's only + # reference in sum(), so the specialized DECREF runs the deallocator. + class F(float): + count = 0 + def __del__(self): + F.count += 1 + + self.assertEqual(sum((F(i) for i in range(5)), 1j), complex(10, 1)) + self.assertEqual(F.count, 5) + @requires_IEEE_754 @skip_if_double_rounding @support.cpython_only # Other implementations may choose a different algorithm diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-07-22-03-20.gh-issue-151060.tdexEE.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-07-22-03-20.gh-issue-151060.tdexEE.rst new file mode 100644 index 000000000000000..1efde8a536c0939 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-07-22-03-20.gh-issue-151060.tdexEE.rst @@ -0,0 +1,2 @@ +Fix a crash or memory corruption in :func:`sum` when summing a +:class:`float` subclass instance into a complex running total. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index d5129bf6a5a6bc0..fbdd637a3fcb78d 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -3046,7 +3046,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) return NULL; } } - if (PyFloat_Check(item)) { + if (PyFloat_CheckExact(item)) { double value = PyFloat_AS_DOUBLE(item); re_sum = cs_add(re_sum, value); _Py_DECREF_SPECIALIZED(item, _PyFloat_ExactDealloc);