(root)/
Python-3.11.7/
Python/
importdl.c
       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) {
      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 *
      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 */