diff options
| author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2024-09-23 19:56:00 (GMT) |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-23 19:56:00 (GMT) |
| commit | de8dc92db7859d5512969f97b6a7ac3f6ad61c74 (patch) | |
| tree | 48e3619125fd0a7938e9b476953b5c946756465f /Python/import.c | |
| parent | 8d5911ef6b03b75914d17dca0c46360fc0413879 (diff) | |
| download | cpython-de8dc92db7859d5512969f97b6a7ac3f6ad61c74.zip cpython-de8dc92db7859d5512969f97b6a7ac3f6ad61c74.tar.gz cpython-de8dc92db7859d5512969f97b6a7ac3f6ad61c74.tar.bz2 | |
[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 aee219f4558dda619bd86e4b0e028ce47a5e4b77)
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>
Diffstat (limited to 'Python/import.c')
| -rw-r--r-- | Python/import.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/Python/import.c b/Python/import.c index 1056ddd..e0eb740 100644 --- a/Python/import.c +++ b/Python/import.c @@ -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) |
