Skip to content

gh-152235: Defer GC tracking during the lock-free fill in set.__init__#153079

Open
corona10 wants to merge 1 commit into
python:mainfrom
corona10:gh-152235-set-init
Open

gh-152235: Defer GC tracking during the lock-free fill in set.__init__#153079
corona10 wants to merge 1 commit into
python:mainfrom
corona10:gh-152235-set-init

Conversation

@corona10

@corona10 corona10 commented Jul 5, 2026

Copy link
Copy Markdown
Member

@corona10

corona10 commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

@vstinner @methane

Final PR of the set: list already has TSan-safe initialization, and this brings set.init up to the same level of protection.

cpython/Objects/listobject.c

Lines 3523 to 3544 in fe9c721

list___init___impl(PyListObject *self, PyObject *iterable)
/*[clinic end generated code: output=0f3c21379d01de48 input=b3f3fe7206af8f6b]*/
{
/* Verify list invariants established by PyType_GenericAlloc() */
assert(0 <= Py_SIZE(self));
assert(Py_SIZE(self) <= self->allocated || self->allocated == -1);
assert(self->ob_item != NULL ||
self->allocated == 0 || self->allocated == -1);
/* Empty previous contents */
if (self->ob_item != NULL) {
Py_BEGIN_CRITICAL_SECTION(self);
list_clear(self);
Py_END_CRITICAL_SECTION();
}
if (iterable != NULL) {
if (_list_extend(self, iterable) < 0) {
return -1;
}
}
return 0;
}

cpython/Objects/listobject.c

Lines 1457 to 1511 in fe9c721

_list_extend(PyListObject *self, PyObject *iterable)
{
// Special case:
// lists and tuples which can use PySequence_Fast ops
int res = -1;
if ((PyObject *)self == iterable) {
Py_BEGIN_CRITICAL_SECTION(self);
res = list_inplace_repeat_lock_held(self, 2);
Py_END_CRITICAL_SECTION();
}
else if (PyList_CheckExact(iterable)) {
Py_BEGIN_CRITICAL_SECTION2(self, iterable);
res = list_extend_lock_held(self, iterable);
Py_END_CRITICAL_SECTION2();
}
else if (PyTuple_CheckExact(iterable)) {
Py_BEGIN_CRITICAL_SECTION(self);
res = list_extend_lock_held(self, iterable);
Py_END_CRITICAL_SECTION();
}
else if (PyAnySet_CheckExact(iterable)) {
Py_BEGIN_CRITICAL_SECTION2(self, iterable);
res = list_extend_set(self, (PySetObject *)iterable);
Py_END_CRITICAL_SECTION2();
}
else if (PyDict_CheckExact(iterable)) {
Py_BEGIN_CRITICAL_SECTION2(self, iterable);
res = list_extend_dict(self, (PyDictObject *)iterable, 0 /*keys*/);
Py_END_CRITICAL_SECTION2();
}
else if (Py_IS_TYPE(iterable, &PyDictKeys_Type)) {
PyDictObject *dict = ((_PyDictViewObject *)iterable)->dv_dict;
Py_BEGIN_CRITICAL_SECTION2(self, dict);
res = list_extend_dict(self, dict, 0 /*keys*/);
Py_END_CRITICAL_SECTION2();
}
else if (Py_IS_TYPE(iterable, &PyDictValues_Type)) {
PyDictObject *dict = ((_PyDictViewObject *)iterable)->dv_dict;
Py_BEGIN_CRITICAL_SECTION2(self, dict);
res = list_extend_dict(self, dict, 1 /*values*/);
Py_END_CRITICAL_SECTION2();
}
else if (Py_IS_TYPE(iterable, &PyDictItems_Type)) {
PyDictObject *dict = ((_PyDictViewObject *)iterable)->dv_dict;
Py_BEGIN_CRITICAL_SECTION2(self, dict);
res = list_extend_dictitems(self, dict);
Py_END_CRITICAL_SECTION2();
}
else {
Py_BEGIN_CRITICAL_SECTION(self);
res = list_extend_iter_lock_held(self, iterable);
Py_END_CRITICAL_SECTION();
}
return res;
}

@vstinner

vstinner commented Jul 5, 2026

Copy link
Copy Markdown
Member

The issue title is "Need to defer GC tracking of frozenset/set construction", but in fact, the problem only arises for frozenset.

PyFrozenSet_Type defines tp_new (frozenset_new) but has no tp_init function.

PySet_Type defines tp_new (set_new) and tp_init (set_init).

So changing set_init() only impacts the mutable set. I don't see which problem you are trying to solve. It's fine to mutate a set object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes skip news topic-free-threading

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants