[3.9] bpo-44050: Extension modules can share state when they don't support sub-interpreters. (GH-27794) (GH-28741)

(cherry picked from commit b9bb74871b)

Co-authored-by: Hai Shi <shihai1992@gmail.com>
This commit is contained in:
Łukasz Langa 2021-10-05 22:30:25 +02:00 committed by GitHub
parent 950b324973
commit 52d9d3b754
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 1 deletions

View file

@ -680,6 +680,37 @@ def test_mutate_exception(self):
self.assertFalse(hasattr(binascii.Error, "foobar"))
def test_module_state_shared_in_global(self):
"""
bpo-44050: Extension module state should be shared between interpreters
when it doesn't support sub-interpreters.
"""
r, w = os.pipe()
self.addCleanup(os.close, r)
self.addCleanup(os.close, w)
script = textwrap.dedent(f"""
import importlib.machinery
import importlib.util
import os
fullname = '_test_module_state_shared'
origin = importlib.util.find_spec('_testmultiphase').origin
loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
spec = importlib.util.spec_from_loader(fullname, loader)
module = importlib.util.module_from_spec(spec)
attr_id = str(id(module.Error)).encode()
os.write({w}, attr_id)
""")
exec(script)
main_attr_id = os.read(r, 100)
ret = support.run_in_subinterp(script)
self.assertEqual(ret, 0)
subinterp_attr_id = os.read(r, 100)
self.assertEqual(main_attr_id, subinterp_attr_id)
class TestThreadState(unittest.TestCase):

View file

@ -0,0 +1,3 @@
Extensions that indicate they use global state (by setting ``m_size`` to -1)
can again be used in multiple interpreters. This reverts to behavior of
Python 3.8.

View file

@ -834,6 +834,30 @@ PyInit__testmultiphase_meth_state_access(PyObject *spec)
return PyModuleDef_Init(&def_meth_state_access);
}
static PyModuleDef def_module_state_shared = {
PyModuleDef_HEAD_INIT,
.m_name = "_test_module_state_shared",
.m_doc = PyDoc_STR("Regression Test module for single-phase init."),
.m_size = -1,
};
PyMODINIT_FUNC
PyInit__test_module_state_shared(PyObject *spec)
{
PyObject *module = PyModule_Create(&def_module_state_shared);
if (module == NULL) {
return NULL;
}
Py_INCREF(PyExc_Exception);
if (PyModule_AddObject(module, "Error", PyExc_Exception) < 0) {
Py_DECREF(PyExc_Exception);
Py_DECREF(module);
return NULL;
}
return module;
}
/*** Helper for imp test ***/

View file

@ -710,7 +710,9 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
return -1;
}
if (_Py_IsMainInterpreter(tstate)) {
// bpo-44050: Extensions and def->m_base.m_copy can be updated
// when the extension module doesn't support sub-interpreters.
if (_Py_IsMainInterpreter(tstate) || def->m_size == -1) {
if (def->m_size == -1) {
if (def->m_base.m_copy) {
/* Somebody already imported the module,