python / python/cpython

PyRefTracer_DESTROY is not called for objects deferred by the trashcan mechanism

Abierto
#156,371 2 comentarios 0 reacciones 1 asignado Ver en GitHub

@corona10 ya está trabajando en esto.

Desde el 25/8/2026.

3.14 3.15 3.16 type-bug
Lenguaje dominante
Python
Estrellas
77.2k
Forks
35.9k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Bug report

This works correctly until Python 3.13, but https://github.com/python/cpython/pull/132280 introduces a regression.
A simple PR will fix this issue, and I have already prepared a fix for this issue.

import os
import subprocess
import sys
import sysconfig
import tempfile

CSRC = r"""
#include <Python.h>

static Py_ssize_t list_destroys = 0;

static int
tracer(PyObject *obj, PyRefTracerEvent event, void *data)
{
    if (event == PyRefTracer_DESTROY && PyList_CheckExact(obj)) {
        list_destroys++;
    }
    return 0;
}

static PyObject *
start(PyObject *self, PyObject *args)
{
    list_destroys = 0;
    if (PyRefTracer_SetTracer(tracer, NULL) < 0) {
        return NULL;
    }
    Py_RETURN_NONE;
}

static PyObject *
stop(PyObject *self, PyObject *args)
{
    if (PyRefTracer_SetTracer(NULL, NULL) < 0) {
        return NULL;
    }
    return PyLong_FromSsize_t(list_destroys);
}

static PyMethodDef methods[] = {
    {"start", start, METH_NOARGS, NULL},
    {"stop", stop, METH_NOARGS, NULL},
    {NULL, NULL, 0, NULL},
};

static PyModuleDef_Slot slots[] = {
#ifdef Py_GIL_DISABLED
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
#endif
    {0, NULL},
};

static struct PyModuleDef module = {
    PyModuleDef_HEAD_INIT,
    .m_name = "reftrace_repro",
    .m_size = 0,
    .m_methods = methods,
    .m_slots = slots,
};

PyMODINIT_FUNC
PyInit_reftrace_repro(void)
{
    return PyModuleDef_Init(&module);
}
"""


def build_module():
    tmpdir = tempfile.mkdtemp(prefix="reftrace_repro_")
    src = os.path.join(tmpdir, "reftrace_repro.c")
    with open(src, "w") as f:
        f.write(CSRC)
    ext = os.path.join(tmpdir, "reftrace_repro.so")
    cmd = ["cc", "-O2", "-shared", "-fPIC",
           "-I", sysconfig.get_path("include"),
           "-I", sysconfig.get_path("platinclude"),
           "-o", ext, src]
    if sys.platform == "darwin":
        cmd.insert(3, "-undefined")
        cmd.insert(4, "dynamic_lookup")
    subprocess.run(cmd, check=True)
    sys.path.insert(0, tmpdir)


def run(depth):
    import reftrace_repro

    chain = None
    for _ in range(depth):
        chain = [chain]
    reftrace_repro.start()
    del chain
    destroys = reftrace_repro.stop()
    missing = depth - destroys
    print(f"depth={depth:>7}  DESTROY events={destroys:>7}  "
          f"missing={missing:>5}  [{'BUG' if missing else 'OK'}]")


if __name__ == "__main__":
    print(sys.version)
    build_module()
    run(100)        
    run(200_000)

Status

$ python3.13 repro.py
3.13.11 (main, Dec 17 2025, 20:55:16) [Clang 21.1.4 ]
depth=    100  DESTROY events=    100  missing=    0  [OK]
depth= 200000  DESTROY events= 200000  missing=    0  [OK]

$ python3.14 repro.py
3.14.3 (main, Feb  3 2026, 15:32:20) [Clang 17.0.0 (clang-1700.6.3.2)]
depth=    100  DESTROY events=    100  missing=    0  [OK]
depth= 200000  DESTROY events= 199923  missing=   77  [BUG]

$ python3.15 repro.py
3.15.0a3 (main, Dec 17 2025, 21:18:28) [Clang 21.1.4 ]
depth=    100  DESTROY events=    100  missing=    0  [OK]
depth= 200000  DESTROY events= 199570  missing=  430  [BUG]

$ ./python.exe repro.py   # main (unpatched)
3.16.0a0 (heads/main:e4b22adf249, Aug 26 2026, 01:02:19) [Clang 21.0.0]
depth=    100  DESTROY events=    100  missing=    0  [OK]
depth= 200000  DESTROY events= 199923  missing=   77  [BUG]
Linked PRs
  • gh-156372
  • gh-156789
  • gh-156802

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.