1
2 /* Support for dynamic loading of extension modules */
3
4 #include "Python.h"
5
6 #ifdef HAVE_DIRECT_H
7 #include <direct.h>
8 #endif
9 #include <ctype.h>
10
11 #include "importdl.h"
12 #include "patchlevel.h"
13 #include <windows.h>
14
15 // "activation context" magic - see dl_nt.c...
16 #if HAVE_SXS
17 extern ULONG_PTR _Py_ActivateActCtx();
18 void _Py_DeactivateActCtx(ULONG_PTR cookie);
19 #endif
20
21 #ifdef _DEBUG
22 #define PYD_DEBUG_SUFFIX "_d"
23 #else
24 #define PYD_DEBUG_SUFFIX ""
25 #endif
26
27 #ifdef PYD_PLATFORM_TAG
28 #define PYD_TAGGED_SUFFIX PYD_DEBUG_SUFFIX ".cp" Py_STRINGIFY(PY_MAJOR_VERSION) Py_STRINGIFY(PY_MINOR_VERSION) "-" PYD_PLATFORM_TAG ".pyd"
29 #else
30 #define PYD_TAGGED_SUFFIX PYD_DEBUG_SUFFIX ".cp" Py_STRINGIFY(PY_MAJOR_VERSION) Py_STRINGIFY(PY_MINOR_VERSION) ".pyd"
31 #endif
32
33 #define PYD_UNTAGGED_SUFFIX PYD_DEBUG_SUFFIX ".pyd"
34
35 const char *_PyImport_DynLoadFiletab[] = {
36 PYD_TAGGED_SUFFIX,
37 PYD_UNTAGGED_SUFFIX,
38 NULL
39 };
40
41 /* Case insensitive string compare, to avoid any dependencies on particular
42 C RTL implementations */
43
strcasecmp(const char * string1,const char * string2)44 static int strcasecmp (const char *string1, const char *string2)
45 {
46 int first, second;
47
48 do {
49 first = tolower(*string1);
50 second = tolower(*string2);
51 string1++;
52 string2++;
53 } while (first && first == second);
54
55 return (first - second);
56 }
57
58
59 /* Function to return the name of the "python" DLL that the supplied module
60 directly imports. Looks through the list of imported modules and
61 returns the first entry that starts with "python" (case sensitive) and
62 is followed by nothing but numbers until the separator (period).
63
64 Returns a pointer to the import name, or NULL if no matching name was
65 located.
66
67 This function parses through the PE header for the module as loaded in
68 memory by the system loader. The PE header is accessed as documented by
69 Microsoft in the MSDN PE and COFF specification (2/99), and handles
70 both PE32 and PE32+. It only worries about the direct import table and
71 not the delay load import table since it's unlikely an extension is
72 going to be delay loading Python (after all, it's already loaded).
73
74 If any magic values are not found (e.g., the PE header or optional
75 header magic), then this function simply returns NULL. */
76
77 #define DWORD_AT(mem) (*(DWORD *)(mem))
78 #define WORD_AT(mem) (*(WORD *)(mem))
79
GetPythonImport(HINSTANCE hModule)80 static char *GetPythonImport (HINSTANCE hModule)
81 {
82 unsigned char *dllbase, *import_data, *import_name;
83 DWORD pe_offset, opt_offset;
84 WORD opt_magic;
85 int num_dict_off, import_off;
86
87 /* Safety check input */
88 if (hModule == NULL) {
89 return NULL;
90 }
91
92 /* Module instance is also the base load address. First portion of
93 memory is the MS-DOS loader, which holds the offset to the PE
94 header (from the load base) at 0x3C */
95 dllbase = (unsigned char *)hModule;
96 pe_offset = DWORD_AT(dllbase + 0x3C);
97
98 /* The PE signature must be "PE\0\0" */
99 if (memcmp(dllbase+pe_offset,"PE\0\0",4)) {
100 return NULL;
101 }
102
103 /* Following the PE signature is the standard COFF header (20
104 bytes) and then the optional header. The optional header starts
105 with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+
106 uses 64-bits for some fields). It might also be 0x107 for a ROM
107 image, but we don't process that here.
108
109 The optional header ends with a data dictionary that directly
110 points to certain types of data, among them the import entries
111 (in the second table entry). Based on the header type, we
112 determine offsets for the data dictionary count and the entry
113 within the dictionary pointing to the imports. */
114
115 opt_offset = pe_offset + 4 + 20;
116 opt_magic = WORD_AT(dllbase+opt_offset);
117 if (opt_magic == 0x10B) {
118 /* PE32 */
119 num_dict_off = 92;
120 import_off = 104;
121 } else if (opt_magic == 0x20B) {
122 /* PE32+ */
123 num_dict_off = 108;
124 import_off = 120;
125 } else {
126 /* Unsupported */
127 return NULL;
128 }
129
130 /* Now if an import table exists, offset to it and walk the list of
131 imports. The import table is an array (ending when an entry has
132 empty values) of structures (20 bytes each), which contains (at
133 offset 12) a relative address (to the module base) at which a
134 string constant holding the import name is located. */
135
136 if (DWORD_AT(dllbase + opt_offset + num_dict_off) >= 2) {
137 /* We have at least 2 tables - the import table is the second
138 one. But still it may be that the table size is zero */
139 if (0 == DWORD_AT(dllbase + opt_offset + import_off + sizeof(DWORD)))
140 return NULL;
141 import_data = dllbase + DWORD_AT(dllbase +
142 opt_offset +
143 import_off);
144 while (DWORD_AT(import_data)) {
145 import_name = dllbase + DWORD_AT(import_data+12);
146 if (strlen(import_name) >= 6 &&
147 !strncmp(import_name,"python",6)) {
148 char *pch;
149
150 #ifndef _DEBUG
151 /* In a release version, don't claim that python3.dll is
152 a Python DLL. */
153 if (strcmp(import_name, "python3.dll") == 0) {
154 import_data += 20;
155 continue;
156 }
157 #endif
158
159 /* Ensure python prefix is followed only
160 by numbers to the end of the basename */
161 pch = import_name + 6;
162 #ifdef _DEBUG
163 while (*pch && pch[0] != '_' && pch[1] != 'd' && pch[2] != '.') {
164 #else
165 while (*pch && *pch != '.') {
166 #endif
167 if (*pch >= '0' && *pch <= '9') {
168 pch++;
169 } else {
170 pch = NULL;
171 break;
172 }
173 }
174
175 if (pch) {
176 /* Found it - return the name */
177 return import_name;
178 }
179 }
180 import_data += 20;
181 }
182 }
183
184 return NULL;
185 }
186
187 dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
188 const char *shortname,
189 PyObject *pathname, FILE *fp)
190 {
191 dl_funcptr p;
192 char funcname[258], *import_python;
193 const wchar_t *wpathname;
194
195 _Py_CheckPython3();
196
197 wpathname = _PyUnicode_AsUnicode(pathname);
198 if (wpathname == NULL)
199 return NULL;
200
201 PyOS_snprintf(funcname, sizeof(funcname), "%.20s_%.200s", prefix, shortname);
202
203 {
204 HINSTANCE hDLL = NULL;
205 unsigned int old_mode;
206 #if HAVE_SXS
207 ULONG_PTR cookie = 0;
208 #endif
209
210 /* Don't display a message box when Python can't load a DLL */
211 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
212
213 #if HAVE_SXS
214 cookie = _Py_ActivateActCtx();
215 #endif
216 /* We use LoadLibraryEx so Windows looks for dependent DLLs
217 in directory of pathname first. */
218 /* XXX This call doesn't exist in Windows CE */
219 hDLL = LoadLibraryExW(wpathname, NULL,
220 LOAD_WITH_ALTERED_SEARCH_PATH);
221 #if HAVE_SXS
222 _Py_DeactivateActCtx(cookie);
223 #endif
224
225 /* restore old error mode settings */
226 SetErrorMode(old_mode);
227
228 if (hDLL==NULL){
229 PyObject *message;
230 unsigned int errorCode;
231
232 /* Get an error string from Win32 error code */
233 wchar_t theInfo[256]; /* Pointer to error text
234 from system */
235 int theLength; /* Length of error text */
236
237 errorCode = GetLastError();
238
239 theLength = FormatMessageW(
240 FORMAT_MESSAGE_FROM_SYSTEM |
241 FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */
242 NULL, /* message source */
243 errorCode, /* the message (error) ID */
244 MAKELANGID(LANG_NEUTRAL,
245 SUBLANG_DEFAULT),
246 /* Default language */
247 theInfo, /* the buffer */
248 sizeof(theInfo) / sizeof(wchar_t), /* size in wchars */
249 NULL); /* no additional format args. */
250
251 /* Problem: could not get the error message.
252 This should not happen if called correctly. */
253 if (theLength == 0) {
254 message = PyUnicode_FromFormat(
255 "DLL load failed with error code %u",
256 errorCode);
257 } else {
258 /* For some reason a \r\n
259 is appended to the text */
260 if (theLength >= 2 &&
261 theInfo[theLength-2] == '\r' &&
262 theInfo[theLength-1] == '\n') {
263 theLength -= 2;
264 theInfo[theLength] = '\0';
265 }
266 message = PyUnicode_FromString(
267 "DLL load failed: ");
268
269 PyUnicode_AppendAndDel(&message,
270 PyUnicode_FromWideChar(
271 theInfo,
272 theLength));
273 }
274 if (message != NULL) {
275 PyObject *shortname_obj = PyUnicode_FromString(shortname);
276 PyErr_SetImportError(message, shortname_obj, pathname);
277 Py_XDECREF(shortname_obj);
278 Py_DECREF(message);
279 }
280 return NULL;
281 } else {
282 char buffer[256];
283
284 PyOS_snprintf(buffer, sizeof(buffer),
285 #ifdef _DEBUG
286 "python%d%d_d.dll",
287 #else
288 "python%d%d.dll",
289 #endif
290 PY_MAJOR_VERSION,PY_MINOR_VERSION);
291 import_python = GetPythonImport(hDLL);
292
293 if (import_python &&
294 strcasecmp(buffer,import_python)) {
295 PyErr_Format(PyExc_ImportError,
296 "Module use of %.150s conflicts "
297 "with this version of Python.",
298 import_python);
299 FreeLibrary(hDLL);
300 return NULL;
301 }
302 }
303 p = GetProcAddress(hDLL, funcname);
304 }
305
306 return p;
307 }
308