Skip to content

sum() deallocates float subclass instances as exact floats in the complex fast path #150868

Open

Description

@opale-c

Bug report

Bug description:

Bug report

Description

In builtin_sum_impl() (Python/bltinmodule.c), the complex-number fast
path tests items with PyFloat_Check() but releases them with
_Py_DECREF_SPECIALIZED(item, _PyFloat_ExactDealloc).

PyFloat_Check() also matches subclasses of float, whereas
_PyFloat_ExactDealloc is only valid for exact float objects. When a
float subclass instance reaches refcount 0 through this path, it is
deallocated as an exact float, bypassing its real tp_dealloc
(instance __dict__, weakref list, and GC bookkeeping). This can leak
memory and leave the cyclic GC in an inconsistent state.

The adjacent float fast path in the same function already guards the
identical specialized dealloc with PyFloat_CheckExact(); only the
complex branch uses the broader PyFloat_Check().

Reproducer

class F(float):
    pass

# complex start value selects the complex fast path
sum([F(1.0), F(2.0)], 0j)

Proposed fix

In the complex branch, use PyFloat_CheckExact(item) instead of
PyFloat_Check(item), so subclass instances fall through to the generic
PyNumber_Add path with a normal Py_DECREF. Numeric behavior is
unchanged.

Environment

  • CPython: main branch (please confirm the line is still present)

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Jun 3, 2026
  2. self-assigned this
    on Jun 3, 2026
  3. skirpichev commented on Jun 4, 2026

    @skirpichev
    Member

    Thanks for the fix, that's my fault. That was noticed before, but not fixed, unfortunately.

    Though, note that in some branches - subclasses are handled. I think we should apply also

    diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
    index fbdd637a3fc..6af21fbef6f 100644
    --- a/Python/bltinmodule.c
    +++ b/Python/bltinmodule.c
    @@ -2981,15 +2981,15 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
                     _Py_DECREF_SPECIALIZED(item, _PyFloat_ExactDealloc);
                     continue;
                 }
    -            if (PyLong_Check(item)) {
    +            if (PyLong_CheckExact(item)) {
                     double value = PyLong_AsDouble(item);
                     if (value != -1.0 || !PyErr_Occurred()) {
                         re_sum = cs_add(re_sum, value);
    -                    Py_DECREF(item);
    +                    _Py_DECREF_SPECIALIZED(item, _PyLong_ExactDealloc);
                         continue;
                     }
                     else {
    -                    Py_DECREF(item);
    +                    _Py_DECREF_SPECIALIZED(item, _PyLong_ExactDealloc);
                         Py_DECREF(iter);
                         return NULL;
                     }
    @@ -3033,15 +3033,15 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
                     Py_DECREF(item);
                     continue;
                 }
    -            if (PyLong_Check(item)) {
    +            if (PyLong_CheckExact(item)) {
                     double value = PyLong_AsDouble(item);
                     if (value != -1.0 || !PyErr_Occurred()) {
                         re_sum = cs_add(re_sum, value);
    -                    Py_DECREF(item);
    +                    _Py_DECREF_SPECIALIZED(item, _PyLong_ExactDealloc);
                         continue;
                     }
                     else {
    -                    Py_DECREF(item);
    +                    _Py_DECREF_SPECIALIZED(item, _PyLong_ExactDealloc);
                         Py_DECREF(iter);
                         return NULL;
                     }

    CC @rhettinger

  4. removed their assignment
    on Jun 4, 2026
  5. eendebakpt commented on Jun 7, 2026

    @eendebakpt
    Contributor

    FWIW: I benchmarked the _Py_DECREF_SPECIALIZED and on PGO builds there is hardly any performance difference with the normal Py_DECREF. So for any PR that makes not a big difference.

  6. added a commit that references this issue on Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions