Fix bug in specialization and make reification atomic

This commit is contained in:
Pablo Galindo Salgado 2025-10-21 16:55:35 +01:00
parent cdec6a6236
commit c3b4807dac
2 changed files with 17 additions and 3 deletions

View file

@ -3712,20 +3712,25 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
assert(PyLazyImport_CheckExact(lazy_import)); assert(PyLazyImport_CheckExact(lazy_import));
PyLazyImportObject *lz = (PyLazyImportObject *)lazy_import; PyLazyImportObject *lz = (PyLazyImportObject *)lazy_import;
PyInterpreterState *interp = tstate->interp;
// Acquire the global import lock to serialize reification
_PyImport_AcquireLock(interp);
// Check if we are already importing this module, if so, then we want to return an error // Check if we are already importing this module, if so, then we want to return an error
// that indicates we've hit a cycle which will indicate the value isn't yet available. // that indicates we've hit a cycle which will indicate the value isn't yet available.
PyInterpreterState *interp = tstate->interp;
PyObject *importing = interp->imports.lazy_importing_modules; PyObject *importing = interp->imports.lazy_importing_modules;
if (importing == NULL) { if (importing == NULL) {
importing = interp->imports.lazy_importing_modules = PySet_New(NULL); importing = interp->imports.lazy_importing_modules = PySet_New(NULL);
if (importing == NULL) { if (importing == NULL) {
_PyImport_ReleaseLock(interp);
return NULL; return NULL;
} }
} }
int is_loading = PySet_Contains(importing, lazy_import); int is_loading = PySet_Contains(importing, lazy_import);
if (is_loading < 0) { if (is_loading < 0) {
_PyImport_ReleaseLock(interp);
return NULL; return NULL;
} else if (is_loading == 1) { } else if (is_loading == 1) {
PyObject *name = _PyLazyImport_GetName(lazy_import); PyObject *name = _PyLazyImport_GetName(lazy_import);
@ -3735,8 +3740,10 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
PyErr_SetImportErrorSubclass(PyExc_ImportCycleError, errmsg, lz->lz_from, NULL); PyErr_SetImportErrorSubclass(PyExc_ImportCycleError, errmsg, lz->lz_from, NULL);
Py_XDECREF(errmsg); Py_XDECREF(errmsg);
Py_XDECREF(name); Py_XDECREF(name);
_PyImport_ReleaseLock(interp);
return NULL; return NULL;
} else if (PySet_Add(importing, lazy_import) < 0) { } else if (PySet_Add(importing, lazy_import) < 0) {
_PyImport_ReleaseLock(interp);
goto error; goto error;
} }
@ -3889,6 +3896,9 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
obj = NULL; obj = NULL;
} }
// Release the global import lock
_PyImport_ReleaseLock(interp);
Py_XDECREF(fromlist); Py_XDECREF(fromlist);
Py_XDECREF(import_func); Py_XDECREF(import_func);
return obj; return obj;

View file

@ -1708,10 +1708,14 @@ specialize_load_global_lock_held(
goto fail; goto fail;
} }
PyObject *value = NULL; PyObject *value = NULL;
if (PyDict_GetItemRef(globals, name, &value) < 0 || if (PyDict_GetItemRef(globals, name, &value) < 0) {
(value != NULL && PyLazyImport_CheckExact(value))) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR);
goto fail;
}
if (value != NULL && PyLazyImport_CheckExact(value)) {
SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_ATTR_MODULE_LAZY_VALUE); SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_ATTR_MODULE_LAZY_VALUE);
Py_DECREF(value); Py_DECREF(value);
goto fail;
} }
Py_XDECREF(value); Py_XDECREF(value);
Py_ssize_t index = _PyDictKeys_StringLookup(globals_keys, name); Py_ssize_t index = _PyDictKeys_StringLookup(globals_keys, name);