Kaydet (Commit) b4baacee authored tarafından Serhiy Storchaka's avatar Serhiy Storchaka Kaydeden (comit) GitHub

bpo-30814: Fixed a race condition when import a submodule from a package. (#2580)

üst 1ccbad9c
......@@ -956,9 +956,19 @@ def _find_and_load_unlocked(name, import_):
def _find_and_load(name, import_):
"""Find and load the module, and release the import lock."""
with _ModuleLockManager(name):
return _find_and_load_unlocked(name, import_)
"""Find and load the module."""
_imp.acquire_lock()
if name not in sys.modules:
with _ModuleLockManager(name):
return _find_and_load_unlocked(name, import_)
module = sys.modules[name]
if module is None:
_imp.release_lock()
message = ('import of {} halted; '
'None in sys.modules'.format(name))
raise ModuleNotFoundError(message, name=name)
_lock_unlock_module(name)
return module
def _gcd_import(name, package=None, level=0):
......@@ -973,17 +983,7 @@ def _gcd_import(name, package=None, level=0):
_sanity_check(name, package, level)
if level > 0:
name = _resolve_name(name, package, level)
_imp.acquire_lock()
if name not in sys.modules:
return _find_and_load(name, _gcd_import)
module = sys.modules[name]
if module is None:
_imp.release_lock()
message = ('import of {} halted; '
'None in sys.modules'.format(name))
raise ModuleNotFoundError(message, name=name)
_lock_unlock_module(name)
return module
return _find_and_load(name, _gcd_import)
def _handle_fromlist(module, fromlist, import_):
......
......@@ -10,6 +10,8 @@ import py_compile
import random
import stat
import sys
import threading
import time
import unittest
import unittest.mock as mock
import textwrap
......@@ -380,6 +382,32 @@ class ImportTests(unittest.TestCase):
self.assertEqual(str(cm.exception),
"cannot import name 'does_not_exist' from '<unknown module name>' (unknown location)")
def test_concurrency(self):
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'data'))
try:
exc = None
def run():
event.wait()
try:
import package
except BaseException as e:
nonlocal exc
exc = e
for i in range(10):
event = threading.Event()
threads = [threading.Thread(target=run) for x in range(2)]
try:
with test.support.start_threads(threads, event.set):
time.sleep(0)
finally:
sys.modules.pop('package', None)
sys.modules.pop('package.submodule', None)
if exc is not None:
raise exc
finally:
del sys.path[0]
@skip_if_dont_write_bytecode
class FilePermissionTests(unittest.TestCase):
......
import package.submodule
package.submodule
......@@ -10,6 +10,8 @@ What's New in Python 3.7.0 alpha 1?
Core and Builtins
-----------------
- bpo-30814: Fixed a race condition when import a submodule from a package.
- bpo-30736: The internal unicodedata database has been upgraded to Unicode
10.0.
......
......@@ -1532,18 +1532,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
}
mod = PyDict_GetItem(interp->modules, abs_name);
if (mod == Py_None) {
PyObject *msg = PyUnicode_FromFormat("import of %R halted; "
"None in sys.modules", abs_name);
if (msg != NULL) {
PyErr_SetImportErrorSubclass(PyExc_ModuleNotFoundError, msg,
abs_name, NULL);
Py_DECREF(msg);
}
mod = NULL;
goto error;
}
else if (mod != NULL) {
if (mod != NULL && mod != Py_None) {
_Py_IDENTIFIER(__spec__);
_Py_IDENTIFIER(_initializing);
_Py_IDENTIFIER(_lock_unlock_module);
......@@ -1584,10 +1573,6 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
}
}
else {
#ifdef WITH_THREAD
_PyImport_AcquireLock();
#endif
/* _bootstrap._find_and_load() releases the import lock */
mod = _PyObject_CallMethodIdObjArgs(interp->importlib,
&PyId__find_and_load, abs_name,
interp->import_func, NULL);
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment