diff --git a/Objects/setobject.c b/Objects/setobject.c index d8c38ff1c1d899a..522a7c65bfc4d8f 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1483,7 +1483,11 @@ frozenset_vectorcall(PyObject *type, PyObject * const*args, static PyObject * set_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return make_new_set(type, NULL); + /* Leave GC-untracked until set_init() finishes filling (gh-152235). + * The vectorcall path uses make_new_set() and tracks at the end; the + * classic tp_new/tp_init path must do the same so a half-built set is + * never visible to gc.get_objects() / another thread during __init__. */ + return make_new_set_untracked(type, NULL); } #ifdef Py_GIL_DISABLED @@ -2750,6 +2754,7 @@ set_init(PyObject *so, PyObject *args, PyObject *kwds) { PySetObject *self = _PySet_CAST(so); PyObject *iterable = NULL; + int rv; if (!_PyArg_NoKeywords("set", kwds)) return -1; @@ -2759,19 +2764,30 @@ set_init(PyObject *so, PyObject *args, PyObject *kwds) if (_PyObject_IsUniquelyReferenced((PyObject *)self) && self->fill == 0) { self->hash = -1; if (iterable == NULL) { - return 0; + rv = 0; + } + else { + rv = set_update_local(self, iterable); } - return set_update_local(self, iterable); } - Py_BEGIN_CRITICAL_SECTION(self); - if (self->fill) - set_clear_internal((PyObject*)self); - self->hash = -1; - Py_END_CRITICAL_SECTION(); + else { + Py_BEGIN_CRITICAL_SECTION(self); + if (self->fill) + set_clear_internal((PyObject*)self); + self->hash = -1; + Py_END_CRITICAL_SECTION(); - if (iterable == NULL) - return 0; - return set_update_internal(self, iterable); + if (iterable == NULL) + rv = 0; + else + rv = set_update_internal(self, iterable); + } + + /* Track only once fully built (pairs with set_new leaving it untracked). */ + if (rv == 0 && !_PyObject_GC_IS_TRACKED(so)) { + _PyObject_GC_TRACK(so); + } + return rv; } static PyObject* diff --git a/Python/import.c b/Python/import.c index 6da6faf5f28cc3b..7abe6b04eb5ebe9 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4567,8 +4567,22 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, } } + // Match __import__: a string fromlist is a sequence of names, not a + // single attribute. Normalize to a 1-tuple so resolve() returns the + // module (gh-151672). + PyObject *fromlist_owned = NULL; + if (fromlist != NULL && PyUnicode_Check(fromlist)) { + fromlist_owned = PyTuple_Pack(1, fromlist); + if (fromlist_owned == NULL) { + Py_DECREF(abs_name); + return NULL; + } + fromlist = fromlist_owned; + } + // here, 'filter' is either NULL or is equivalent to a borrowed reference PyObject *res = _PyLazyImport_New(frame, builtins, abs_name, fromlist); + Py_XDECREF(fromlist_owned); if (res == NULL) { Py_DECREF(abs_name); return NULL; @@ -4580,12 +4594,7 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, goto error; } - if (fromlist && PyUnicode_Check(fromlist)) { - if (register_from_lazy_on_parent(tstate, abs_name, fromlist) < 0) { - goto error; - } - } - else if (fromlist && PyTuple_Check(fromlist) && + if (fromlist && PyTuple_Check(fromlist) && PyTuple_GET_SIZE(fromlist)) { for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(fromlist); i++) { if (register_from_lazy_on_parent(tstate, abs_name,