diff options
Diffstat (limited to 'contrib/tools/python3/Objects/moduleobject.c')
| -rw-r--r-- | contrib/tools/python3/Objects/moduleobject.c | 454 |
1 files changed, 334 insertions, 120 deletions
diff --git a/contrib/tools/python3/Objects/moduleobject.c b/contrib/tools/python3/Objects/moduleobject.c index 4daf1a929e0..d787f290045 100644 --- a/contrib/tools/python3/Objects/moduleobject.c +++ b/contrib/tools/python3/Objects/moduleobject.c @@ -3,15 +3,21 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_fileutils.h" // _Py_wgetcwd #include "pycore_interp.h" // PyInterpreterState.importlib +#include "pycore_modsupport.h" // _PyModule_CreateInitialized() +#include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_object.h" // _PyType_AllocNoTrack +#include "pycore_pyerrors.h" // _PyErr_FormatFromCause() #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_moduleobject.h" // _PyModule_GetDef() -#include "structmember.h" // PyMemberDef +#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString() +#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS() + +#include "osdefs.h" // MAXPATHLEN static PyMemberDef module_members[] = { - {"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY}, + {"__dict__", _Py_T_OBJECT, offsetof(PyModuleObject, md_dict), Py_READONLY}, {0} }; @@ -86,21 +92,31 @@ new_module_notrack(PyTypeObject *mt) m->md_weaklist = NULL; m->md_name = NULL; m->md_dict = PyDict_New(); - if (m->md_dict != NULL) { - return m; + if (m->md_dict == NULL) { + Py_DECREF(m); + return NULL; } - Py_DECREF(m); - return NULL; + return m; +} + +static void +track_module(PyModuleObject *m) +{ + _PyObject_SetDeferredRefcount(m->md_dict); + PyObject_GC_Track(m->md_dict); + + _PyObject_SetDeferredRefcount((PyObject *)m); + PyObject_GC_Track(m); } static PyObject * new_module(PyTypeObject *mt, PyObject *args, PyObject *kws) { - PyObject *m = (PyObject *)new_module_notrack(mt); + PyModuleObject *m = new_module_notrack(mt); if (m != NULL) { - PyObject_GC_Track(m); + track_module(m); } - return m; + return (PyObject *)m; } PyObject * @@ -111,7 +127,7 @@ PyModule_NewObject(PyObject *name) return NULL; if (module_init_dict(m, m->md_dict, name, NULL) != 0) goto fail; - PyObject_GC_Track(m); + track_module(m); return (PyObject *)m; fail: @@ -169,6 +185,7 @@ _add_methods_to_object(PyObject *module, PyObject *name, PyMethodDef *functions) if (func == NULL) { return -1; } + _PyObject_SetDeferredRefcount(func); if (PyObject_SetAttrString(module, fdef->ml_name, func) != 0) { Py_DECREF(func); return -1; @@ -235,6 +252,9 @@ _PyModule_CreateInitialized(PyModuleDef* module, int module_api_version) } } m->md_def = module; +#ifdef Py_GIL_DISABLED + m->md_gil = Py_MOD_GIL_USED; +#endif return (PyObject*)m; } @@ -247,6 +267,8 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio PyObject *m = NULL; int has_multiple_interpreters_slot = 0; void *multiple_interpreters = (void *)0; + int has_gil_slot = 0; + void *gil_slot = Py_MOD_GIL_USED; int has_execution_slots = 0; const char *name; int ret; @@ -301,6 +323,17 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio multiple_interpreters = cur_slot->value; has_multiple_interpreters_slot = 1; break; + case Py_mod_gil: + if (has_gil_slot) { + PyErr_Format( + PyExc_SystemError, + "module %s has more than one 'gil' slot", + name); + goto error; + } + gil_slot = cur_slot->value; + has_gil_slot = 1; + break; default: assert(cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT); PyErr_Format( @@ -360,6 +393,11 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio if (PyModule_Check(m)) { ((PyModuleObject*)m)->md_state = NULL; ((PyModuleObject*)m)->md_def = def; +#ifdef Py_GIL_DISABLED + ((PyModuleObject*)m)->md_gil = gil_slot; +#else + (void)gil_slot; +#endif } else { if (def->m_size > 0 || def->m_traverse || def->m_clear || def->m_free) { PyErr_Format( @@ -401,6 +439,19 @@ error: return NULL; } +#ifdef Py_GIL_DISABLED +int +PyUnstable_Module_SetGIL(PyObject *module, void *gil) +{ + if (!PyModule_Check(module)) { + PyErr_BadInternalCall(); + return -1; + } + ((PyModuleObject *)module)->md_gil = gil; + return 0; +} +#endif + int PyModule_ExecDef(PyObject *module, PyModuleDef *def) { @@ -456,6 +507,7 @@ PyModule_ExecDef(PyObject *module, PyModuleDef *def) } break; case Py_mod_multiple_interpreters: + case Py_mod_gil: /* handled in PyModule_FromDefAndSpec2 */ break; default: @@ -504,29 +556,36 @@ PyModule_GetDict(PyObject *m) PyErr_BadInternalCall(); return NULL; } - return _PyModule_GetDict(m); + return _PyModule_GetDict(m); // borrowed reference } PyObject* -PyModule_GetNameObject(PyObject *m) +PyModule_GetNameObject(PyObject *mod) { - PyObject *d; - PyObject *name; - if (!PyModule_Check(m)) { + if (!PyModule_Check(mod)) { PyErr_BadArgument(); return NULL; } - d = ((PyModuleObject *)m)->md_dict; - if (d == NULL || !PyDict_Check(d) || - (name = PyDict_GetItemWithError(d, &_Py_ID(__name__))) == NULL || - !PyUnicode_Check(name)) - { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_SystemError, "nameless module"); - } - return NULL; + PyObject *dict = ((PyModuleObject *)mod)->md_dict; // borrowed reference + if (dict == NULL || !PyDict_Check(dict)) { + goto error; + } + PyObject *name; + if (PyDict_GetItemRef(dict, &_Py_ID(__name__), &name) <= 0) { + // error or not found + goto error; + } + if (!PyUnicode_Check(name)) { + Py_DECREF(name); + goto error; } - return Py_NewRef(name); + return name; + +error: + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_SystemError, "nameless module"); + } + return NULL; } const char * @@ -542,25 +601,32 @@ PyModule_GetName(PyObject *m) } PyObject* -PyModule_GetFilenameObject(PyObject *m) +PyModule_GetFilenameObject(PyObject *mod) { - PyObject *d; - PyObject *fileobj; - if (!PyModule_Check(m)) { + if (!PyModule_Check(mod)) { PyErr_BadArgument(); return NULL; } - d = ((PyModuleObject *)m)->md_dict; - if (d == NULL || - (fileobj = PyDict_GetItemWithError(d, &_Py_ID(__file__))) == NULL || - !PyUnicode_Check(fileobj)) - { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_SystemError, "module filename missing"); - } - return NULL; + PyObject *dict = ((PyModuleObject *)mod)->md_dict; // borrowed reference + if (dict == NULL) { + goto error; + } + PyObject *fileobj; + if (PyDict_GetItemRef(dict, &_Py_ID(__file__), &fileobj) <= 0) { + // error or not found + goto error; + } + if (!PyUnicode_Check(fileobj)) { + Py_DECREF(fileobj); + goto error; + } + return fileobj; + +error: + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_SystemError, "module filename missing"); } - return Py_NewRef(fileobj); + return NULL; } const char * @@ -633,7 +699,7 @@ _PyModule_ClearDict(PyObject *d) PyErr_Clear(); } if (PyDict_SetItem(d, key, Py_None) != 0) { - PyErr_WriteUnraisable(NULL); + PyErr_FormatUnraisable("Exception ignored on clearing module dict"); } } } @@ -654,7 +720,7 @@ _PyModule_ClearDict(PyObject *d) PyErr_Clear(); } if (PyDict_SetItem(d, key, Py_None) != 0) { - PyErr_WriteUnraisable(NULL); + PyErr_FormatUnraisable("Exception ignored on clearing module dict"); } } } @@ -689,16 +755,7 @@ static int module___init___impl(PyModuleObject *self, PyObject *name, PyObject *doc) /*[clinic end generated code: output=e7e721c26ce7aad7 input=57f9e177401e5e1e]*/ { - PyObject *dict = self->md_dict; - if (dict == NULL) { - dict = PyDict_New(); - if (dict == NULL) - return -1; - self->md_dict = dict; - } - if (module_init_dict(self, dict, name, doc) < 0) - return -1; - return 0; + return module_init_dict(self, self->md_dict, name, doc); } static void @@ -710,8 +767,7 @@ module_dealloc(PyModuleObject *m) if (verbose && m->md_name) { PySys_FormatStderr("# destroy %U\n", m->md_name); } - if (m->md_weaklist != NULL) - PyObject_ClearWeakRefs((PyObject *) m); + FT_CLEAR_WEAKREFS((PyObject *) m, m->md_weaklist); /* bpo-39824: Don't call m_free() if m_size > 0 and md_state=NULL */ if (m->md_def && m->md_def->m_free && (m->md_def->m_size <= 0 || m->md_state != NULL)) @@ -733,27 +789,20 @@ module_repr(PyModuleObject *m) } /* Check if the "_initializing" attribute of the module spec is set to true. - Clear the exception and return 0 if spec is NULL. */ int _PyModuleSpec_IsInitializing(PyObject *spec) { - if (spec != NULL) { - PyObject *value; - int ok = _PyObject_LookupAttr(spec, &_Py_ID(_initializing), &value); - if (ok == 0) { - return 0; - } - if (value != NULL) { - int initializing = PyObject_IsTrue(value); - Py_DECREF(value); - if (initializing >= 0) { - return initializing; - } - } + if (spec == NULL) { + return 0; } - PyErr_Clear(); - return 0; + PyObject *value; + int rc = PyObject_GetOptionalAttr(spec, &_Py_ID(_initializing), &value); + if (rc > 0) { + rc = PyObject_IsTrue(value); + Py_DECREF(value); + } + return rc; } /* Check if the submodule name is in the "_uninitialized_submodules" attribute @@ -766,17 +815,108 @@ _PyModuleSpec_IsUninitializedSubmodule(PyObject *spec, PyObject *name) return 0; } - PyObject *value = PyObject_GetAttr(spec, &_Py_ID(_uninitialized_submodules)); - if (value == NULL) { + PyObject *value; + int rc = PyObject_GetOptionalAttr(spec, &_Py_ID(_uninitialized_submodules), &value); + if (rc > 0) { + rc = PySequence_Contains(value, name); + Py_DECREF(value); + } + return rc; +} + +int +_PyModuleSpec_GetFileOrigin(PyObject *spec, PyObject **p_origin) +{ + PyObject *has_location = NULL; + int rc = PyObject_GetOptionalAttr(spec, &_Py_ID(has_location), &has_location); + if (rc <= 0) { + return rc; + } + // If origin is not a location, or doesn't exist, or is not a str, we could consider falling + // back to module.__file__. But the cases in which module.__file__ is not __spec__.origin + // are cases in which we probably shouldn't be guessing. + rc = PyObject_IsTrue(has_location); + Py_DECREF(has_location); + if (rc <= 0) { + return rc; + } + // has_location is true, so origin is a location + PyObject *origin = NULL; + rc = PyObject_GetOptionalAttr(spec, &_Py_ID(origin), &origin); + if (rc <= 0) { + return rc; + } + assert(origin != NULL); + if (!PyUnicode_Check(origin)) { + Py_DECREF(origin); + return 0; + } + *p_origin = origin; + return 1; +} + +int +_PyModule_IsPossiblyShadowing(PyObject *origin) +{ + // origin must be a unicode subtype + // Returns 1 if the module at origin could be shadowing a module of the + // same name later in the module search path. The condition we check is basically: + // root = os.path.dirname(origin.removesuffix(os.sep + "__init__.py")) + // return not sys.flags.safe_path and root == (sys.path[0] or os.getcwd()) + // Returns 0 otherwise (or if we aren't sure) + // Returns -1 if an error occurred that should be propagated + if (origin == NULL) { + return 0; + } + + // not sys.flags.safe_path + const PyConfig *config = _Py_GetConfig(); + if (config->safe_path) { + return 0; + } + + // root = os.path.dirname(origin.removesuffix(os.sep + "__init__.py")) + wchar_t root[MAXPATHLEN + 1]; + Py_ssize_t size = PyUnicode_AsWideChar(origin, root, MAXPATHLEN); + if (size < 0) { + return -1; + } + assert(size <= MAXPATHLEN); + root[size] = L'\0'; + + wchar_t *sep = wcsrchr(root, SEP); + if (sep == NULL) { return 0; } + // If it's a package then we need to look one directory further up + if (wcscmp(sep + 1, L"__init__.py") == 0) { + *sep = L'\0'; + sep = wcsrchr(root, SEP); + if (sep == NULL) { + return 0; + } + } + *sep = L'\0'; - int is_uninitialized = PySequence_Contains(value, name); - Py_DECREF(value); - if (is_uninitialized == -1) { + // sys.path[0] or os.getcwd() + wchar_t *sys_path_0 = config->sys_path_0; + if (!sys_path_0) { return 0; } - return is_uninitialized; + + wchar_t sys_path_0_buf[MAXPATHLEN]; + if (sys_path_0[0] == L'\0') { + // if sys.path[0] == "", treat it as if it were the current directory + if (!_Py_wgetcwd(sys_path_0_buf, MAXPATHLEN)) { + // If we failed to getcwd, don't raise an exception and instead + // let the caller proceed assuming no shadowing + return 0; + } + sys_path_0 = sys_path_0_buf; + } + + int result = wcscmp(sys_path_0, root) == 0; + return result; } PyObject* @@ -802,58 +942,132 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress) PyErr_Clear(); } assert(m->md_dict != NULL); - getattr = PyDict_GetItemWithError(m->md_dict, &_Py_ID(__getattr__)); + if (PyDict_GetItemRef(m->md_dict, &_Py_ID(__getattr__), &getattr) < 0) { + return NULL; + } if (getattr) { PyObject *result = PyObject_CallOneArg(getattr, name); if (result == NULL && suppress == 1 && PyErr_ExceptionMatches(PyExc_AttributeError)) { // suppress AttributeError PyErr_Clear(); } + Py_DECREF(getattr); return result; } - if (PyErr_Occurred()) { + + // The attribute was not found. We make a best effort attempt at a useful error message, + // but only if we're not suppressing AttributeError. + if (suppress == 1) { return NULL; } - mod_name = PyDict_GetItemWithError(m->md_dict, &_Py_ID(__name__)); - if (mod_name && PyUnicode_Check(mod_name)) { - Py_INCREF(mod_name); - PyObject *spec = PyDict_GetItemWithError(m->md_dict, &_Py_ID(__spec__)); - if (spec == NULL && PyErr_Occurred()) { - Py_DECREF(mod_name); - return NULL; + if (PyDict_GetItemRef(m->md_dict, &_Py_ID(__name__), &mod_name) < 0) { + return NULL; + } + if (!mod_name || !PyUnicode_Check(mod_name)) { + Py_XDECREF(mod_name); + PyErr_Format(PyExc_AttributeError, + "module has no attribute '%U'", name); + return NULL; + } + PyObject *spec; + if (PyDict_GetItemRef(m->md_dict, &_Py_ID(__spec__), &spec) < 0) { + Py_DECREF(mod_name); + return NULL; + } + if (spec == NULL) { + PyErr_Format(PyExc_AttributeError, + "module '%U' has no attribute '%U'", + mod_name, name); + Py_DECREF(mod_name); + return NULL; + } + + PyObject *origin = NULL; + if (_PyModuleSpec_GetFileOrigin(spec, &origin) < 0) { + goto done; + } + + int is_possibly_shadowing = _PyModule_IsPossiblyShadowing(origin); + if (is_possibly_shadowing < 0) { + goto done; + } + int is_possibly_shadowing_stdlib = 0; + if (is_possibly_shadowing) { + PyObject *stdlib_modules; + if (_PySys_GetOptionalAttrString("stdlib_module_names", &stdlib_modules) < 0) { + goto done; + } + if (stdlib_modules && PyAnySet_Check(stdlib_modules)) { + is_possibly_shadowing_stdlib = PySet_Contains(stdlib_modules, mod_name); + if (is_possibly_shadowing_stdlib < 0) { + Py_DECREF(stdlib_modules); + goto done; + } + } + Py_XDECREF(stdlib_modules); + } + + if (is_possibly_shadowing_stdlib) { + assert(origin); + PyErr_Format(PyExc_AttributeError, + "module '%U' has no attribute '%U' " + "(consider renaming '%U' since it has the same " + "name as the standard library module named '%U' " + "and prevents importing that standard library module)", + mod_name, name, origin, mod_name); + } + else { + int rc = _PyModuleSpec_IsInitializing(spec); + if (rc < 0) { + goto done; } - if (suppress != 1) { - Py_XINCREF(spec); - if (_PyModuleSpec_IsInitializing(spec)) { + else if (rc > 0) { + if (is_possibly_shadowing) { + assert(origin); + // For non-stdlib modules, only mention the possibility of + // shadowing if the module is being initialized. PyErr_Format(PyExc_AttributeError, - "partially initialized " - "module '%U' has no attribute '%U' " - "(most likely due to a circular import)", - mod_name, name); + "module '%U' has no attribute '%U' " + "(consider renaming '%U' if it has the same name " + "as a library you intended to import)", + mod_name, name, origin); } - else if (_PyModuleSpec_IsUninitializedSubmodule(spec, name)) { + else if (origin) { PyErr_Format(PyExc_AttributeError, - "cannot access submodule '%U' of module '%U' " - "(most likely due to a circular import)", - name, mod_name); + "partially initialized " + "module '%U' from '%U' has no attribute '%U' " + "(most likely due to a circular import)", + mod_name, origin, name); } else { PyErr_Format(PyExc_AttributeError, - "module '%U' has no attribute '%U'", - mod_name, name); + "partially initialized " + "module '%U' has no attribute '%U' " + "(most likely due to a circular import)", + mod_name, name); + } + } + else { + assert(rc == 0); + rc = _PyModuleSpec_IsUninitializedSubmodule(spec, name); + if (rc > 0) { + PyErr_Format(PyExc_AttributeError, + "cannot access submodule '%U' of module '%U' " + "(most likely due to a circular import)", + name, mod_name); + } + else if (rc == 0) { + PyErr_Format(PyExc_AttributeError, + "module '%U' has no attribute '%U'", + mod_name, name); } - Py_XDECREF(spec); } - Py_DECREF(mod_name); - return NULL; - } - else if (PyErr_Occurred()) { - return NULL; - } - if (suppress != 1) { - PyErr_Format(PyExc_AttributeError, - "module has no attribute '%U'", name); } + +done: + Py_XDECREF(origin); + Py_DECREF(spec); + Py_DECREF(mod_name); return NULL; } @@ -888,10 +1102,9 @@ module_clear(PyModuleObject *m) { int res = m->md_def->m_clear((PyObject*)m); if (PyErr_Occurred()) { - PySys_FormatStderr("Exception ignored in m_clear of module%s%V\n", - m->md_name ? " " : "", - m->md_name, ""); - PyErr_WriteUnraisable(NULL); + PyErr_FormatUnraisable("Exception ignored in m_clear of module%s%V", + m->md_name ? " " : "", + m->md_name, ""); } if (res) return res; @@ -944,11 +1157,8 @@ module_get_annotations(PyModuleObject *m, void *Py_UNUSED(ignored)) return NULL; } - PyObject *annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); - if (annotations) { - Py_INCREF(annotations); - } - else if (!PyErr_Occurred()) { + PyObject *annotations; + if (PyDict_GetItemRef(dict, &_Py_ID(__annotations__), &annotations) == 0) { annotations = PyDict_New(); if (annotations) { int result = PyDict_SetItem( @@ -981,9 +1191,13 @@ module_set_annotations(PyModuleObject *m, PyObject *value, void *Py_UNUSED(ignor } else { /* delete */ - ret = PyDict_DelItem(dict, &_Py_ID(__annotations__)); - if (ret < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_SetString(PyExc_AttributeError, "__annotations__"); + ret = PyDict_Pop(dict, &_Py_ID(__annotations__), NULL); + if (ret == 0) { + PyErr_SetObject(PyExc_AttributeError, &_Py_ID(__annotations__)); + ret = -1; + } + else if (ret > 0) { + ret = 0; } } |
