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