summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2019-02-22 20:53:33 +0100
committerStefan Behnel <stefan_ml@behnel.de>2019-02-22 20:53:33 +0100
commitfb26190830ce90218070be95cac3ccf8e33717f1 (patch)
tree955ec4cfcb66df74cd2ebe59e9241fbeace7d1b1
parent4993ba6a0194c2fbcf438ae2833f43c33781148d (diff)
downloadcython-fb26190830ce90218070be95cac3ccf8e33717f1.tar.gz
GH-2854: Implement CPython's safety guard against concurrent module initialisations during the import.
-rw-r--r--Cython/Utility/ImportExport.c76
1 files changed, 43 insertions, 33 deletions
diff --git a/Cython/Utility/ImportExport.c b/Cython/Utility/ImportExport.c
index 24f98b56d..2727ab03c 100644
--- a/Cython/Utility/ImportExport.c
+++ b/Cython/Utility/ImportExport.c
@@ -56,9 +56,23 @@ bad:
}
#endif
+static PyObject *__Pyx__ImportDottedModule_Lookup(PyObject *name) {
+ PyObject *imported_module;
+#if PY_VERSION_HEX < 0x030700A1
+ PyObject *modules = PyImport_GetModuleDict();
+ if (unlikely(!modules))
+ return NULL;
+ imported_module = __Pyx_PyDict_GetItemStr(modules, name);
+ Py_XINCREF(imported_module);
+#else
+ imported_module = PyImport_GetModule(name);
+#endif
+ return imported_module;
+}
+
static PyObject *__Pyx__ImportDottedModule(PyObject *name, CYTHON_UNUSED PyObject *parts_tuple) {
#if PY_MAJOR_VERSION < 3
- PyObject *module, *from_list = NULL, *star = PYIDENT("*");
+ PyObject *module, *from_list, *star = PYIDENT("*");
from_list = PyList_New(1);
if (unlikely(!from_list))
return NULL;
@@ -69,10 +83,19 @@ static PyObject *__Pyx__ImportDottedModule(PyObject *name, CYTHON_UNUSED PyObjec
return module;
#else
Py_ssize_t i, nparts;
+ PyObject *imported_module;
PyObject *module = __Pyx_Import(name, NULL, 0);
if (!parts_tuple || unlikely(!module))
return module;
+ // Look up module in sys.modules, which is safer than the attribute lookups below.
+ imported_module = __Pyx__ImportDottedModule_Lookup(name);
+ if (likely(imported_module)) {
+ Py_DECREF(module);
+ return imported_module;
+ }
+ PyErr_Clear();
+
nparts = PyTuple_GET_SIZE(parts_tuple);
for (i=1; i < nparts && module; i++) {
PyObject *part, *submodule;
@@ -96,39 +119,26 @@ static PyObject *__Pyx__ImportDottedModule(PyObject *name, CYTHON_UNUSED PyObjec
static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple) {
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030400B1
- PyObject *module;
- #if PY_VERSION_HEX < 0x030700A1
- PyObject *modules = PyImport_GetModuleDict();
- if (unlikely(!modules))
- return NULL;
- module = __Pyx_PyDict_GetItemStr(modules, name);
- Py_XINCREF(module);
- #else
- module = PyImport_GetModule(name);
- #endif
+ PyObject *module = __Pyx__ImportDottedModule_Lookup(name);
if (likely(module)) {
- // TODO: CPython guards against thread-concurrent imports in importlib,
- // but importing and calling into importlib just for that rare case would
- // be quite costly, so we skip it for now.
- return module;
-
-// -- Code copied from Py3.8-pre:
-// PyObject *spec = __Pyx_PyObject_GetAttrStrNoError(module, PYIDENT("__spec__"));
-// if (likely(spec)) {
-// PyObject *unsafe = __Pyx_PyObject_GetAttrStrNoError(spec, PYIDENT("_initializing"));
-// if (likely(!unsafe || !__Pyx_PyObject_IsTrue(unsafe))) {
-// Py_DECREF(spec);
-// spec = NULL;
-// }
-// Py_XDECREF(unsafe);
-// }
-// if (likely(!spec)) {
-// PyErr_Clear();
-// return module;
-// }
-// Py_DECREF(spec);
-// // Need to let PyImport_ImportModuleLevelObject() handle the locking.
-// Py_DECREF(module);
+ // CPython guards against thread-concurrent initialisation in importlib.
+ // In this case, we let PyImport_ImportModuleLevelObject() handle the locking.
+ PyObject *spec = __Pyx_PyObject_GetAttrStrNoError(module, PYIDENT("__spec__"));
+ if (likely(spec)) {
+ PyObject *unsafe = __Pyx_PyObject_GetAttrStrNoError(spec, PYIDENT("_initializing"));
+ if (likely(!unsafe || !__Pyx_PyObject_IsTrue(unsafe))) {
+ Py_DECREF(spec);
+ spec = NULL;
+ }
+ Py_XDECREF(unsafe);
+ }
+ if (likely(!spec)) {
+ // Not in initialisation phase => use modules as is.
+ PyErr_Clear();
+ return module;
+ }
+ Py_DECREF(spec);
+ Py_DECREF(module);
} else if (PyErr_Occurred()) {
PyErr_Clear();
}