Skip to content

Commit c05db54

Browse files
committed
make sure PySet_Add tracks frozensets if needed
1 parent a3292c2 commit c05db54

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

Modules/_testcapimodule.c

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2435,6 +2435,66 @@ test_critical_sections(PyObject *module, PyObject *Py_UNUSED(args))
24352435
}
24362436

24372437

2438+
2439+
static PyObject *
2440+
test_pyset_add(PyObject* self, PyObject *Py_UNUSED(args))
2441+
{
2442+
2443+
PyObject *set = NULL, *empty_tuple=NULL, *tracked_object;
2444+
2445+
2446+
tracked_object = PyImport_ImportModule("sys");
2447+
if (tracked_object == NULL) {
2448+
goto failed;
2449+
}
2450+
if (!PyObject_GC_IsTracked(tracked_object)) {
2451+
PyErr_SetString(PyExc_ValueError, "Test item is not tracked by GC");
2452+
goto failed;
2453+
}
2454+
2455+
2456+
int return_value;
2457+
empty_tuple = PyTuple_New(0);
2458+
if (empty_tuple == NULL) {
2459+
goto failed;
2460+
}
2461+
set = PyFrozenSet_New(empty_tuple);
2462+
if (set == NULL) {
2463+
return NULL;
2464+
}
2465+
2466+
if (PyObject_GC_IsTracked(set)) {
2467+
PyErr_SetString(PyExc_ValueError, "Empty frozenset object is tracked by GC");
2468+
goto failed;
2469+
}
2470+
return_value = PySet_Add(set, empty_tuple);
2471+
if (return_value<0) {
2472+
goto failed;
2473+
}
2474+
if (PyObject_GC_IsTracked(set)) {
2475+
PyErr_SetString(PyExc_ValueError, "Frozenset object with immutable is tracked by GC");
2476+
goto failed;
2477+
}
2478+
2479+
PySet_Add(set, tracked_object);
2480+
if (return_value<0) {
2481+
goto failed;
2482+
}
2483+
if (!PyObject_GC_IsTracked(set)) {
2484+
PyErr_SetString(PyExc_ValueError, "Frozenset object with tracked objects is not tracked by GC");
2485+
goto failed;
2486+
}
2487+
2488+
Py_RETURN_NONE;
2489+
2490+
failed:
2491+
Py_XDECREF(tracked_object);
2492+
Py_XDECREF(empty_tuple);
2493+
Py_XDECREF(set);
2494+
return NULL;
2495+
2496+
}
2497+
24382498
// Used by `finalize_thread_hang`.
24392499
#if defined(_POSIX_THREADS) && !defined(__wasi__)
24402500
static void finalize_thread_hang_cleanup_callback(void *Py_UNUSED(arg)) {
@@ -2625,7 +2685,7 @@ static PyMethodDef TestMethods[] = {
26252685
{"return_null_without_error", return_null_without_error, METH_NOARGS},
26262686
{"return_result_with_error", return_result_with_error, METH_NOARGS},
26272687
{"getitem_with_error", getitem_with_error, METH_VARARGS},
2628-
{"Py_CompileString", pycompilestring, METH_O},
2688+
{"Py_CompileString", pycompilestring, METH_O},
26292689
{"raise_SIGINT_then_send_None", raise_SIGINT_then_send_None, METH_VARARGS},
26302690
{"stack_pointer", stack_pointer, METH_NOARGS},
26312691
#ifdef W_STOPCODE
@@ -2646,6 +2706,7 @@ static PyMethodDef TestMethods[] = {
26462706
{"gen_get_code", gen_get_code, METH_O, NULL},
26472707
{"get_feature_macros", get_feature_macros, METH_NOARGS, NULL},
26482708
{"test_code_api", test_code_api, METH_NOARGS, NULL},
2709+
{"test_pyset_add", test_pyset_add, METH_NOARGS, NULL},
26492710
{"settrace_to_error", settrace_to_error, METH_O, NULL},
26502711
{"settrace_to_record", settrace_to_record, METH_O, NULL},
26512712
{"test_macros", test_macros, METH_NOARGS, NULL},

Objects/setobject.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,6 +2802,9 @@ PySet_Add(PyObject *anyset, PyObject *key)
28022802
return -1;
28032803
}
28042804

2805+
if (PyFrozenSet_Check(anyset) && PyObject_GC_IsTracked(key) && !PyObject_GC_IsTracked(anyset) ) {
2806+
_PyObject_GC_TRACK(anyset);
2807+
}
28052808
int rv;
28062809
Py_BEGIN_CRITICAL_SECTION(anyset);
28072810
rv = set_add_key((PySetObject *)anyset, key);

0 commit comments

Comments
 (0)