LCOV - code coverage report
Current view: top level - Python - importdl.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 92 116 79.3 %
Date: 2022-07-07 18:19:46 Functions: 2 2 100.0 %

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

Generated by: LCOV version 1.14