diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 5f78c337028a99..db26b9b5ddedbf 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -762,6 +762,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): diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-09-08-00-30-09.bpo-44050.mFI15u.rst b/Misc/NEWS.d/next/Core and Builtins/2021-09-08-00-30-09.bpo-44050.mFI15u.rst new file mode 100644 index 00000000000000..d6eed9f1bcfe9d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-09-08-00-30-09.bpo-44050.mFI15u.rst @@ -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. diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index ad60f32f7e7a62..e0ed77d265cdcc 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -844,6 +844,28 @@ 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; + } + + if (PyModule_AddObjectRef(module, "Error", PyExc_Exception) < 0) { + Py_DECREF(module); + return NULL; + } + return module; +} + /*** Helper for imp test ***/ diff --git a/Python/import.c b/Python/import.c index f2b30afe3f2284..50f4956e5a9d60 100644 --- a/Python/import.c +++ b/Python/import.c @@ -441,7 +441,9 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name, return -1; } - if (_Py_IsMainInterpreter(tstate->interp)) { + // 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->interp) || def->m_size == -1) { if (def->m_size == -1) { if (def->m_base.m_copy) { /* Somebody already imported the module, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy