summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Pytel <tompytel@gmail.com>2025-03-13 16:31:49 (GMT)
committerGitHub <noreply@github.com>2025-03-13 16:31:49 (GMT)
commitc5abded09995f208b21ebaf012185ca5acb0180b (patch)
tree2b22375cdd0ce4c5ed704222e1f6028b32076d06
parent3a91ee97245639c7c4f8852418157d3fc0ec1a82 (diff)
downloadcpython-c5abded09995f208b21ebaf012185ca5acb0180b.zip
cpython-c5abded09995f208b21ebaf012185ca5acb0180b.tar.gz
cpython-c5abded09995f208b21ebaf012185ca5acb0180b.tar.bz2
gh-130382: add missing `_PyReftracerTrack` to ceval `Py_DECREF` (#130689)
-rw-r--r--Lib/test/test_capi/test_misc.py17
-rw-r--r--Misc/NEWS.d/next/Core_and_Builtins/2025-02-28-16-13-02.gh-issue-130382.66VTmy.rst1
-rw-r--r--Modules/_testcapimodule.c26
-rw-r--r--Python/ceval.c1
4 files changed, 45 insertions, 0 deletions
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index 6c4cf5b..2e1e8e7 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -2884,5 +2884,22 @@ class TestVersions(unittest.TestCase):
self.assertEqual(result, expected)
+class TestCEval(unittest.TestCase):
+ def test_ceval_decref(self):
+ code = textwrap.dedent("""
+ import _testcapi
+ _testcapi.toggle_reftrace_printer(True)
+ l1 = []
+ l2 = []
+ del l1
+ del l2
+ _testcapi.toggle_reftrace_printer(False)
+ """)
+ _, out, _ = assert_python_ok("-c", code)
+ lines = out.decode("utf-8").splitlines()
+ self.assertEqual(lines.count("CREATE list"), 2)
+ self.assertEqual(lines.count("DESTROY list"), 2)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-02-28-16-13-02.gh-issue-130382.66VTmy.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-28-16-13-02.gh-issue-130382.66VTmy.rst
new file mode 100644
index 0000000..8b775c8
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-28-16-13-02.gh-issue-130382.66VTmy.rst
@@ -0,0 +1 @@
+Fix ``PyRefTracer_DESTROY`` not being sent from :file:`Python/ceval.c` ``Py_DECREF()``.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 9260c76..409dd02 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2515,6 +2515,31 @@ code_offset_to_line(PyObject* self, PyObject* const* args, Py_ssize_t nargsf)
}
+static int
+_reftrace_printer(PyObject *obj, PyRefTracerEvent event, void *counter_data)
+{
+ if (event == PyRefTracer_CREATE) {
+ printf("CREATE %s\n", Py_TYPE(obj)->tp_name);
+ }
+ else { // PyRefTracer_DESTROY
+ printf("DESTROY %s\n", Py_TYPE(obj)->tp_name);
+ }
+ return 0;
+}
+
+// A simple reftrace printer for very simple tests
+static PyObject *
+toggle_reftrace_printer(PyObject *ob, PyObject *arg)
+{
+ if (arg == Py_True) {
+ PyRefTracer_SetTracer(_reftrace_printer, NULL);
+ }
+ else {
+ PyRefTracer_SetTracer(NULL, NULL);
+ }
+ Py_RETURN_NONE;
+}
+
static PyMethodDef TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
@@ -2608,6 +2633,7 @@ static PyMethodDef TestMethods[] = {
{"finalize_thread_hang", finalize_thread_hang, METH_O, NULL},
{"test_atexit", test_atexit, METH_NOARGS},
{"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL},
+ {"toggle_reftrace_printer", toggle_reftrace_printer, METH_O},
{NULL, NULL} /* sentinel */
};
diff --git a/Python/ceval.c b/Python/ceval.c
index f9089d7..34f4417 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -80,6 +80,7 @@
} \
_Py_DECREF_STAT_INC(); \
if (--op->ob_refcnt == 0) { \
+ _PyReftracerTrack(op, PyRefTracer_DESTROY); \
destructor dealloc = Py_TYPE(op)->tp_dealloc; \
(*dealloc)(op); \
} \