[3.13] gh-123880: Allow recursive import of single-phase-init modules (GH-123950) (#124273)

gh-123880: Allow recursive import of single-phase-init modules (GH-123950)

(cherry picked from commit aee219f455)

Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
Co-authored-by: Brett Cannon <brett@python.org>
This commit is contained in:
Miss Islington (bot) 2024-09-23 21:56:00 +02:00 committed by GitHub
parent 8d5911ef6b
commit de8dc92db7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 141 additions and 25 deletions

View file

@ -814,6 +814,8 @@ static int clear_singlephase_extension(PyInterpreterState *interp,
// Currently, this is only used for testing.
// (See _testinternalcapi.clear_extension().)
// If adding another use, be careful about modules that import themselves
// recursively (see gh-123880).
int
_PyImport_ClearExtension(PyObject *name, PyObject *filename)
{
@ -1321,12 +1323,16 @@ _extensions_cache_set(PyObject *path, PyObject *name,
value = entry == NULL
? NULL
: (struct extensions_cache_value *)entry->value;
/* We should never be updating an existing cache value. */
assert(value == NULL);
if (value != NULL) {
PyErr_Format(PyExc_SystemError,
"extension module %R is already cached", name);
goto finally;
/* gh-123880: If there's an existing cache value, it means a module is
* being imported recursively from its PyInit_* or Py_mod_* function.
* (That function presumably handles returning a partially
* constructed module in such a case.)
* We can reuse the existing cache value; it is owned by the cache.
* (Entries get removed from it in exceptional circumstances,
* after interpreter shutdown, and in runtime shutdown.)
*/
goto finally_oldvalue;
}
newvalue = alloc_extensions_cache_value();
if (newvalue == NULL) {
@ -1391,6 +1397,7 @@ finally:
cleanup_old_cached_def(&olddefbase);
}
finally_oldvalue:
extensions_lock_release();
if (key != NULL) {
hashtable_destroy_str(key);
@ -2127,6 +2134,7 @@ error:
}
// Used in _PyImport_ClearExtension; see notes there.
static int
clear_singlephase_extension(PyInterpreterState *interp,
PyObject *name, PyObject *path)