Home | History | Annotate | Download | only in Python
      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 get_encoded_name(PyObject *name, const char **hook_prefix) {
     37     PyObject *tmp;
     38     PyObject *encoded = NULL;
     39     PyObject *modname = NULL;
     40     Py_ssize_t name_len, lastdot;
     41     _Py_IDENTIFIER(replace);
     42 
     43     /* Get the short name (substring after last dot) */
     44     name_len = PyUnicode_GetLength(name);
     45     lastdot = PyUnicode_FindChar(name, '.', 0, name_len, -1);
     46     if (lastdot < -1) {
     47         return NULL;
     48     } else if (lastdot >= 0) {
     49         tmp = PyUnicode_Substring(name, lastdot + 1, name_len);
     50         if (tmp == NULL)
     51             return NULL;
     52         name = tmp;
     53         /* "name" now holds a new reference to the substring */
     54     } else {
     55         Py_INCREF(name);
     56     }
     57 
     58     /* Encode to ASCII or Punycode, as needed */
     59     encoded = PyUnicode_AsEncodedString(name, "ascii", NULL);
     60     if (encoded != NULL) {
     61         *hook_prefix = ascii_only_prefix;
     62     } else {
     63         if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
     64             PyErr_Clear();
     65             encoded = PyUnicode_AsEncodedString(name, "punycode", NULL);
     66             if (encoded == NULL) {
     67                 goto error;
     68             }
     69             *hook_prefix = nonascii_prefix;
     70         } else {
     71             goto error;
     72         }
     73     }
     74 
     75     /* Replace '-' by '_' */
     76     modname = _PyObject_CallMethodId(encoded, &PyId_replace, "cc", '-', '_');
     77     if (modname == NULL)
     78         goto error;
     79 
     80     Py_DECREF(name);
     81     Py_DECREF(encoded);
     82     return modname;
     83 error:
     84     Py_DECREF(name);
     85     Py_XDECREF(encoded);
     86     return NULL;
     87 }
     88 
     89 PyObject *
     90 _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp)
     91 {
     92 #ifndef MS_WINDOWS
     93     PyObject *pathbytes = NULL;
     94 #endif
     95     PyObject *name_unicode = NULL, *name = NULL, *path = NULL, *m = NULL;
     96     const char *name_buf, *hook_prefix;
     97     const char *oldcontext;
     98     dl_funcptr exportfunc;
     99     PyModuleDef *def;
    100     PyObject *(*p0)(void);
    101 
    102     name_unicode = PyObject_GetAttrString(spec, "name");
    103     if (name_unicode == NULL) {
    104         return NULL;
    105     }
    106     if (!PyUnicode_Check(name_unicode)) {
    107         PyErr_SetString(PyExc_TypeError,
    108                         "spec.name must be a string");
    109         goto error;
    110     }
    111 
    112     name = get_encoded_name(name_unicode, &hook_prefix);
    113     if (name == NULL) {
    114         goto error;
    115     }
    116     name_buf = PyBytes_AS_STRING(name);
    117 
    118     path = PyObject_GetAttrString(spec, "origin");
    119     if (path == NULL)
    120         goto error;
    121 
    122 #ifdef MS_WINDOWS
    123     exportfunc = _PyImport_FindSharedFuncptrWindows(hook_prefix, name_buf,
    124                                                     path, fp);
    125 #else
    126     pathbytes = PyUnicode_EncodeFSDefault(path);
    127     if (pathbytes == NULL)
    128         goto error;
    129     exportfunc = _PyImport_FindSharedFuncptr(hook_prefix, name_buf,
    130                                              PyBytes_AS_STRING(pathbytes),
    131                                              fp);
    132     Py_DECREF(pathbytes);
    133 #endif
    134 
    135     if (exportfunc == NULL) {
    136         if (!PyErr_Occurred()) {
    137             PyObject *msg;
    138             msg = PyUnicode_FromFormat(
    139                 "dynamic module does not define "
    140                 "module export function (%s_%s)",
    141                 hook_prefix, name_buf);
    142             if (msg == NULL)
    143                 goto error;
    144             PyErr_SetImportError(msg, name_unicode, path);
    145             Py_DECREF(msg);
    146         }
    147         goto error;
    148     }
    149 
    150     p0 = (PyObject *(*)(void))exportfunc;
    151 
    152     /* Package context is needed for single-phase init */
    153     oldcontext = _Py_PackageContext;
    154     _Py_PackageContext = PyUnicode_AsUTF8(name_unicode);
    155     if (_Py_PackageContext == NULL) {
    156         _Py_PackageContext = oldcontext;
    157         goto error;
    158     }
    159     m = p0();
    160     _Py_PackageContext = oldcontext;
    161 
    162     if (m == NULL) {
    163         if (!PyErr_Occurred()) {
    164             PyErr_Format(
    165                 PyExc_SystemError,
    166                 "initialization of %s failed without raising an exception",
    167                 name_buf);
    168         }
    169         goto error;
    170     } else if (PyErr_Occurred()) {
    171         PyErr_Clear();
    172         PyErr_Format(
    173             PyExc_SystemError,
    174             "initialization of %s raised unreported exception",
    175             name_buf);
    176         m = NULL;
    177         goto error;
    178     }
    179     if (Py_TYPE(m) == NULL) {
    180         /* This can happen when a PyModuleDef is returned without calling
    181          * PyModuleDef_Init on it
    182          */
    183         PyErr_Format(PyExc_SystemError,
    184                      "init function of %s returned uninitialized object",
    185                      name_buf);
    186         m = NULL; /* prevent segfault in DECREF */
    187         goto error;
    188     }
    189     if (PyObject_TypeCheck(m, &PyModuleDef_Type)) {
    190         Py_DECREF(name_unicode);
    191         Py_DECREF(name);
    192         Py_DECREF(path);
    193         return PyModule_FromDefAndSpec((PyModuleDef*)m, spec);
    194     }
    195 
    196     /* Fall back to single-phase init mechanism */
    197 
    198     if (hook_prefix == nonascii_prefix) {
    199         /* don't allow legacy init for non-ASCII module names */
    200         PyErr_Format(
    201             PyExc_SystemError,
    202             "initialization of * did not return PyModuleDef",
    203             name_buf);
    204         goto error;
    205     }
    206 
    207     /* Remember pointer to module init function. */
    208     def = PyModule_GetDef(m);
    209     if (def == NULL) {
    210         PyErr_Format(PyExc_SystemError,
    211                      "initialization of %s did not return an extension "
    212                      "module", name_buf);
    213         goto error;
    214     }
    215     def->m_base.m_init = p0;
    216 
    217     /* Remember the filename as the __file__ attribute */
    218     if (PyModule_AddObject(m, "__file__", path) < 0)
    219         PyErr_Clear(); /* Not important enough to report */
    220     else
    221         Py_INCREF(path);
    222 
    223     PyObject *modules = PyImport_GetModuleDict();
    224     if (_PyImport_FixupExtensionObject(m, name_unicode, path, modules) < 0)
    225         goto error;
    226 
    227     Py_DECREF(name_unicode);
    228     Py_DECREF(name);
    229     Py_DECREF(path);
    230 
    231     return m;
    232 
    233 error:
    234     Py_DECREF(name_unicode);
    235     Py_XDECREF(name);
    236     Py_XDECREF(path);
    237     Py_XDECREF(m);
    238     return NULL;
    239 }
    240 
    241 #endif /* HAVE_DYNAMIC_LOADING */
    242