https://github.com/python/cpython/commit/f01181b595971fd1af12cf43ab6731a4e5766142
commit: f01181b595971fd1af12cf43ab6731a4e5766142
branch: main
author: Pablo Galindo Salgado <[email protected]>
committer: pablogsal <[email protected]>
date: 2025-09-15T11:12:09+01:00
summary:
gh-138794: Communicate to PyRefTracer when they are being replaced (#138797)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-09-11-15-56-18.gh-issue-138794.nrOn1K.rst
M Doc/c-api/init.rst
M Include/cpython/object.h
M Modules/_testcapimodule.c
M Objects/object.c
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 379330f380400f..199b64387266bf 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -2010,6 +2010,11 @@ Reference tracing
is set to :c:data:`PyRefTracer_DESTROY`). The **data** argument is the
opaque pointer
that was provided when :c:func:`PyRefTracer_SetTracer` was called.
+ If a new tracing function is registered replacing the current a call to the
+ trace function will be made with the object set to **NULL** and **event**
set to
+ :c:data:`PyRefTracer_TRACKER_REMOVED`. This will happen just before the new
+ function is registered.
+
.. versionadded:: 3.13
.. c:var:: int PyRefTracer_CREATE
@@ -2022,6 +2027,13 @@ Reference tracing
The value for the *event* parameter to :c:type:`PyRefTracer` functions when
a Python
object has been destroyed.
+.. c:var:: int PyRefTracer_TRACKER_REMOVED
+
+ The value for the *event* parameter to :c:type:`PyRefTracer` functions when
the
+ current tracer is about to be replaced by a new one.
+
+ .. versionadded:: 3.14
+
.. c:function:: int PyRefTracer_SetTracer(PyRefTracer tracer, void *data)
Register a reference tracer function. The function will be called when a new
@@ -2037,6 +2049,10 @@ Reference tracing
There must be an :term:`attached thread state` when calling this function.
+ If another tracer function was already registered, the old function will be
+ called with **event** set to :c:data:`PyRefTracer_TRACKER_REMOVED` just
before
+ the new function is registered.
+
.. versionadded:: 3.13
.. c:function:: PyRefTracer PyRefTracer_GetTracer(void** data)
diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index b244c062c7679e..4e6f86f29d8473 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -463,6 +463,7 @@ PyAPI_FUNC(int)
PyUnstable_Type_AssignVersionTag(PyTypeObject *type);
typedef enum {
PyRefTracer_CREATE = 0,
PyRefTracer_DESTROY = 1,
+ PyRefTracer_TRACKER_REMOVED = 2,
} PyRefTracerEvent;
typedef int (*PyRefTracer)(PyObject *, PyRefTracerEvent event, void *);
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-11-15-56-18.gh-issue-138794.nrOn1K.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-11-15-56-18.gh-issue-138794.nrOn1K.rst
new file mode 100644
index 00000000000000..2fb0f07329899f
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-11-15-56-18.gh-issue-138794.nrOn1K.rst
@@ -0,0 +1,5 @@
+When a new tracing function is registered with
+:c:func:`PyRefTracer_SetTracer`, replacing the current a call to the trace
+function will be made with the object set to **NULL** and **event** set to
+:c:data:`PyRefTracer_TRACKER_REMOVED`. This will happen just before the new
+function is registered. Patch by Pablo Galindo
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 4f22a70802009a..c80a780e22ca34 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2319,6 +2319,7 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject
*Py_UNUSED(args))
struct simpletracer_data {
int create_count;
int destroy_count;
+ int tracker_removed;
void* addresses[10];
};
@@ -2326,10 +2327,18 @@ static int _simpletracer(PyObject *obj,
PyRefTracerEvent event, void* data) {
struct simpletracer_data* the_data = (struct simpletracer_data*)data;
assert(the_data->create_count + the_data->destroy_count <
(int)Py_ARRAY_LENGTH(the_data->addresses));
the_data->addresses[the_data->create_count + the_data->destroy_count] =
obj;
- if (event == PyRefTracer_CREATE) {
- the_data->create_count++;
- } else {
- the_data->destroy_count++;
+ switch (event) {
+ case PyRefTracer_CREATE:
+ the_data->create_count++;
+ break;
+ case PyRefTracer_DESTROY:
+ the_data->destroy_count++;
+ break;
+ case PyRefTracer_TRACKER_REMOVED:
+ the_data->tracker_removed++;
+ break;
+ default:
+ return -1;
}
return 0;
}
@@ -2393,6 +2402,10 @@ test_reftracer(PyObject *ob, PyObject
*Py_UNUSED(ignored))
PyErr_SetString(PyExc_ValueError, "The object destruction was not
correctly traced");
goto failed;
}
+ if (tracer_data.tracker_removed != 1) {
+ PyErr_SetString(PyExc_ValueError, "The tracker removal was not
correctly traced");
+ goto failed;
+ }
PyRefTracer_SetTracer(current_tracer, current_data);
Py_RETURN_NONE;
failed:
@@ -2533,11 +2546,15 @@ 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);
+ switch (event) {
+ case PyRefTracer_CREATE:
+ printf("CREATE %s\n", Py_TYPE(obj)->tp_name);
+ break;
+ case PyRefTracer_DESTROY:
+ printf("DESTROY %s\n", Py_TYPE(obj)->tp_name);
+ break;
+ case PyRefTracer_TRACKER_REMOVED:
+ return 0;
}
return 0;
}
diff --git a/Objects/object.c b/Objects/object.c
index aaa3c0b338434e..2c07c2e9841b0d 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -3287,6 +3287,12 @@ _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt)
int PyRefTracer_SetTracer(PyRefTracer tracer, void *data) {
_Py_AssertHoldsTstate();
+ if (_PyRuntime.ref_tracer.tracer_func != NULL) {
+ _PyReftracerTrack(NULL, PyRefTracer_TRACKER_REMOVED);
+ if (PyErr_Occurred()) {
+ return -1;
+ }
+ }
_PyRuntime.ref_tracer.tracer_func = tracer;
_PyRuntime.ref_tracer.tracer_data = data;
return 0;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]