3
3
4
4
#include <windows.h>
5
5
#include <direct.h>
6
+ #include <ctype.h>
6
7
7
8
#include "Python.h"
8
9
#include "importdl.h"
@@ -19,11 +20,144 @@ const struct filedescr _PyImport_DynLoadFiletab[] = {
19
20
};
20
21
21
22
23
+ #ifdef MS_WIN32
24
+
25
+ /* Case insensitive string compare, to avoid any dependencies on particular
26
+ C RTL implementations */
27
+
28
+ static int strcasecmp (char * string1 , char * string2 )
29
+ {
30
+ int first , second ;
31
+
32
+ do {
33
+ first = tolower (* string1 );
34
+ second = tolower (* string2 );
35
+ string1 ++ ;
36
+ string2 ++ ;
37
+ } while (first && first == second );
38
+
39
+ return (first - second );
40
+ }
41
+
42
+
43
+ /* Function to return the name of the "python" DLL that the supplied module
44
+ directly imports. Looks through the list of imported modules and
45
+ returns the first entry that starts with "python" (case sensitive) and
46
+ is followed by nothing but numbers until the separator (period).
47
+
48
+ Returns a pointer to the import name, or NULL if no matching name was
49
+ located.
50
+
51
+ This function parses through the PE header for the module as loaded in
52
+ memory by the system loader. The PE header is accessed as documented by
53
+ Microsoft in the MSDN PE and COFF specification (2/99), and handles
54
+ both PE32 and PE32+. It only worries about the direct import table and
55
+ not the delay load import table since it's unlikely an extension is
56
+ going to be delay loading Python (after all, it's already loaded).
57
+
58
+ If any magic values are not found (e.g., the PE header or optional
59
+ header magic), then this function simply returns NULL. */
60
+
61
+ #define DWORD_AT (mem ) (*(DWORD *)(mem))
62
+ #define WORD_AT (mem ) (*(WORD *)(mem))
63
+
64
+ static char * GetPythonImport (HINSTANCE hModule )
65
+ {
66
+ unsigned char * dllbase , * import_data , * import_name ;
67
+ DWORD pe_offset , opt_offset ;
68
+ WORD opt_magic ;
69
+ int num_dict_off , import_off ;
70
+
71
+ /* Safety check input */
72
+ if (hModule == NULL ) {
73
+ return NULL ;
74
+ }
75
+
76
+ /* Module instance is also the base load address. First portion of
77
+ memory is the MS-DOS loader, which holds the offset to the PE
78
+ header (from the load base) at 0x3C */
79
+ dllbase = (unsigned char * )hModule ;
80
+ pe_offset = DWORD_AT (dllbase + 0x3C );
81
+
82
+ /* The PE signature must be "PE\0\0" */
83
+ if (memcmp (dllbase + pe_offset ,"PE\0\0" ,4 )) {
84
+ return NULL ;
85
+ }
86
+
87
+ /* Following the PE signature is the standard COFF header (20
88
+ bytes) and then the optional header. The optional header starts
89
+ with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+
90
+ uses 64-bits for some fields). It might also be 0x107 for a ROM
91
+ image, but we don't process that here.
92
+
93
+ The optional header ends with a data dictionary that directly
94
+ points to certain types of data, among them the import entries
95
+ (in the second table entry). Based on the header type, we
96
+ determine offsets for the data dictionary count and the entry
97
+ within the dictionary pointing to the imports. */
98
+
99
+ opt_offset = pe_offset + 4 + 20 ;
100
+ opt_magic = WORD_AT (dllbase + opt_offset );
101
+ if (opt_magic == 0x10B ) {
102
+ /* PE32 */
103
+ num_dict_off = 92 ;
104
+ import_off = 104 ;
105
+ } else if (opt_magic == 0x20B ) {
106
+ /* PE32+ */
107
+ num_dict_off = 108 ;
108
+ import_off = 120 ;
109
+ } else {
110
+ /* Unsupported */
111
+ return NULL ;
112
+ }
113
+
114
+ /* Now if an import table exists, offset to it and walk the list of
115
+ imports. The import table is an array (ending when an entry has
116
+ empty values) of structures (20 bytes each), which contains (at
117
+ offset 12) a relative address (to the module base) at which a
118
+ string constant holding the import name is located. */
119
+
120
+ if (DWORD_AT (dllbase + opt_offset + num_dict_off ) >= 2 ) {
121
+ import_data = dllbase + DWORD_AT (dllbase +
122
+ opt_offset +
123
+ import_off );
124
+ while (DWORD_AT (import_data )) {
125
+ import_name = dllbase + DWORD_AT (import_data + 12 );
126
+ if (strlen (import_name ) >= 6 &&
127
+ !strncmp (import_name ,"python" ,6 )) {
128
+ char * pch ;
129
+
130
+ /* Ensure python prefix is followed only
131
+ by numbers to the end of the basename */
132
+ pch = import_name + 6 ;
133
+ while (* pch && * pch != '.' ) {
134
+ if (* pch >= '0' && * pch <= '9' ) {
135
+ pch ++ ;
136
+ } else {
137
+ pch = NULL ;
138
+ break ;
139
+ }
140
+ }
141
+
142
+ if (pch ) {
143
+ /* Found it - return the name */
144
+ return import_name ;
145
+ }
146
+ }
147
+ import_data += 20 ;
148
+ }
149
+ }
150
+
151
+ return NULL ;
152
+ }
153
+ #endif /* MS_WIN32 */
154
+
155
+
22
156
dl_funcptr _PyImport_GetDynLoadFunc (const char * fqname , const char * shortname ,
23
157
const char * pathname , FILE * fp )
24
158
{
25
159
dl_funcptr p ;
26
- char funcname [258 ];
160
+ char funcname [258 ], * import_python ;
27
161
28
162
sprintf (funcname , "init%.200s" , shortname );
29
163
@@ -91,6 +225,23 @@ dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname,
91
225
}
92
226
PyErr_SetString (PyExc_ImportError , errBuf );
93
227
return NULL ;
228
+ } else {
229
+ char buffer [256 ];
230
+
231
+ sprintf (buffer ,"python%d%d.dll" ,
232
+ PY_MAJOR_VERSION ,PY_MINOR_VERSION );
233
+ import_python = GetPythonImport (hDLL );
234
+
235
+ if (import_python &&
236
+ strcasecmp (buffer ,import_python )) {
237
+ sprintf (buffer ,
238
+ "Module use of %s conflicts "
239
+ "with this version of Python." ,
240
+ import_python );
241
+ PyErr_SetString (PyExc_ImportError ,buffer );
242
+ FreeLibrary (hDLL );
243
+ return NULL ;
244
+ }
94
245
}
95
246
p = GetProcAddress (hDLL , funcname );
96
247
}
0 commit comments