]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117953: Add Internal struct _Py_ext_module_loader_info (gh-118194)
authorEric Snow <ericsnowcurrently@gmail.com>
Wed, 24 Apr 2024 17:42:01 +0000 (11:42 -0600)
committerGitHub <noreply@github.com>
Wed, 24 Apr 2024 17:42:01 +0000 (17:42 +0000)
This helps with a later change that splits up _PyImport_LoadDynamicModuleWithSpec().

Include/internal/pycore_importdl.h
Python/import.c
Python/importdl.c

index c8583582b358ac116ea9cdb034f94ade5a8070be..8bf7c2a48f66bea324c427dc85b29097916c8612 100644 (file)
@@ -14,10 +14,38 @@ 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 *filename;
+#ifndef MS_WINDOWS
+    PyObject *filename_encoded;
+#endif
+    PyObject *name;
+    PyObject *name_encoded;
+    /* path is always a borrowed ref of name or filename,
+     * depending on if it's builtin or not. */
+    PyObject *path;
+    const char *hook_prefix;
+    const char *newcontext;
+};
+extern void _Py_ext_module_loader_info_clear(
+    struct _Py_ext_module_loader_info *info);
+extern int _Py_ext_module_loader_info_init(
+    struct _Py_ext_module_loader_info *info,
+    PyObject *name,
+    PyObject *filename);
+extern int _Py_ext_module_loader_info_init_from_spec(
+    struct _Py_ext_module_loader_info *info,
+    PyObject *spec);
+
+extern PyObject *_PyImport_LoadDynamicModuleWithSpec(
+    struct _Py_ext_module_loader_info *info,
+    PyObject *spec,
+    FILE *fp);
+
+
 /* Max length of module suffix searched for -- accommodates "module.slb" */
 #define MAXSUFFIXSIZE 12
 
index 739f506fe03100aa3760e07ff66adea624535bbb..56011295f95190f1b6fac42c7615e63dad9378d8 100644 (file)
@@ -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;
 }
 
index e512161d3071f2d6898e70ce62eca280d864f2d7..65370249493325ebab198fc073235dfb2192a722 100644 (file)
@@ -93,57 +93,108 @@ error:
     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);
-    if (name == NULL) {
-        goto error;
+    info.newcontext = PyUnicode_AsUTF8(info.name);
+    if (info.newcontext == NULL) {
+        _Py_ext_module_loader_info_clear(&info);
+        return -1;
     }
-    name_buf = PyBytes_AS_STRING(name);
 
-    filename = PyObject_GetAttrString(spec, "origin");
+    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) {
+        return -1;
+    }
+    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;
 }