1
2 /* Support for dynamic loading of extension modules */
3
4 #include "Python.h"
5 #include "pycore_pystate.h"
6 #include "importdl.h"
7
8 #include <sys/types.h>
9 #include <sys/stat.h>
10
11 #if defined(__NetBSD__)
12 #include <sys/param.h>
13 #if (NetBSD < 199712)
14 #include <nlist.h>
15 #include <link.h>
16 #define dlerror() "error in dynamic linking"
17 #endif
18 #endif /* NetBSD */
19
20 #ifdef HAVE_DLFCN_H
21 #include <dlfcn.h>
22 #endif
23
24 #if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(__ELF__)
25 #define LEAD_UNDERSCORE "_"
26 #else
27 #define LEAD_UNDERSCORE ""
28 #endif
29
30 /* The .so extension module ABI tag, supplied by the Makefile via
31 Makefile.pre.in and configure. This is used to discriminate between
32 incompatible .so files so that extensions for different Python builds can
33 live in the same directory. E.g. foomodule.cpython-32.so
34 */
35
36 const char *_PyImport_DynLoadFiletab[] = {
37 #ifdef __CYGWIN__
38 ".dll",
39 #else /* !__CYGWIN__ */
40 "." SOABI ".so",
41 #ifdef ALT_SOABI
42 "." ALT_SOABI ".so",
43 #endif
44 ".abi" PYTHON_ABI_STRING ".so",
45 ".so",
46 #endif /* __CYGWIN__ */
47 NULL,
48 };
49
50 static struct {
51 dev_t dev;
52 ino_t ino;
53 void *handle;
54 } handles[128];
55 static int nhandles = 0;
56
57
58 dl_funcptr
_PyImport_FindSharedFuncptr(const char * prefix,const char * shortname,const char * pathname,FILE * fp)59 _PyImport_FindSharedFuncptr(const char *prefix,
60 const char *shortname,
61 const char *pathname, FILE *fp)
62 {
63 dl_funcptr p;
64 void *handle;
65 char funcname[258];
66 char pathbuf[260];
67 int dlopenflags=0;
68
69 if (strchr(pathname, '/') == NULL) {
70 /* Prefix bare filename with "./" */
71 PyOS_snprintf(pathbuf, sizeof(pathbuf), "./%-.255s", pathname);
72 pathname = pathbuf;
73 }
74
75 PyOS_snprintf(funcname, sizeof(funcname),
76 LEAD_UNDERSCORE "%.20s_%.200s", prefix, shortname);
77
78 if (fp != NULL) {
79 int i;
80 struct _Py_stat_struct status;
81 if (_Py_fstat(fileno(fp), &status) == -1)
82 return NULL;
83 for (i = 0; i < nhandles; i++) {
84 if (status.st_dev == handles[i].dev &&
85 status.st_ino == handles[i].ino) {
86 p = (dl_funcptr) dlsym(handles[i].handle,
87 funcname);
88 return p;
89 }
90 }
91 if (nhandles < 128) {
92 handles[nhandles].dev = status.st_dev;
93 handles[nhandles].ino = status.st_ino;
94 }
95 }
96
97 dlopenflags = _PyInterpreterState_Get()->dlopenflags;
98
99 handle = dlopen(pathname, dlopenflags);
100
101 if (handle == NULL) {
102 PyObject *mod_name;
103 PyObject *path;
104 PyObject *error_ob;
105 const char *error = dlerror();
106 if (error == NULL)
107 error = "unknown dlopen() error";
108 error_ob = PyUnicode_DecodeLocale(error, "surrogateescape");
109 if (error_ob == NULL)
110 return NULL;
111 mod_name = PyUnicode_FromString(shortname);
112 if (mod_name == NULL) {
113 Py_DECREF(error_ob);
114 return NULL;
115 }
116 path = PyUnicode_DecodeFSDefault(pathname);
117 if (path == NULL) {
118 Py_DECREF(error_ob);
119 Py_DECREF(mod_name);
120 return NULL;
121 }
122 PyErr_SetImportError(error_ob, mod_name, path);
123 Py_DECREF(error_ob);
124 Py_DECREF(mod_name);
125 Py_DECREF(path);
126 return NULL;
127 }
128 if (fp != NULL && nhandles < 128)
129 handles[nhandles++].handle = handle;
130 p = (dl_funcptr) dlsym(handle, funcname);
131 return p;
132 }
133