diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index eb8a9a0db46c22..cb6c957c09fa7e 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -27,6 +27,7 @@ extern int _PyImport_FixupBuiltin( const char *name, /* UTF-8 encoded string */ PyObject *modules ); +// We could probably drop this: extern int _PyImport_FixupExtensionObject(PyObject*, PyObject *, PyObject *, PyObject *); diff --git a/Include/internal/pycore_importdl.h b/Include/internal/pycore_importdl.h index c8583582b358ac..ce9c6366b510ad 100644 --- a/Include/internal/pycore_importdl.h +++ b/Include/internal/pycore_importdl.h @@ -14,10 +14,29 @@ extern "C" { extern const char *_PyImport_DynLoadFiletab[]; -extern PyObject *_PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *); - typedef PyObject *(*PyModInitFunction)(void); +struct _Py_ext_module_loader_info { + PyObject *path; + PyObject *name; + PyObject *name_encoded; + const char *hook_prefix; +}; +extern void _Py_ext_module_loader_info_clear( + struct _Py_ext_module_loader_info *info); +extern int _Py_ext_module_loader_info_from_spec( + PyObject *spec, + struct _Py_ext_module_loader_info *info); + +struct _Py_ext_module_loader_result { + PyModuleDef *def; + PyObject *module; +}; +extern int _PyImport_RunDynamicModule( + struct _Py_ext_module_loader_info *info, + FILE *fp, + struct _Py_ext_module_loader_result *res); + /* Max length of module suffix searched for -- accommodates "module.slb" */ #define MAXSUFFIXSIZE 12 diff --git a/Python/import.c b/Python/import.c index 6544a84d895d4a..9e4bd4556a9a5d 100644 --- a/Python/import.c +++ b/Python/import.c @@ -200,16 +200,22 @@ _PyImport_ClearModules(PyInterpreterState *interp) Py_SETREF(MODULES(interp), NULL); } -PyObject * -PyImport_GetModuleDict(void) +static inline PyObject * +get_modules_dict(PyInterpreterState *interp) { - PyInterpreterState *interp = _PyInterpreterState_GET(); if (MODULES(interp) == NULL) { Py_FatalError("interpreter has no modules dictionary"); } return MODULES(interp); } +PyObject * +PyImport_GetModuleDict(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return get_modules_dict(interp); +} + int _PyImport_SetModule(PyObject *name, PyObject *m) { @@ -619,9 +625,9 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) (6). first time (not found in _PyRuntime.imports.extensions): 1. _imp_create_dynamic_impl() -> import_find_extension() - 2. _imp_create_dynamic_impl() -> _PyImport_LoadDynamicModuleWithSpec() - 3. _PyImport_LoadDynamicModuleWithSpec(): load - 4. _PyImport_LoadDynamicModuleWithSpec(): call + 2. _imp_create_dynamic_impl() -> _PyImport_RunDynamicModule() + 3. _PyImport_RunDynamicModule(): load + 4. _PyImport_RunDynamicModule(): call 5. -> PyModule_Create() -> PyModule_Create2() -> PyModule_CreateInitialized() 6. PyModule_CreateInitialized() -> PyModule_New() 7. PyModule_CreateInitialized(): allocate mod->md_state @@ -629,13 +635,15 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) 9. PyModule_CreateInitialized() -> PyModule_SetDocString() 10. PyModule_CreateInitialized(): set mod->md_def 11. : initialize the module - 12. _PyImport_LoadDynamicModuleWithSpec() -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed() - 13. _PyImport_LoadDynamicModuleWithSpec(): set def->m_base.m_init - 14. _PyImport_LoadDynamicModuleWithSpec(): set __file__ - 15. _PyImport_LoadDynamicModuleWithSpec() -> _PyImport_FixupExtensionObject() - 16. _PyImport_FixupExtensionObject(): add it to interp->imports.modules_by_index - 17. _PyImport_FixupExtensionObject(): copy __dict__ into def->m_base.m_copy - 18. _PyImport_FixupExtensionObject(): add it to _PyRuntime.imports.extensions + 12. _PyImport_RunDynamicModule(): set def->m_base.m_init + 13. _PyImport_RunDynamicModule(): set __file__ + 14. _imp_create_dynamic_impl() -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed() + 15. _imp_create_dynamic_impl() -> fix_up_extension() + 16. fix_up_extension(): add it to _PyRuntime.imports.extensions + 17. fix_up_extension() -> fix_up_extension_for_interpreter() + 18. fix_up_extension_for_interpreter(): set it on sys.modules + 19. fix_up_extension_for_interpreter(): add it to interp->imports.modules_by_index + 20. fix_up_extension_for_interpreter(): copy __dict__ into def->m_base.m_copy (6). subsequent times (found in _PyRuntime.imports.extensions): 1. _imp_create_dynamic_impl() -> import_find_extension() @@ -654,11 +662,12 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) ...for single-phase init modules, where m_size >= 0: (6). not main interpreter and never loaded there - every time (not found in _PyRuntime.imports.extensions): - 1-16. (same as for m_size == -1) + 1-20. (same as for m_size == -1) (6). main interpreter - first time (not found in _PyRuntime.imports.extensions): - 1-16. (same as for m_size == -1) - 17. _PyImport_FixupExtensionObject(): add it to _PyRuntime.imports.extensions + 1-15. (same as for m_size == -1) + 16. fix_up_extension(): add it to _PyRuntime.imports.extensions + 17-20. (same as for m_size == -1) (6). previously loaded in main interpreter (found in _PyRuntime.imports.extensions): 1. _imp_create_dynamic_impl() -> import_find_extension() @@ -673,18 +682,18 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) (6). every time: 1. _imp_create_dynamic_impl() -> import_find_extension() (not found) - 2. _imp_create_dynamic_impl() -> _PyImport_LoadDynamicModuleWithSpec() - 3. _PyImport_LoadDynamicModuleWithSpec(): load module init func - 4. _PyImport_LoadDynamicModuleWithSpec(): call module init func - 5. _PyImport_LoadDynamicModuleWithSpec() -> PyModule_FromDefAndSpec() - 6. PyModule_FromDefAndSpec(): gather/check moduledef slots - 7. if there's a Py_mod_create slot: - 1. PyModule_FromDefAndSpec(): call its function - 8. else: - 1. PyModule_FromDefAndSpec() -> PyModule_NewObject() - 9: PyModule_FromDefAndSpec(): set mod->md_def - 10. PyModule_FromDefAndSpec() -> _add_methods_to_object() - 11. PyModule_FromDefAndSpec() -> PyModule_SetDocString() + 2. _imp_create_dynamic_impl() -> _PyImport_RunDynamicModule() + 3. _PyImport_RunDynamicModule(): load module init func + 4. _PyImport_RunDynamicModule(): call module init func + 5. _imp_create_dynamic_impl() -> PyModule_FromDefAndSpec() + 6. PyModule_FromDefAndSpec(): gather/check moduledef slots + 7. if there's a Py_mod_create slot: + 1. PyModule_FromDefAndSpec(): call its function + 8. else: + 1. PyModule_FromDefAndSpec() -> PyModule_NewObject() + 9: PyModule_FromDefAndSpec(): set mod->md_def + 10. PyModule_FromDefAndSpec() -> _add_methods_to_object() + 11. PyModule_FromDefAndSpec() -> PyModule_SetDocString() (10). every time: 1. _imp_exec_dynamic_impl() -> exec_builtin_or_dynamic() @@ -894,7 +903,7 @@ extensions_lock_release(void) (module name, module name) (for built-in modules) or by (filename, module name) (for dynamically loaded modules), containing these modules. A copy of the module's dictionary is stored by calling - _PyImport_FixupExtensionObject() immediately after the module initialization + fix_up_extension() immediately after the module initialization function succeeds. A copy can be retrieved from there by calling import_find_extension(). @@ -1123,6 +1132,48 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) return 0; } +static PyThreadState * +maybe_switch_to_main_interpreter(PyThreadState *tstate) +{ + PyThreadState *main_tstate = tstate; + if (check_multi_interp_extensions(tstate->interp)) { + /* + If the module is single-phase init then the import + will fail. However, the module's init function will still + get run. That means it may still store state in the + shared-object/DLL address space (which never gets + closed/cleared), including objects (e.g. static types). + + This is a problem for isolated subinterpreters since each + has its own object allocator. If the loaded shared-object + still holds a reference to an object after the corresponding + interpreter has finalized then either we must let it leak + or else any later use of that object by another interpreter + (or across multiple init-fini cycles) will crash the process. + + We avoid the problem by first loading the module in the main + interpreter. + + Here's another complication: the module's init function might + register callbacks, whether in Python (e.g. sys.stdin, atexit) + or in linked libraries. Thus we cannot just dlclose() the + module in this error case. + */ + main_tstate = PyThreadState_New(_PyInterpreterState_Main()); + if (main_tstate == NULL) { + return NULL; + } + main_tstate->_whence = _PyThreadState_WHENCE_EXEC; +#ifndef NDEBUG + PyThreadState *old_tstate = PyThreadState_Swap(main_tstate); + assert(old_tstate == tstate); +#else + (void)PyThreadState_Swap(main_tstate); +#endif + } + return main_tstate; +} + static PyObject * get_core_module_dict(PyInterpreterState *interp, PyObject *name, PyObject *filename) @@ -1159,28 +1210,29 @@ is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *filename) } static int -fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) +fix_up_extension_for_interpreter(PyInterpreterState *interp, + PyObject *mod, PyModuleDef *def, + PyObject *name, PyObject *filename, + PyObject *modules) { - if (mod == NULL || !PyModule_Check(mod)) { - PyErr_BadInternalCall(); - return -1; - } + assert(mod != NULL && PyModule_Check(mod)); + assert(def == PyModule_GetDef(mod)); - struct PyModuleDef *def = PyModule_GetDef(mod); - if (!def) { - PyErr_BadInternalCall(); + if (modules == NULL) { + modules = get_modules_dict(interp); + } + if (PyObject_SetItem(modules, name, mod) < 0) { return -1; } - PyThreadState *tstate = _PyThreadState_GET(); - if (_modules_by_index_set(tstate->interp, def, mod) < 0) { - return -1; + if (_modules_by_index_set(interp, def, mod) < 0) { + goto error; } // bpo-44050: Extensions and def->m_base.m_copy can be updated // when the extension module doesn't support sub-interpreters. if (def->m_size == -1) { - if (!is_core_module(tstate->interp, name, filename)) { + if (!is_core_module(interp, name, filename)) { assert(PyUnicode_CompareWithASCIIString(name, "sys") != 0); assert(PyUnicode_CompareWithASCIIString(name, "builtins") != 0); if (def->m_base.m_copy) { @@ -1191,22 +1243,54 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) } PyObject *dict = PyModule_GetDict(mod); if (dict == NULL) { - return -1; + goto error; } def->m_base.m_copy = PyDict_Copy(dict); if (def->m_base.m_copy == NULL) { - return -1; + goto error; } } } + return 0; + +error: + PyMapping_DelItem(modules, name); + return -1; +} + + +static int +fix_up_extension(PyObject *mod, PyModuleDef *def, + PyObject *name, PyObject *filename, + PyObject *modules) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (def == NULL) { + def = PyModule_GetDef(mod); + if (def == NULL) { + PyErr_BadInternalCall(); + return -1; + } + } + // XXX Why special-case the main interpreter? - if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { + if (_Py_IsMainInterpreter(interp) || def->m_size == -1) { +#ifndef NDEBUG + PyModuleDef *cached = _extensions_cache_get(filename, name); + assert(cached == NULL || cached == def); +#endif if (_extensions_cache_set(filename, name, def) < 0) { return -1; } } + if (fix_up_extension_for_interpreter( + interp, mod, def, name, filename, modules) < 0) + { + return -1; + } + return 0; } @@ -1214,11 +1298,11 @@ int _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name, PyObject *filename, PyObject *modules) { - if (PyObject_SetItem(modules, name, mod) < 0) { + if (mod == NULL || !PyModule_Check(mod)) { + PyErr_BadInternalCall(); return -1; } - if (fix_up_extension(mod, name, filename) < 0) { - PyMapping_DelItem(modules, name); + if (fix_up_extension(mod, NULL, name, filename, modules) < 0) { return -1; } return 0; @@ -1341,11 +1425,8 @@ _PyImport_FixupBuiltin(PyObject *mod, const char *name, PyObject *modules) if (nameobj == NULL) { return -1; } - if (PyObject_SetItem(modules, nameobj, mod) < 0) { - goto finally; - } - if (fix_up_extension(mod, nameobj, nameobj) < 0) { - PyMapping_DelItem(modules, nameobj); + assert(mod != NULL && PyModule_Check(mod)); + if (fix_up_extension(mod, NULL, nameobj, nameobj, modules) < 0) { goto finally; } res = 0; @@ -1397,15 +1478,15 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) return PyModule_FromDefAndSpec((PyModuleDef*)mod, spec); } else { + assert(PyModule_Check(mod)); /* Remember pointer to module init function. */ PyModuleDef *def = PyModule_GetDef(mod); if (def == NULL) { return NULL; } - def->m_base.m_init = p->initfunc; - if (_PyImport_FixupExtensionObject(mod, name, name, - modules) < 0) { + + if (fix_up_extension(mod, def, name, name, modules) < 0) { return NULL; } return mod; @@ -3717,44 +3798,90 @@ static PyObject * _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) /*[clinic end generated code: output=83249b827a4fde77 input=c31b954f4cf4e09d]*/ { - PyObject *mod, *name, *path; - FILE *fp; - - name = PyObject_GetAttrString(spec, "name"); - if (name == NULL) { - return NULL; - } + PyObject *mod = NULL; + FILE *fp = NULL; + struct _Py_ext_module_loader_info info; + struct _Py_ext_module_loader_result res; - path = PyObject_GetAttrString(spec, "origin"); - if (path == NULL) { - Py_DECREF(name); + if (_Py_ext_module_loader_info_from_spec(spec, &info) < 0) { return NULL; } + const char *name_buf = PyBytes_AS_STRING(info.name_encoded); PyThreadState *tstate = _PyThreadState_GET(); - mod = import_find_extension(tstate, name, path); + mod = import_find_extension(tstate, info.name, info.path); if (mod != NULL || _PyErr_Occurred(tstate)) { assert(mod == NULL || !_PyErr_Occurred(tstate)); goto finally; } + /* Is multi-phase init or this is the first time being loaded. */ + if (file != NULL) { - fp = _Py_fopen_obj(path, "r"); + fp = _Py_fopen_obj(info.path, "r"); if (fp == NULL) { goto finally; } } - else + else { fp = NULL; + } - mod = _PyImport_LoadDynamicModuleWithSpec(spec, fp); + PyThreadState *main_tstate = maybe_switch_to_main_interpreter(tstate); - if (fp) - fclose(fp); + if (_PyImport_RunDynamicModule(&info, fp, &res) < 0) { + goto finally; + } + mod = res.module; + + if (main_tstate != tstate) { + /* The init func ran under the main interpreter. + Now we must switch back and run it again under + the original interpreter. Only then should we + finish loading the module. */ + int is_singlephase = (mod != NULL); + Py_CLEAR(mod); + (void)PyThreadState_Swap(tstate); + if (is_singlephase) { + /* maybe_switch_to_main_interpreter() switched interpreters + only if it was an isolated interpreter. Thus we know + that a single-phase init module is incompatible. */ + (void)_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf); + assert(PyErr_Occurred()); + goto finally; + } + if (_PyImport_RunDynamicModule(&info, fp, &res) < 0) { + goto finally; + } + mod = res.module; + } + + if (mod == NULL) { + /* multi-phase init */ + + mod = PyModule_FromDefAndSpec(res.def, spec); + } + else { + /* Fall back to single-phase init mechanism */ + + const char *name_buf = PyBytes_AS_STRING(info.name_encoded); + if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { + Py_CLEAR(mod); + goto finally; + } + + if (fix_up_extension(mod, res.def, info.name, info.path, NULL) < 0) { + Py_CLEAR(mod); + goto finally; + } + } finally: - Py_DECREF(name); - Py_DECREF(path); + if (fp != NULL) { + fclose(fp); + } + + _Py_ext_module_loader_info_clear(&info); return mod; } diff --git a/Python/importdl.c b/Python/importdl.c index 7dfd301d77efb4..bbfb4620806b7e 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -93,58 +93,91 @@ 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) { -#ifndef MS_WINDOWS - PyObject *pathbytes = NULL; -#endif - PyObject *name_unicode = NULL, *name = NULL, *path = NULL, *m = NULL; - const char *name_buf, *hook_prefix; - const char *oldcontext, *newcontext; - dl_funcptr exportfunc; - PyModuleDef *def; - PyModInitFunction p0; + Py_CLEAR(info->path); + Py_CLEAR(info->name); + Py_CLEAR(info->name_encoded); +} + +int +_Py_ext_module_loader_info_from_spec(PyObject *spec, + struct _Py_ext_module_loader_info *info) +{ + PyObject *name_unicode = NULL, *name = NULL, *path = NULL; + const char *hook_prefix; name_unicode = PyObject_GetAttrString(spec, "name"); if (name_unicode == NULL) { - return NULL; + return -1; } if (!PyUnicode_Check(name_unicode)) { PyErr_SetString(PyExc_TypeError, "spec.name must be a string"); - goto error; - } - newcontext = PyUnicode_AsUTF8(name_unicode); - if (newcontext == NULL) { - goto error; + Py_DECREF(name_unicode); + return -1; } name = get_encoded_name(name_unicode, &hook_prefix); if (name == NULL) { - goto error; + Py_DECREF(name_unicode); + return -1; } - name_buf = PyBytes_AS_STRING(name); path = PyObject_GetAttrString(spec, "origin"); - if (path == NULL) - goto error; + if (path == NULL) { + Py_DECREF(name_unicode); + Py_DECREF(name); + return -1; + } + + *info = (struct _Py_ext_module_loader_info){ + .path=path, + .name=name_unicode, + .name_encoded=name, + .hook_prefix=hook_prefix, + }; + return 0; +} + +int +_PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, + FILE *fp, + struct _Py_ext_module_loader_result *res) +{ +#ifndef MS_WINDOWS + PyObject *pathbytes = NULL; + const char *path_buf; +#endif + PyObject *m = NULL; + const char *name_buf = PyBytes_AS_STRING(info->name_encoded); + const char *oldcontext, *newcontext; + dl_funcptr exportfunc; + PyModInitFunction p0; + PyModuleDef *def; + + newcontext = PyUnicode_AsUTF8(info->name); + if (newcontext == NULL) { + return -1; + } - if (PySys_Audit("import", "OOOOO", name_unicode, path, + if (PySys_Audit("import", "OOOOO", info->name, info->path, Py_None, Py_None, Py_None) < 0) { - goto error; + return -1; } #ifdef MS_WINDOWS - exportfunc = _PyImport_FindSharedFuncptrWindows(hook_prefix, name_buf, - path, fp); + exportfunc = _PyImport_FindSharedFuncptrWindows( + info->hook_prefix, name_buf, info->path, fp); #else - pathbytes = PyUnicode_EncodeFSDefault(path); - if (pathbytes == NULL) - goto error; - exportfunc = _PyImport_FindSharedFuncptr(hook_prefix, name_buf, - PyBytes_AS_STRING(pathbytes), - fp); + pathbytes = PyUnicode_EncodeFSDefault(info->path); + if (pathbytes == NULL) { + return -1; + } + path_buf = PyBytes_AS_STRING(pathbytes); + exportfunc = _PyImport_FindSharedFuncptr( + info->hook_prefix, name_buf, path_buf, fp); Py_DECREF(pathbytes); #endif @@ -154,13 +187,13 @@ _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, path); - Py_DECREF(msg); + info->hook_prefix, name_buf); + if (msg != NULL) { + PyErr_SetImportError(msg, info->name, info->path); + Py_DECREF(msg); + } } - goto error; + return -1; } p0 = (PyModInitFunction)exportfunc; @@ -177,14 +210,14 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) "initialization of %s failed without raising an exception", name_buf); } - goto error; + return -1; } else if (PyErr_Occurred()) { _PyErr_FormatFromCause( PyExc_SystemError, "initialization of %s raised unreported exception", name_buf); m = NULL; - goto error; + return -1; } if (Py_IS_TYPE(m, NULL)) { /* This can happen when a PyModuleDef is returned without calling @@ -194,61 +227,54 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) "init function of %s returned uninitialized object", name_buf); m = NULL; /* prevent segfault in DECREF */ - goto error; + return -1; } - if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { - Py_DECREF(name_unicode); - Py_DECREF(name); - Py_DECREF(path); - return PyModule_FromDefAndSpec((PyModuleDef*)m, spec); - } - - /* Fall back to single-phase init mechanism */ - if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { - goto error; - } + if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { + /* multi-phase init */ - if (hook_prefix == nonascii_prefix) { - /* don't allow legacy init for non-ASCII module names */ - PyErr_Format( - PyExc_SystemError, - "initialization of %s did not return PyModuleDef", - name_buf); - goto error; - } + def = (PyModuleDef *)m; + m = NULL; - /* Remember pointer to module init function. */ - def = PyModule_GetDef(m); - if (def == NULL) { - PyErr_Format(PyExc_SystemError, - "initialization of %s did not return an extension " - "module", name_buf); - goto error; + /* Run PyModule_FromDefAndSpec() to finish loading the module. */ } - def->m_base.m_init = p0; + else { + /* single-phase init (legacy) */ - /* Remember the filename as the __file__ attribute */ - if (PyModule_AddObjectRef(m, "__file__", path) < 0) { - PyErr_Clear(); /* Not important enough to report */ - } + /* Remember pointer to module init function. */ + def = PyModule_GetDef(m); + if (def == NULL) { + PyErr_Format(PyExc_SystemError, + "initialization of %s did not return an extension " + "module", name_buf); + Py_DECREF(m); + return -1; + } + def->m_base.m_init = p0; - PyObject *modules = PyImport_GetModuleDict(); - if (_PyImport_FixupExtensionObject(m, name_unicode, path, modules) < 0) - goto error; + if (info->hook_prefix == nonascii_prefix) { + /* don't allow legacy init for non-ASCII module names */ + PyErr_Format( + PyExc_SystemError, + "initialization of %s did not return PyModuleDef", + name_buf); + Py_DECREF(m); + return -1; + } - Py_DECREF(name_unicode); - Py_DECREF(name); - Py_DECREF(path); + /* Remember the filename as the __file__ attribute */ + if (PyModule_AddObjectRef(m, "__file__", info->path) < 0) { + PyErr_Clear(); /* Not important enough to report */ + } - return m; + /* Run _PyImport_FixupExtensionObject() to finish loading the module. */ + } -error: - Py_DECREF(name_unicode); - Py_XDECREF(name); - Py_XDECREF(path); - Py_XDECREF(m); - return NULL; + *res = (struct _Py_ext_module_loader_result){ + .def=def, + .module=m, + }; + return 0; } #endif /* HAVE_DYNAMIC_LOADING */ 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