mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	gh-117953: Add Internal struct _Py_ext_module_loader_info (gh-118194)
This helps with a later change that splits up _PyImport_LoadDynamicModuleWithSpec().
This commit is contained in:
		
							parent
							
								
									9b280ab0ab
								
							
						
					
					
						commit
						5865fa5f9b
					
				
					 3 changed files with 180 additions and 94 deletions
				
			
		|  | @ -1328,11 +1328,11 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name, | |||
| 
 | ||||
| 
 | ||||
| static PyObject * | ||||
| import_find_extension(PyThreadState *tstate, PyObject *name, | ||||
|                       PyObject *path) | ||||
| import_find_extension(PyThreadState *tstate, | ||||
|                       struct _Py_ext_module_loader_info *info) | ||||
| { | ||||
|     /* Only single-phase init modules will be in the cache. */ | ||||
|     PyModuleDef *def = _extensions_cache_get(path, name); | ||||
|     PyModuleDef *def = _extensions_cache_get(info->path, info->name); | ||||
|     if (def == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | @ -1340,7 +1340,7 @@ import_find_extension(PyThreadState *tstate, PyObject *name, | |||
|     /* It may have been successfully imported previously
 | ||||
|        in an interpreter that allows legacy modules | ||||
|        but is not allowed in the current interpreter. */ | ||||
|     const char *name_buf = PyUnicode_AsUTF8(name); | ||||
|     const char *name_buf = PyUnicode_AsUTF8(info->name); | ||||
|     assert(name_buf != NULL); | ||||
|     if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { | ||||
|         return NULL; | ||||
|  | @ -1355,12 +1355,13 @@ import_find_extension(PyThreadState *tstate, PyObject *name, | |||
|         if (m_copy == NULL) { | ||||
|             /* It might be a core module (e.g. sys & builtins),
 | ||||
|                for which we don't set m_copy. */ | ||||
|             m_copy = get_core_module_dict(tstate->interp, name, path); | ||||
|             m_copy = get_core_module_dict( | ||||
|                     tstate->interp, info->name, info->path); | ||||
|             if (m_copy == NULL) { | ||||
|                 return NULL; | ||||
|             } | ||||
|         } | ||||
|         mod = import_add_module(tstate, name); | ||||
|         mod = import_add_module(tstate, info->name); | ||||
|         if (mod == NULL) { | ||||
|             return NULL; | ||||
|         } | ||||
|  | @ -1378,15 +1379,16 @@ import_find_extension(PyThreadState *tstate, PyObject *name, | |||
|         if (def->m_base.m_init == NULL) | ||||
|             return NULL; | ||||
|         mod = def->m_base.m_init(); | ||||
|         if (mod == NULL) | ||||
|         if (mod == NULL) { | ||||
|             return NULL; | ||||
|         if (PyObject_SetItem(modules, name, mod) == -1) { | ||||
|         } | ||||
|         if (PyObject_SetItem(modules, info->name, mod) == -1) { | ||||
|             Py_DECREF(mod); | ||||
|             return NULL; | ||||
|         } | ||||
|     } | ||||
|     if (_modules_by_index_set(tstate->interp, def, mod) < 0) { | ||||
|         PyMapping_DelItem(modules, name); | ||||
|         PyMapping_DelItem(modules, info->name); | ||||
|         Py_DECREF(mod); | ||||
|         return NULL; | ||||
|     } | ||||
|  | @ -1394,7 +1396,7 @@ import_find_extension(PyThreadState *tstate, PyObject *name, | |||
|     int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose; | ||||
|     if (verbose) { | ||||
|         PySys_FormatStderr("import %U # previously loaded (%R)\n", | ||||
|                            name, path); | ||||
|                            info->name, info->path); | ||||
|     } | ||||
|     return mod; | ||||
| } | ||||
|  | @ -1505,44 +1507,56 @@ static PyObject* | |||
| create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) | ||||
| { | ||||
|     PyModuleDef *def = NULL; | ||||
|     PyObject *mod = import_find_extension(tstate, name, name); | ||||
| 
 | ||||
|     struct _Py_ext_module_loader_info info; | ||||
|     if (_Py_ext_module_loader_info_init(&info, name, NULL) < 0) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     PyObject *mod = import_find_extension(tstate, &info); | ||||
|     if (mod || _PyErr_Occurred(tstate)) { | ||||
|         return mod; | ||||
|         goto finally; | ||||
|     } | ||||
| 
 | ||||
|     struct _inittab *found = NULL; | ||||
|     for (struct _inittab *p = INITTAB; p->name != NULL; p++) { | ||||
|         if (_PyUnicode_EqualToASCIIString(name, p->name)) { | ||||
|         if (_PyUnicode_EqualToASCIIString(info.name, p->name)) { | ||||
|             found = p; | ||||
|         } | ||||
|     } | ||||
|     if (found == NULL) { | ||||
|         // not found
 | ||||
|         Py_RETURN_NONE; | ||||
|         mod = Py_NewRef(Py_None); | ||||
|         goto finally; | ||||
|     } | ||||
| 
 | ||||
|     PyModInitFunction p0 = (PyModInitFunction)found->initfunc; | ||||
|     if (p0 == NULL) { | ||||
|         /* Cannot re-init internal module ("sys" or "builtins") */ | ||||
|         assert(is_core_module(tstate->interp, name, name)); | ||||
|         return import_add_module(tstate, name); | ||||
|         assert(is_core_module(tstate->interp, info.name, info.path)); | ||||
|         mod = import_add_module(tstate, info.name); | ||||
|         goto finally; | ||||
|     } | ||||
| 
 | ||||
|     mod = p0(); | ||||
|     if (mod == NULL) { | ||||
|         return NULL; | ||||
|         goto finally; | ||||
|     } | ||||
| 
 | ||||
|     if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) { | ||||
|         def = (PyModuleDef*)mod; | ||||
|         assert(!is_singlephase(def)); | ||||
|         return PyModule_FromDefAndSpec(def, spec); | ||||
|         mod = PyModule_FromDefAndSpec(def, spec); | ||||
|         if (mod == NULL) { | ||||
|             goto finally; | ||||
|         } | ||||
|     } | ||||
|     else { | ||||
|         assert(PyModule_Check(mod)); | ||||
|         def = PyModule_GetDef(mod); | ||||
|         if (def == NULL) { | ||||
|             return NULL; | ||||
|             Py_CLEAR(mod); | ||||
|             goto finally; | ||||
|         } | ||||
|         assert(is_singlephase(def)); | ||||
| 
 | ||||
|  | @ -1553,22 +1567,29 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) | |||
|         // gh-88216: Extensions and def->m_base.m_copy can be updated
 | ||||
|         // when the extension module doesn't support sub-interpreters.
 | ||||
|         if (def->m_size == -1 | ||||
|                 && !is_core_module(tstate->interp, name, name)) | ||||
|                 && !is_core_module(tstate->interp, info.name, info.path)) | ||||
|         { | ||||
|             singlephase.m_dict = PyModule_GetDict(mod); | ||||
|             assert(singlephase.m_dict != NULL); | ||||
|         } | ||||
|         if (update_global_state_for_extension( | ||||
|                 tstate, name, name, def, &singlephase) < 0) | ||||
|                 tstate, info.name, info.path, def, &singlephase) < 0) | ||||
|         { | ||||
|             return NULL; | ||||
|             Py_CLEAR(mod); | ||||
|             goto finally; | ||||
|         } | ||||
|         PyObject *modules = get_modules_dict(tstate, true); | ||||
|         if (finish_singlephase_extension(tstate, mod, def, name, modules) < 0) { | ||||
|             return NULL; | ||||
|         if (finish_singlephase_extension( | ||||
|                 tstate, mod, def, info.name, modules) < 0) | ||||
|         { | ||||
|             Py_CLEAR(mod); | ||||
|             goto finally; | ||||
|         } | ||||
|         return mod; | ||||
|     } | ||||
| 
 | ||||
| finally: | ||||
|     _Py_ext_module_loader_info_clear(&info); | ||||
|     return mod; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -3878,28 +3899,22 @@ static PyObject * | |||
| _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) | ||||
| /*[clinic end generated code: output=83249b827a4fde77 input=c31b954f4cf4e09d]*/ | ||||
| { | ||||
|     PyObject *mod, *name, *filename; | ||||
|     PyObject *mod = NULL; | ||||
|     FILE *fp; | ||||
| 
 | ||||
|     name = PyObject_GetAttrString(spec, "name"); | ||||
|     if (name == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     filename = PyObject_GetAttrString(spec, "origin"); | ||||
|     if (filename == NULL) { | ||||
|         Py_DECREF(name); | ||||
|     struct _Py_ext_module_loader_info info; | ||||
|     if (_Py_ext_module_loader_info_init_from_spec(&info, spec) < 0) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     PyThreadState *tstate = _PyThreadState_GET(); | ||||
|     mod = import_find_extension(tstate, name, filename); | ||||
|     mod = import_find_extension(tstate, &info); | ||||
|     if (mod != NULL || _PyErr_Occurred(tstate)) { | ||||
|         assert(mod == NULL || !_PyErr_Occurred(tstate)); | ||||
|         goto finally; | ||||
|     } | ||||
| 
 | ||||
|     if (PySys_Audit("import", "OOOOO", name, filename, | ||||
|     if (PySys_Audit("import", "OOOOO", info.name, info.filename, | ||||
|                     Py_None, Py_None, Py_None) < 0) | ||||
|     { | ||||
|         goto finally; | ||||
|  | @ -3911,7 +3926,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) | |||
|      * _PyImport_GetModInitFunc(), but it isn't clear if the intervening | ||||
|      * code relies on fp still being open. */ | ||||
|     if (file != NULL) { | ||||
|         fp = _Py_fopen_obj(filename, "r"); | ||||
|         fp = _Py_fopen_obj(info.filename, "r"); | ||||
|         if (fp == NULL) { | ||||
|             goto finally; | ||||
|         } | ||||
|  | @ -3920,7 +3935,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) | |||
|         fp = NULL; | ||||
|     } | ||||
| 
 | ||||
|     mod = _PyImport_LoadDynamicModuleWithSpec(spec, fp); | ||||
|     mod = _PyImport_LoadDynamicModuleWithSpec(&info, spec, fp); | ||||
| 
 | ||||
|     // XXX Shouldn't this happen in the error cases too.
 | ||||
|     if (fp) { | ||||
|  | @ -3928,8 +3943,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) | |||
|     } | ||||
| 
 | ||||
| finally: | ||||
|     Py_DECREF(name); | ||||
|     Py_DECREF(filename); | ||||
|     _Py_ext_module_loader_info_clear(&info); | ||||
|     return mod; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -93,57 +93,108 @@ get_encoded_name(PyObject *name, const char **hook_prefix) { | |||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| PyObject * | ||||
| _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) | ||||
| void | ||||
| _Py_ext_module_loader_info_clear(struct _Py_ext_module_loader_info *info) | ||||
| { | ||||
|     Py_CLEAR(info->filename); | ||||
| #ifndef MS_WINDOWS | ||||
|     PyObject *filename_bytes = NULL; | ||||
|     const char *filename_buf; | ||||
|     Py_CLEAR(info->filename_encoded); | ||||
| #endif | ||||
|     PyObject *name_unicode = NULL, *name = NULL, *filename = NULL, *m = NULL; | ||||
|     const char *name_buf, *hook_prefix; | ||||
|     const char *oldcontext, *newcontext; | ||||
|     dl_funcptr exportfunc; | ||||
|     PyModuleDef *def; | ||||
|     PyModInitFunction p0; | ||||
|     Py_CLEAR(info->name); | ||||
|     Py_CLEAR(info->name_encoded); | ||||
| } | ||||
| 
 | ||||
|     name_unicode = PyObject_GetAttrString(spec, "name"); | ||||
|     if (name_unicode == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|     if (!PyUnicode_Check(name_unicode)) { | ||||
| int | ||||
| _Py_ext_module_loader_info_init(struct _Py_ext_module_loader_info *p_info, | ||||
|                                 PyObject *name, PyObject *filename) | ||||
| { | ||||
|     struct _Py_ext_module_loader_info info = {0}; | ||||
| 
 | ||||
|     assert(name != NULL); | ||||
|     if (!PyUnicode_Check(name)) { | ||||
|         PyErr_SetString(PyExc_TypeError, | ||||
|                         "spec.name must be a string"); | ||||
|         goto error; | ||||
|                         "module name must be a string"); | ||||
|         _Py_ext_module_loader_info_clear(&info); | ||||
|         return -1; | ||||
|     } | ||||
|     newcontext = PyUnicode_AsUTF8(name_unicode); | ||||
|     if (newcontext == NULL) { | ||||
|         goto error; | ||||
|     info.name = Py_NewRef(name); | ||||
| 
 | ||||
|     info.name_encoded = get_encoded_name(info.name, &info.hook_prefix); | ||||
|     if (info.name_encoded == NULL) { | ||||
|         _Py_ext_module_loader_info_clear(&info); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     name = get_encoded_name(name_unicode, &hook_prefix); | ||||
|     info.newcontext = PyUnicode_AsUTF8(info.name); | ||||
|     if (info.newcontext == NULL) { | ||||
|         _Py_ext_module_loader_info_clear(&info); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (filename != NULL) { | ||||
|         if (!PyUnicode_Check(filename)) { | ||||
|             PyErr_SetString(PyExc_TypeError, | ||||
|                             "module filename must be a string"); | ||||
|             _Py_ext_module_loader_info_clear(&info); | ||||
|             return -1; | ||||
|         } | ||||
|         info.filename = Py_NewRef(filename); | ||||
| 
 | ||||
| #ifndef MS_WINDOWS | ||||
|         info.filename_encoded = PyUnicode_EncodeFSDefault(info.filename); | ||||
|         if (info.filename_encoded == NULL) { | ||||
|             _Py_ext_module_loader_info_clear(&info); | ||||
|             return -1; | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
|         info.path = info.filename; | ||||
|     } | ||||
|     else { | ||||
|         info.path = info.name; | ||||
|     } | ||||
| 
 | ||||
|     *p_info = info; | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| _Py_ext_module_loader_info_init_from_spec( | ||||
|                             struct _Py_ext_module_loader_info *p_info, | ||||
|                             PyObject *spec) | ||||
| { | ||||
|     PyObject *name = PyObject_GetAttrString(spec, "name"); | ||||
|     if (name == NULL) { | ||||
|         goto error; | ||||
|         return -1; | ||||
|     } | ||||
|     name_buf = PyBytes_AS_STRING(name); | ||||
| 
 | ||||
|     filename = PyObject_GetAttrString(spec, "origin"); | ||||
|     PyObject *filename = PyObject_GetAttrString(spec, "origin"); | ||||
|     if (filename == NULL) { | ||||
|         goto error; | ||||
|         return -1; | ||||
|     } | ||||
|     return _Py_ext_module_loader_info_init(p_info, name, filename); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| PyObject * | ||||
| _PyImport_LoadDynamicModuleWithSpec(struct _Py_ext_module_loader_info *info, | ||||
|                                     PyObject *spec, FILE *fp) | ||||
| { | ||||
|     PyObject *m = NULL; | ||||
|     const char *name_buf = PyBytes_AS_STRING(info->name_encoded); | ||||
|     const char *oldcontext; | ||||
|     dl_funcptr exportfunc; | ||||
|     PyModInitFunction p0; | ||||
|     PyModuleDef *def; | ||||
| 
 | ||||
| #ifdef MS_WINDOWS | ||||
|     exportfunc = _PyImport_FindSharedFuncptrWindows( | ||||
|             hook_prefix, name_buf, filename, fp); | ||||
|             info->hook_prefix, name_buf, info->filename, fp); | ||||
| #else | ||||
|     filename_bytes = PyUnicode_EncodeFSDefault(filename); | ||||
|     if (filename_bytes == NULL) { | ||||
|         goto error; | ||||
|     { | ||||
|         const char *path_buf = PyBytes_AS_STRING(info->filename_encoded); | ||||
|         exportfunc = _PyImport_FindSharedFuncptr( | ||||
|                         info->hook_prefix, name_buf, path_buf, fp); | ||||
|     } | ||||
|     filename_buf = PyBytes_AS_STRING(filename_bytes); | ||||
|     exportfunc = _PyImport_FindSharedFuncptr( | ||||
|             hook_prefix, name_buf, filename_buf, fp); | ||||
|     Py_DECREF(filename_bytes); | ||||
| #endif | ||||
| 
 | ||||
|     if (exportfunc == NULL) { | ||||
|  | @ -152,11 +203,11 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) | |||
|             msg = PyUnicode_FromFormat( | ||||
|                 "dynamic module does not define " | ||||
|                 "module export function (%s_%s)", | ||||
|                 hook_prefix, name_buf); | ||||
|             if (msg == NULL) | ||||
|                 goto error; | ||||
|             PyErr_SetImportError(msg, name_unicode, filename); | ||||
|             Py_DECREF(msg); | ||||
|                 info->hook_prefix, name_buf); | ||||
|             if (msg != NULL) { | ||||
|                 PyErr_SetImportError(msg, info->name, info->filename); | ||||
|                 Py_DECREF(msg); | ||||
|             } | ||||
|         } | ||||
|         goto error; | ||||
|     } | ||||
|  | @ -164,7 +215,7 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) | |||
|     p0 = (PyModInitFunction)exportfunc; | ||||
| 
 | ||||
|     /* Package context is needed for single-phase init */ | ||||
|     oldcontext = _PyImport_SwapPackageContext(newcontext); | ||||
|     oldcontext = _PyImport_SwapPackageContext(info->newcontext); | ||||
|     m = p0(); | ||||
|     _PyImport_SwapPackageContext(oldcontext); | ||||
| 
 | ||||
|  | @ -195,9 +246,6 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) | |||
|         goto error; | ||||
|     } | ||||
|     if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { | ||||
|         Py_DECREF(name_unicode); | ||||
|         Py_DECREF(name); | ||||
|         Py_DECREF(filename); | ||||
|         return PyModule_FromDefAndSpec((PyModuleDef*)m, spec); | ||||
|     } | ||||
| 
 | ||||
|  | @ -207,7 +255,7 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) | |||
|         goto error; | ||||
|     } | ||||
| 
 | ||||
|     if (hook_prefix == nonascii_prefix) { | ||||
|     if (info->hook_prefix == nonascii_prefix) { | ||||
|         /* don't allow legacy init for non-ASCII module names */ | ||||
|         PyErr_Format( | ||||
|             PyExc_SystemError, | ||||
|  | @ -227,24 +275,20 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) | |||
|     def->m_base.m_init = p0; | ||||
| 
 | ||||
|     /* Remember the filename as the __file__ attribute */ | ||||
|     if (PyModule_AddObjectRef(m, "__file__", filename) < 0) { | ||||
|     if (PyModule_AddObjectRef(m, "__file__", info->filename) < 0) { | ||||
|         PyErr_Clear(); /* Not important enough to report */ | ||||
|     } | ||||
| 
 | ||||
|     PyObject *modules = PyImport_GetModuleDict(); | ||||
|     if (_PyImport_FixupExtensionObject(m, name_unicode, filename, modules) < 0) | ||||
|     if (_PyImport_FixupExtensionObject( | ||||
|                 m, info->name, info->filename, modules) < 0) | ||||
|     { | ||||
|         goto error; | ||||
| 
 | ||||
|     Py_DECREF(name_unicode); | ||||
|     Py_DECREF(name); | ||||
|     Py_DECREF(filename); | ||||
|     } | ||||
| 
 | ||||
|     return m; | ||||
| 
 | ||||
| error: | ||||
|     Py_DECREF(name_unicode); | ||||
|     Py_XDECREF(name); | ||||
|     Py_XDECREF(filename); | ||||
|     Py_XDECREF(m); | ||||
|     return NULL; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Eric Snow
						Eric Snow