• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* Support for dynamic loading of extension modules */
3 
4 #include "Python.h"
5 #include "pycore_call.h"
6 #include "pycore_import.h"
7 #include "pycore_pyerrors.h"      // _PyErr_FormatFromCause()
8 #include "pycore_pystate.h"
9 #include "pycore_runtime.h"
10 
11 #include "pycore_importdl.h"
12 
13 /* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is
14    supported on this platform. configure will then compile and link in one
15    of the dynload_*.c files, as appropriate. We will call a function in
16    those modules to get a function pointer to the module's init function.
17 */
18 #ifdef HAVE_DYNAMIC_LOADING
19 
20 #ifdef MS_WINDOWS
21 extern dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
22                                                      const char *shortname,
23                                                      PyObject *pathname,
24                                                      FILE *fp);
25 #else
26 extern dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix,
27                                               const char *shortname,
28                                               const char *pathname, FILE *fp);
29 #endif
30 
31 #endif /* HAVE_DYNAMIC_LOADING */
32 
33 
34 /***********************************/
35 /* module info to use when loading */
36 /***********************************/
37 
38 static const char * const ascii_only_prefix = "PyInit";
39 static const char * const nonascii_prefix = "PyInitU";
40 
41 /* Get the variable part of a module's export symbol name.
42  * Returns a bytes instance. For non-ASCII-named modules, the name is
43  * encoded as per PEP 489.
44  * The hook_prefix pointer is set to either ascii_only_prefix or
45  * nonascii_prefix, as appropriate.
46  */
47 static PyObject *
get_encoded_name(PyObject * name,const char ** hook_prefix)48 get_encoded_name(PyObject *name, const char **hook_prefix) {
49     PyObject *tmp;
50     PyObject *encoded = NULL;
51     PyObject *modname = NULL;
52     Py_ssize_t name_len, lastdot;
53 
54     /* Get the short name (substring after last dot) */
55     name_len = PyUnicode_GetLength(name);
56     if (name_len < 0) {
57         return NULL;
58     }
59     lastdot = PyUnicode_FindChar(name, '.', 0, name_len, -1);
60     if (lastdot < -1) {
61         return NULL;
62     } else if (lastdot >= 0) {
63         tmp = PyUnicode_Substring(name, lastdot + 1, name_len);
64         if (tmp == NULL)
65             return NULL;
66         name = tmp;
67         /* "name" now holds a new reference to the substring */
68     } else {
69         Py_INCREF(name);
70     }
71 
72     /* Encode to ASCII or Punycode, as needed */
73     encoded = PyUnicode_AsEncodedString(name, "ascii", NULL);
74     if (encoded != NULL) {
75         *hook_prefix = ascii_only_prefix;
76     } else {
77         if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
78             PyErr_Clear();
79             encoded = PyUnicode_AsEncodedString(name, "punycode", NULL);
80             if (encoded == NULL) {
81                 goto error;
82             }
83             *hook_prefix = nonascii_prefix;
84         } else {
85             goto error;
86         }
87     }
88 
89     /* Replace '-' by '_' */
90     modname = _PyObject_CallMethod(encoded, &_Py_ID(replace), "cc", '-', '_');
91     if (modname == NULL)
92         goto error;
93 
94     Py_DECREF(name);
95     Py_DECREF(encoded);
96     return modname;
97 error:
98     Py_DECREF(name);
99     Py_XDECREF(encoded);
100     return NULL;
101 }
102 
103 void
_Py_ext_module_loader_info_clear(struct _Py_ext_module_loader_info * info)104 _Py_ext_module_loader_info_clear(struct _Py_ext_module_loader_info *info)
105 {
106     Py_CLEAR(info->filename);
107 #ifndef MS_WINDOWS
108     Py_CLEAR(info->filename_encoded);
109 #endif
110     Py_CLEAR(info->name);
111     Py_CLEAR(info->name_encoded);
112 }
113 
114 int
_Py_ext_module_loader_info_init(struct _Py_ext_module_loader_info * p_info,PyObject * name,PyObject * filename,_Py_ext_module_origin origin)115 _Py_ext_module_loader_info_init(struct _Py_ext_module_loader_info *p_info,
116                                 PyObject *name, PyObject *filename,
117                                 _Py_ext_module_origin origin)
118 {
119     struct _Py_ext_module_loader_info info = {
120         .origin=origin,
121     };
122 
123     assert(name != NULL);
124     if (!PyUnicode_Check(name)) {
125         PyErr_SetString(PyExc_TypeError,
126                         "module name must be a string");
127         _Py_ext_module_loader_info_clear(&info);
128         return -1;
129     }
130     assert(PyUnicode_GetLength(name) > 0);
131     info.name = Py_NewRef(name);
132 
133     info.name_encoded = get_encoded_name(info.name, &info.hook_prefix);
134     if (info.name_encoded == NULL) {
135         _Py_ext_module_loader_info_clear(&info);
136         return -1;
137     }
138 
139     info.newcontext = PyUnicode_AsUTF8(info.name);
140     if (info.newcontext == NULL) {
141         _Py_ext_module_loader_info_clear(&info);
142         return -1;
143     }
144 
145     if (filename != NULL) {
146         if (!PyUnicode_Check(filename)) {
147             PyErr_SetString(PyExc_TypeError,
148                             "module filename must be a string");
149             _Py_ext_module_loader_info_clear(&info);
150             return -1;
151         }
152         info.filename = Py_NewRef(filename);
153 
154 #ifndef MS_WINDOWS
155         info.filename_encoded = PyUnicode_EncodeFSDefault(info.filename);
156         if (info.filename_encoded == NULL) {
157             _Py_ext_module_loader_info_clear(&info);
158             return -1;
159         }
160 #endif
161 
162         info.path = info.filename;
163     }
164     else {
165         info.path = info.name;
166     }
167 
168     *p_info = info;
169     return 0;
170 }
171 
172 int
_Py_ext_module_loader_info_init_for_builtin(struct _Py_ext_module_loader_info * info,PyObject * name)173 _Py_ext_module_loader_info_init_for_builtin(
174                             struct _Py_ext_module_loader_info *info,
175                             PyObject *name)
176 {
177     assert(PyUnicode_Check(name));
178     assert(PyUnicode_FindChar(name, '.', 0, PyUnicode_GetLength(name), -1) == -1);
179     assert(PyUnicode_GetLength(name) > 0);
180 
181     PyObject *name_encoded = PyUnicode_AsEncodedString(name, "ascii", NULL);
182     if (name_encoded == NULL) {
183         return -1;
184     }
185 
186     *info = (struct _Py_ext_module_loader_info){
187         .name=Py_NewRef(name),
188         .name_encoded=name_encoded,
189         /* We won't need filename. */
190         .path=name,
191         .origin=_Py_ext_module_origin_BUILTIN,
192         .hook_prefix=ascii_only_prefix,
193         .newcontext=NULL,
194     };
195     return 0;
196 }
197 
198 int
_Py_ext_module_loader_info_init_for_core(struct _Py_ext_module_loader_info * info,PyObject * name)199 _Py_ext_module_loader_info_init_for_core(
200                             struct _Py_ext_module_loader_info *info,
201                             PyObject *name)
202 {
203     if (_Py_ext_module_loader_info_init_for_builtin(info, name) < 0) {
204         return -1;
205     }
206     info->origin = _Py_ext_module_origin_CORE;
207     return 0;
208 }
209 
210 #ifdef HAVE_DYNAMIC_LOADING
211 int
_Py_ext_module_loader_info_init_from_spec(struct _Py_ext_module_loader_info * p_info,PyObject * spec)212 _Py_ext_module_loader_info_init_from_spec(
213                             struct _Py_ext_module_loader_info *p_info,
214                             PyObject *spec)
215 {
216     PyObject *name = PyObject_GetAttrString(spec, "name");
217     if (name == NULL) {
218         return -1;
219     }
220     PyObject *filename = PyObject_GetAttrString(spec, "origin");
221     if (filename == NULL) {
222         Py_DECREF(name);
223         return -1;
224     }
225     /* We could also accommodate builtin modules here without much trouble. */
226     _Py_ext_module_origin origin = _Py_ext_module_origin_DYNAMIC;
227     int err = _Py_ext_module_loader_info_init(p_info, name, filename, origin);
228     Py_DECREF(name);
229     Py_DECREF(filename);
230     return err;
231 }
232 #endif /* HAVE_DYNAMIC_LOADING */
233 
234 
235 /********************************/
236 /* module init function results */
237 /********************************/
238 
239 void
_Py_ext_module_loader_result_clear(struct _Py_ext_module_loader_result * res)240 _Py_ext_module_loader_result_clear(struct _Py_ext_module_loader_result *res)
241 {
242     /* Instead, the caller should have called
243      * _Py_ext_module_loader_result_apply_error(). */
244     assert(res->err == NULL);
245     *res = (struct _Py_ext_module_loader_result){0};
246 }
247 
248 static void
_Py_ext_module_loader_result_set_error(struct _Py_ext_module_loader_result * res,enum _Py_ext_module_loader_result_error_kind kind)249 _Py_ext_module_loader_result_set_error(
250                             struct _Py_ext_module_loader_result *res,
251                             enum _Py_ext_module_loader_result_error_kind kind)
252 {
253 #ifndef NDEBUG
254     switch (kind) {
255     case _Py_ext_module_loader_result_EXCEPTION:  /* fall through */
256     case _Py_ext_module_loader_result_ERR_UNREPORTED_EXC:
257         assert(PyErr_Occurred());
258         break;
259     case _Py_ext_module_loader_result_ERR_MISSING:  /* fall through */
260     case _Py_ext_module_loader_result_ERR_UNINITIALIZED:  /* fall through */
261     case _Py_ext_module_loader_result_ERR_NONASCII_NOT_MULTIPHASE:  /* fall through */
262     case _Py_ext_module_loader_result_ERR_NOT_MODULE:  /* fall through */
263     case _Py_ext_module_loader_result_ERR_MISSING_DEF:
264         assert(!PyErr_Occurred());
265         break;
266     default:
267         /* We added a new error kind but forgot to add it to this switch. */
268         assert(0);
269     }
270 #endif
271 
272     assert(res->err == NULL && res->_err.exc == NULL);
273     res->err = &res->_err;
274     *res->err = (struct _Py_ext_module_loader_result_error){
275         .kind=kind,
276         .exc=PyErr_GetRaisedException(),
277     };
278 
279     /* For some kinds, we also set/check res->kind. */
280     switch (kind) {
281     case _Py_ext_module_loader_result_ERR_UNINITIALIZED:
282         assert(res->kind == _Py_ext_module_kind_UNKNOWN);
283         res->kind = _Py_ext_module_kind_INVALID;
284         break;
285     /* None of the rest affect the result kind. */
286     case _Py_ext_module_loader_result_EXCEPTION:  /* fall through */
287     case _Py_ext_module_loader_result_ERR_MISSING:  /* fall through */
288     case _Py_ext_module_loader_result_ERR_UNREPORTED_EXC:  /* fall through */
289     case _Py_ext_module_loader_result_ERR_NONASCII_NOT_MULTIPHASE:  /* fall through */
290     case _Py_ext_module_loader_result_ERR_NOT_MODULE:  /* fall through */
291     case _Py_ext_module_loader_result_ERR_MISSING_DEF:
292         break;
293     default:
294         /* We added a new error kind but forgot to add it to this switch. */
295         assert(0);
296     }
297 }
298 
299 void
_Py_ext_module_loader_result_apply_error(struct _Py_ext_module_loader_result * res,const char * name)300 _Py_ext_module_loader_result_apply_error(
301                             struct _Py_ext_module_loader_result *res,
302                             const char *name)
303 {
304     assert(!PyErr_Occurred());
305     assert(res->err != NULL && res->err == &res->_err);
306     struct _Py_ext_module_loader_result_error err = *res->err;
307     res->err = NULL;
308 
309     /* We're otherwise done with the result at this point. */
310     _Py_ext_module_loader_result_clear(res);
311 
312 #ifndef NDEBUG
313     switch (err.kind) {
314     case _Py_ext_module_loader_result_EXCEPTION:  /* fall through */
315     case _Py_ext_module_loader_result_ERR_UNREPORTED_EXC:
316         assert(err.exc != NULL);
317         break;
318     case _Py_ext_module_loader_result_ERR_MISSING:  /* fall through */
319     case _Py_ext_module_loader_result_ERR_UNINITIALIZED:  /* fall through */
320     case _Py_ext_module_loader_result_ERR_NONASCII_NOT_MULTIPHASE:  /* fall through */
321     case _Py_ext_module_loader_result_ERR_NOT_MODULE:  /* fall through */
322     case _Py_ext_module_loader_result_ERR_MISSING_DEF:
323         assert(err.exc == NULL);
324         break;
325     default:
326         /* We added a new error kind but forgot to add it to this switch. */
327         assert(0);
328     }
329 #endif
330 
331     const char *msg = NULL;
332     switch (err.kind) {
333     case _Py_ext_module_loader_result_EXCEPTION:
334         break;
335     case _Py_ext_module_loader_result_ERR_MISSING:
336         msg = "initialization of %s failed without raising an exception";
337         break;
338     case _Py_ext_module_loader_result_ERR_UNREPORTED_EXC:
339         msg = "initialization of %s raised unreported exception";
340         break;
341     case _Py_ext_module_loader_result_ERR_UNINITIALIZED:
342         msg = "init function of %s returned uninitialized object";
343         break;
344     case _Py_ext_module_loader_result_ERR_NONASCII_NOT_MULTIPHASE:
345         msg = "initialization of %s did not return PyModuleDef";
346         break;
347     case _Py_ext_module_loader_result_ERR_NOT_MODULE:
348         msg = "initialization of %s did not return an extension module";
349         break;
350     case _Py_ext_module_loader_result_ERR_MISSING_DEF:
351         msg = "initialization of %s did not return a valid extension module";
352         break;
353     default:
354         /* We added a new error kind but forgot to add it to this switch. */
355         assert(0);
356         PyErr_Format(PyExc_SystemError,
357                      "loading %s failed due to init function", name);
358         return;
359     }
360 
361     if (err.exc != NULL) {
362         PyErr_SetRaisedException(err.exc);
363         err.exc = NULL;  /* PyErr_SetRaisedException() stole our reference. */
364         if (msg != NULL) {
365             _PyErr_FormatFromCause(PyExc_SystemError, msg, name);
366         }
367     }
368     else {
369         assert(msg != NULL);
370         PyErr_Format(PyExc_SystemError, msg, name);
371     }
372 }
373 
374 
375 /********************************************/
376 /* getting/running the module init function */
377 /********************************************/
378 
379 #ifdef HAVE_DYNAMIC_LOADING
380 PyModInitFunction
_PyImport_GetModInitFunc(struct _Py_ext_module_loader_info * info,FILE * fp)381 _PyImport_GetModInitFunc(struct _Py_ext_module_loader_info *info,
382                          FILE *fp)
383 {
384     const char *name_buf = PyBytes_AS_STRING(info->name_encoded);
385     dl_funcptr exportfunc;
386 #ifdef MS_WINDOWS
387     exportfunc = _PyImport_FindSharedFuncptrWindows(
388             info->hook_prefix, name_buf, info->filename, fp);
389 #else
390     {
391         const char *path_buf = PyBytes_AS_STRING(info->filename_encoded);
392         exportfunc = _PyImport_FindSharedFuncptr(
393                         info->hook_prefix, name_buf, path_buf, fp);
394     }
395 #endif
396 
397     if (exportfunc == NULL) {
398         if (!PyErr_Occurred()) {
399             PyObject *msg;
400             msg = PyUnicode_FromFormat(
401                 "dynamic module does not define "
402                 "module export function (%s_%s)",
403                 info->hook_prefix, name_buf);
404             if (msg != NULL) {
405                 PyErr_SetImportError(msg, info->name, info->filename);
406                 Py_DECREF(msg);
407             }
408         }
409         return NULL;
410     }
411 
412     return (PyModInitFunction)exportfunc;
413 }
414 #endif /* HAVE_DYNAMIC_LOADING */
415 
416 int
_PyImport_RunModInitFunc(PyModInitFunction p0,struct _Py_ext_module_loader_info * info,struct _Py_ext_module_loader_result * p_res)417 _PyImport_RunModInitFunc(PyModInitFunction p0,
418                          struct _Py_ext_module_loader_info *info,
419                          struct _Py_ext_module_loader_result *p_res)
420 {
421     struct _Py_ext_module_loader_result res = {
422         .kind=_Py_ext_module_kind_UNKNOWN,
423     };
424 
425     /* Call the module init function. */
426 
427     /* Package context is needed for single-phase init */
428     const char *oldcontext = _PyImport_SwapPackageContext(info->newcontext);
429     PyObject *m = p0();
430     _PyImport_SwapPackageContext(oldcontext);
431 
432     /* Validate the result (and populate "res". */
433 
434     if (m == NULL) {
435         /* The init func for multi-phase init modules is expected
436          * to return a PyModuleDef after calling PyModuleDef_Init().
437          * That function never raises an exception nor returns NULL,
438          * so at this point it must be a single-phase init modules. */
439         res.kind = _Py_ext_module_kind_SINGLEPHASE;
440         if (PyErr_Occurred()) {
441             _Py_ext_module_loader_result_set_error(
442                         &res, _Py_ext_module_loader_result_EXCEPTION);
443         }
444         else {
445             _Py_ext_module_loader_result_set_error(
446                         &res, _Py_ext_module_loader_result_ERR_MISSING);
447         }
448         goto error;
449     } else if (PyErr_Occurred()) {
450         /* Likewise, we infer that this is a single-phase init module. */
451         res.kind = _Py_ext_module_kind_SINGLEPHASE;
452         _Py_ext_module_loader_result_set_error(
453                 &res, _Py_ext_module_loader_result_ERR_UNREPORTED_EXC);
454         /* We would probably be correct to decref m here,
455          * but we weren't doing so before,
456          * so we stick with doing nothing. */
457         m = NULL;
458         goto error;
459     }
460 
461     if (Py_IS_TYPE(m, NULL)) {
462         /* This can happen when a PyModuleDef is returned without calling
463          * PyModuleDef_Init on it
464          */
465         _Py_ext_module_loader_result_set_error(
466                 &res, _Py_ext_module_loader_result_ERR_UNINITIALIZED);
467         /* Likewise, decref'ing here makes sense.  However, the original
468          * code has a note about "prevent segfault in DECREF",
469          * so we play it safe and leave it alone. */
470         m = NULL; /* prevent segfault in DECREF */
471         goto error;
472     }
473 
474     if (PyObject_TypeCheck(m, &PyModuleDef_Type)) {
475         /* multi-phase init */
476         res.kind = _Py_ext_module_kind_MULTIPHASE;
477         res.def = (PyModuleDef *)m;
478         /* Run PyModule_FromDefAndSpec() to finish loading the module. */
479     }
480     else if (info->hook_prefix == nonascii_prefix) {
481         /* Non-ASCII is only supported for multi-phase init. */
482         res.kind = _Py_ext_module_kind_MULTIPHASE;
483         /* Don't allow legacy init for non-ASCII module names. */
484         _Py_ext_module_loader_result_set_error(
485                 &res, _Py_ext_module_loader_result_ERR_NONASCII_NOT_MULTIPHASE);
486         goto error;
487     }
488     else {
489         /* single-phase init (legacy) */
490         res.kind = _Py_ext_module_kind_SINGLEPHASE;
491         res.module = m;
492 
493         if (!PyModule_Check(m)) {
494             _Py_ext_module_loader_result_set_error(
495                     &res, _Py_ext_module_loader_result_ERR_NOT_MODULE);
496             goto error;
497         }
498 
499         res.def = _PyModule_GetDef(m);
500         if (res.def == NULL) {
501             PyErr_Clear();
502             _Py_ext_module_loader_result_set_error(
503                     &res, _Py_ext_module_loader_result_ERR_MISSING_DEF);
504             goto error;
505         }
506     }
507 
508     assert(!PyErr_Occurred());
509     assert(res.err == NULL);
510     *p_res = res;
511     return 0;
512 
513 error:
514     assert(!PyErr_Occurred());
515     assert(res.err != NULL);
516     Py_CLEAR(res.module);
517     res.def = NULL;
518     *p_res = res;
519     p_res->err = &p_res->_err;
520     return -1;
521 }
522