Coverage Report

Created: 2025-07-11 06:59

/src/Python-3.8.3/Python/importdl.c
Line
Count
Source (jump to first uncovered line)
1
2
/* Support for dynamic loading of extension modules */
3
4
#include "Python.h"
5
6
/* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is
7
   supported on this platform. configure will then compile and link in one
8
   of the dynload_*.c files, as appropriate. We will call a function in
9
   those modules to get a function pointer to the module's init function.
10
*/
11
#ifdef HAVE_DYNAMIC_LOADING
12
13
#include "importdl.h"
14
15
#ifdef MS_WINDOWS
16
extern dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
17
                                                     const char *shortname,
18
                                                     PyObject *pathname,
19
                                                     FILE *fp);
20
#else
21
extern dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix,
22
                                              const char *shortname,
23
                                              const char *pathname, FILE *fp);
24
#endif
25
26
static const char * const ascii_only_prefix = "PyInit";
27
static const char * const nonascii_prefix = "PyInitU";
28
29
/* Get the variable part of a module's export symbol name.
30
 * Returns a bytes instance. For non-ASCII-named modules, the name is
31
 * encoded as per PEP 489.
32
 * The hook_prefix pointer is set to either ascii_only_prefix or
33
 * nonascii_prefix, as appropriate.
34
 */
35
static PyObject *
36
0
get_encoded_name(PyObject *name, const char **hook_prefix) {
37
0
    PyObject *tmp;
38
0
    PyObject *encoded = NULL;
39
0
    PyObject *modname = NULL;
40
0
    Py_ssize_t name_len, lastdot;
41
0
    _Py_IDENTIFIER(replace);
42
43
    /* Get the short name (substring after last dot) */
44
0
    name_len = PyUnicode_GetLength(name);
45
0
    lastdot = PyUnicode_FindChar(name, '.', 0, name_len, -1);
46
0
    if (lastdot < -1) {
47
0
        return NULL;
48
0
    } else if (lastdot >= 0) {
49
0
        tmp = PyUnicode_Substring(name, lastdot + 1, name_len);
50
0
        if (tmp == NULL)
51
0
            return NULL;
52
0
        name = tmp;
53
        /* "name" now holds a new reference to the substring */
54
0
    } else {
55
0
        Py_INCREF(name);
56
0
    }
57
58
    /* Encode to ASCII or Punycode, as needed */
59
0
    encoded = PyUnicode_AsEncodedString(name, "ascii", NULL);
60
0
    if (encoded != NULL) {
61
0
        *hook_prefix = ascii_only_prefix;
62
0
    } else {
63
0
        if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
64
0
            PyErr_Clear();
65
0
            encoded = PyUnicode_AsEncodedString(name, "punycode", NULL);
66
0
            if (encoded == NULL) {
67
0
                goto error;
68
0
            }
69
0
            *hook_prefix = nonascii_prefix;
70
0
        } else {
71
0
            goto error;
72
0
        }
73
0
    }
74
75
    /* Replace '-' by '_' */
76
0
    modname = _PyObject_CallMethodId(encoded, &PyId_replace, "cc", '-', '_');
77
0
    if (modname == NULL)
78
0
        goto error;
79
80
0
    Py_DECREF(name);
81
0
    Py_DECREF(encoded);
82
0
    return modname;
83
0
error:
84
0
    Py_DECREF(name);
85
0
    Py_XDECREF(encoded);
86
0
    return NULL;
87
0
}
88
89
PyObject *
90
_PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp)
91
0
{
92
0
#ifndef MS_WINDOWS
93
0
    PyObject *pathbytes = NULL;
94
0
#endif
95
0
    PyObject *name_unicode = NULL, *name = NULL, *path = NULL, *m = NULL;
96
0
    const char *name_buf, *hook_prefix;
97
0
    const char *oldcontext;
98
0
    dl_funcptr exportfunc;
99
0
    PyModuleDef *def;
100
0
    PyObject *(*p0)(void);
101
102
0
    name_unicode = PyObject_GetAttrString(spec, "name");
103
0
    if (name_unicode == NULL) {
104
0
        return NULL;
105
0
    }
106
0
    if (!PyUnicode_Check(name_unicode)) {
107
0
        PyErr_SetString(PyExc_TypeError,
108
0
                        "spec.name must be a string");
109
0
        goto error;
110
0
    }
111
112
0
    name = get_encoded_name(name_unicode, &hook_prefix);
113
0
    if (name == NULL) {
114
0
        goto error;
115
0
    }
116
0
    name_buf = PyBytes_AS_STRING(name);
117
118
0
    path = PyObject_GetAttrString(spec, "origin");
119
0
    if (path == NULL)
120
0
        goto error;
121
122
0
    if (PySys_Audit("import", "OOOOO", name_unicode, path,
123
0
                    Py_None, Py_None, Py_None) < 0) {
124
0
        return NULL;
125
0
    }
126
127
#ifdef MS_WINDOWS
128
    exportfunc = _PyImport_FindSharedFuncptrWindows(hook_prefix, name_buf,
129
                                                    path, fp);
130
#else
131
0
    pathbytes = PyUnicode_EncodeFSDefault(path);
132
0
    if (pathbytes == NULL)
133
0
        goto error;
134
0
    exportfunc = _PyImport_FindSharedFuncptr(hook_prefix, name_buf,
135
0
                                             PyBytes_AS_STRING(pathbytes),
136
0
                                             fp);
137
0
    Py_DECREF(pathbytes);
138
0
#endif
139
140
0
    if (exportfunc == NULL) {
141
0
        if (!PyErr_Occurred()) {
142
0
            PyObject *msg;
143
0
            msg = PyUnicode_FromFormat(
144
0
                "dynamic module does not define "
145
0
                "module export function (%s_%s)",
146
0
                hook_prefix, name_buf);
147
0
            if (msg == NULL)
148
0
                goto error;
149
0
            PyErr_SetImportError(msg, name_unicode, path);
150
0
            Py_DECREF(msg);
151
0
        }
152
0
        goto error;
153
0
    }
154
155
0
    p0 = (PyObject *(*)(void))exportfunc;
156
157
    /* Package context is needed for single-phase init */
158
0
    oldcontext = _Py_PackageContext;
159
0
    _Py_PackageContext = PyUnicode_AsUTF8(name_unicode);
160
0
    if (_Py_PackageContext == NULL) {
161
0
        _Py_PackageContext = oldcontext;
162
0
        goto error;
163
0
    }
164
0
    m = p0();
165
0
    _Py_PackageContext = oldcontext;
166
167
0
    if (m == NULL) {
168
0
        if (!PyErr_Occurred()) {
169
0
            PyErr_Format(
170
0
                PyExc_SystemError,
171
0
                "initialization of %s failed without raising an exception",
172
0
                name_buf);
173
0
        }
174
0
        goto error;
175
0
    } else if (PyErr_Occurred()) {
176
0
        PyErr_Clear();
177
0
        PyErr_Format(
178
0
            PyExc_SystemError,
179
0
            "initialization of %s raised unreported exception",
180
0
            name_buf);
181
0
        m = NULL;
182
0
        goto error;
183
0
    }
184
0
    if (Py_TYPE(m) == NULL) {
185
        /* This can happen when a PyModuleDef is returned without calling
186
         * PyModuleDef_Init on it
187
         */
188
0
        PyErr_Format(PyExc_SystemError,
189
0
                     "init function of %s returned uninitialized object",
190
0
                     name_buf);
191
0
        m = NULL; /* prevent segfault in DECREF */
192
0
        goto error;
193
0
    }
194
0
    if (PyObject_TypeCheck(m, &PyModuleDef_Type)) {
195
0
        Py_DECREF(name_unicode);
196
0
        Py_DECREF(name);
197
0
        Py_DECREF(path);
198
0
        return PyModule_FromDefAndSpec((PyModuleDef*)m, spec);
199
0
    }
200
201
    /* Fall back to single-phase init mechanism */
202
203
0
    if (hook_prefix == nonascii_prefix) {
204
        /* don't allow legacy init for non-ASCII module names */
205
0
        PyErr_Format(
206
0
            PyExc_SystemError,
207
0
            "initialization of * did not return PyModuleDef",
208
0
            name_buf);
209
0
        goto error;
210
0
    }
211
212
    /* Remember pointer to module init function. */
213
0
    def = PyModule_GetDef(m);
214
0
    if (def == NULL) {
215
0
        PyErr_Format(PyExc_SystemError,
216
0
                     "initialization of %s did not return an extension "
217
0
                     "module", name_buf);
218
0
        goto error;
219
0
    }
220
0
    def->m_base.m_init = p0;
221
222
    /* Remember the filename as the __file__ attribute */
223
0
    if (PyModule_AddObject(m, "__file__", path) < 0)
224
0
        PyErr_Clear(); /* Not important enough to report */
225
0
    else
226
0
        Py_INCREF(path);
227
228
0
    PyObject *modules = PyImport_GetModuleDict();
229
0
    if (_PyImport_FixupExtensionObject(m, name_unicode, path, modules) < 0)
230
0
        goto error;
231
232
0
    Py_DECREF(name_unicode);
233
0
    Py_DECREF(name);
234
0
    Py_DECREF(path);
235
236
0
    return m;
237
238
0
error:
239
0
    Py_DECREF(name_unicode);
240
0
    Py_XDECREF(name);
241
0
    Py_XDECREF(path);
242
0
    Py_XDECREF(m);
243
0
    return NULL;
244
0
}
245
246
#endif /* HAVE_DYNAMIC_LOADING */