Skip to content

Commit

Permalink
pythongh-123880: Allow recursive import of single-phase-init modules
Browse files Browse the repository at this point in the history
  • Loading branch information
encukou committed Sep 11, 2024
1 parent e9eedf1 commit 1700e33
Showing 1 changed file with 13 additions and 5 deletions.
18 changes: 13 additions & 5 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,8 @@ static int clear_singlephase_extension(PyInterpreterState *interp,

// Currently, this is only used for testing.
// (See _testinternalcapi.clear_extension().)
// If adding another use uses, careful about modules that import themselves
// recursively (see gh-123880)
int
_PyImport_ClearExtension(PyObject *name, PyObject *filename)
{
Expand Down Expand Up @@ -1322,12 +1324,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 byt 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) {
Expand Down Expand Up @@ -1392,6 +1398,7 @@ _extensions_cache_set(PyObject *path, PyObject *name,
cleanup_old_cached_def(&olddefbase);
}

finally_oldvalue:
extensions_lock_release();
if (key != NULL) {
hashtable_destroy_str(key);
Expand Down Expand Up @@ -2128,6 +2135,7 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
}


// Used in _PyImport_ClearExtension; see notes there
static int
clear_singlephase_extension(PyInterpreterState *interp,
PyObject *name, PyObject *path)
Expand Down

0 comments on commit 1700e33

Please sign in to comment.