python / python/cpython

PyRefTracer_DESTROY is not called for objects deferred by the trashcan mechanism

Ouverte
#156,371 2 commentaires 0 réactions 1 personne assignée Voir sur GitHub

@corona10 y travaille déjà.

Depuis le 25/8/2026.

3.14 3.15 3.16 type-bug
Langage dominant
Python
Étoiles
77.2k
Forks
35.9k
Métriques de merge des PR
Métriques de PR en attente

Description

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

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.