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 *
get_encoded_name(PyObject * name,const char ** hook_prefix)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) {
48         return NULL;
49     }
50     lastdot = PyUnicode_FindChar(name, '.', 0, name_len, -1);
51     if (lastdot < -1) {
52         return NULL;
53     } else if (lastdot >= 0) {
54         tmp = PyUnicode_Substring(name, lastdot + 1, name_len);
55         if (tmp == NULL)
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) {
66         *hook_prefix = ascii_only_prefix;
67     } else {
68         if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
69             PyErr_Clear();
70             encoded = PyUnicode_AsEncodedString(name, "punycode", NULL);
71             if (encoded == NULL) {
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)
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 *
_PyImport_LoadDynamicModuleWithSpec(PyObject * spec,FILE * fp)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) {
109         return NULL;
110     }
111     if (!PyUnicode_Check(name_unicode)) {
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) {
119         goto error;
120     }
121     name_buf = PyBytes_AS_STRING(name);
122 
123     path = PyObject_GetAttrString(spec, "origin");
124     if (path == NULL)
125         goto error;
126 
127     if (PySys_Audit("import", "OOOOO", name_unicode, path,
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)
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) {
146         if (!PyErr_Occurred()) {
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)
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) {
166         _Py_PackageContext = oldcontext;
167         goto error;
168     }
169     m = _PyImport_InitFunc_TrampolineCall(p0);
170     _Py_PackageContext = oldcontext;
171 
172     if (m == NULL) {
173         if (!PyErr_Occurred()) {
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()) {
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) {
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) {
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) {
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)
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 */
251