Coverage Report

Created: 2022-07-08 09:39

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