Skip to content

Commit 9036982

Browse files
authored
gh-156395: Report frozen objects on free-threaded GC build (#156396)
Report frozen objects on free-threaded GC build
1 parent f54fd2a commit 9036982

3 files changed

Lines changed: 56 additions & 1 deletion

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
On the free-threaded build, :c:func:`PyUnstable_GC_VisitObjects` now also
2+
visits frozen objects (objects moved to the permanent generation by
3+
:func:`gc.freeze`), matching the behavior of the default build.

Modules/_testcapi/gc.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,57 @@ test_gc_visit_objects_basic(PyObject *Py_UNUSED(self),
195195
Py_RETURN_NONE;
196196
}
197197

198+
static int
199+
gc_call_no_args(const char *method)
200+
{
201+
PyObject *gc = PyImport_ImportModule("gc");
202+
if (gc == NULL) {
203+
return -1;
204+
}
205+
PyObject *res = PyObject_CallMethod(gc, method, NULL);
206+
Py_DECREF(gc);
207+
if (res == NULL) {
208+
return -1;
209+
}
210+
Py_DECREF(res);
211+
return 0;
212+
}
213+
214+
// gh-131740: frozen objects must be visited too.
215+
static PyObject *
216+
test_gc_visit_objects_frozen(PyObject *Py_UNUSED(self),
217+
PyObject *Py_UNUSED(ignored))
218+
{
219+
PyObject *obj;
220+
struct gc_visit_state_basic state;
221+
222+
obj = PyList_New(0);
223+
if (obj == NULL) {
224+
return NULL;
225+
}
226+
if (gc_call_no_args("freeze") < 0) {
227+
Py_DECREF(obj);
228+
return NULL;
229+
}
230+
state.target = obj;
231+
state.found = 0;
232+
233+
PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state);
234+
235+
int err = gc_call_no_args("unfreeze");
236+
Py_DECREF(obj);
237+
if (err < 0) {
238+
return NULL;
239+
}
240+
if (!state.found) {
241+
PyErr_SetString(
242+
PyExc_AssertionError,
243+
"test_gc_visit_objects_frozen: Didn't find frozen list");
244+
return NULL;
245+
}
246+
Py_RETURN_NONE;
247+
}
248+
198249
static int
199250
gc_visit_callback_exit_early(PyObject *obj, void *arg)
200251
{
@@ -316,6 +367,7 @@ static PyType_Spec ObjExtraData_TypeSpec = {
316367
static PyMethodDef test_methods[] = {
317368
{"test_gc_control", test_gc_control, METH_NOARGS},
318369
{"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL},
370+
{"test_gc_visit_objects_frozen", test_gc_visit_objects_frozen, METH_NOARGS, NULL},
319371
{"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL},
320372
{"without_gc", without_gc, METH_O, NULL},
321373
{"with_tp_del", with_tp_del, METH_VARARGS, NULL},

Python/gc_free_threading.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2860,7 +2860,7 @@ static bool
28602860
custom_visitor_wrapper(const mi_heap_t *heap, const mi_heap_area_t *area,
28612861
void *block, size_t block_size, void *args)
28622862
{
2863-
PyObject *op = op_from_block(block, args, false);
2863+
PyObject *op = op_from_block(block, args, true);
28642864
if (op == NULL) {
28652865
return true;
28662866
}

0 commit comments

Comments
 (0)