]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-107471: Fix Refleaks in test_import (gh-107569)
authorEric Snow <ericsnowcurrently@gmail.com>
Wed, 2 Aug 2023 20:55:09 +0000 (14:55 -0600)
committerGitHub <noreply@github.com>
Wed, 2 Aug 2023 20:55:09 +0000 (20:55 +0000)
gh-107184 introduced a refleak in test_import.SubinterpImportTests (specifically test_singlephase_check_with_setting_and_override and test_single_init_extension_compat).  We fix it here by making sure _testsinglephase is removed from sys.modules whenever we clear the runtime's internal state for the module.

The underlying problem is strictly contained in the internal function _PyImport_ClearExtension() (AKA _testinternalcapi.clear_extension()), which is only used in tests.

(This also fixes an intermittent segfault introduced in the same place, in test_disallowed_reimport.)

Lib/test/test_import/__init__.py
Python/import.c

index 7a3fcc22be8d1334021c1f82c7e2deb1fde7e33b..163ed824ff1fb08c2f678d56ff7a6b6219899a6b 100644 (file)
@@ -150,6 +150,7 @@ if _testsinglephase is not None:
     def restore__testsinglephase(*, _orig=_testsinglephase):
         # We started with the module imported and want to restore
         # it to its nominal state.
+        sys.modules.pop('_testsinglephase', None)
         _orig._clear_globals()
         _testinternalcapi.clear_extension('_testsinglephase', _orig.__file__)
         import _testsinglephase
@@ -2125,7 +2126,7 @@ class SinglephaseInitTests(unittest.TestCase):
             _interpreters.run_string(interpid, textwrap.dedent(f'''
                 name = {self.NAME!r}
                 if name in sys.modules:
-                    sys.modules[name]._clear_globals()
+                    sys.modules.pop(name)._clear_globals()
                 _testinternalcapi.clear_extension(name, {self.FILE!r})
                 '''))
             _interpreters.destroy(interpid)
index 3be2f76c9eca7555271f7ef1907bd1639ceb8cf6..56b2dc1a4ada2cd47536378ee96e9972fa402612 100644 (file)
@@ -1073,6 +1073,7 @@ _extensions_cache_delete(PyObject *filename, PyObject *name)
        However, this decref would be problematic if the module def were
        dynamically allocated, it were the last ref, and this function
        were called with an interpreter other than the def's owner. */
+    assert(_Py_IsImmortal(entry->value));
     entry->value = NULL;
 
 finally: