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 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 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 wchar_t *wpathname; 194 195 #ifndef _DEBUG 196 _Py_CheckPython3(); 197 #endif 198 199 wpathname = PyUnicode_AsUnicode(pathname); 200 if (wpathname == NULL) 201 return NULL; 202 203 PyOS_snprintf(funcname, sizeof(funcname), "%.20s_%.200s", prefix, shortname); 204 205 { 206 HINSTANCE hDLL = NULL; 207 unsigned int old_mode; 208 #if HAVE_SXS 209 ULONG_PTR cookie = 0; 210 #endif 211 212 /* Don't display a message box when Python can't load a DLL */ 213 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS); 214 215 #if HAVE_SXS 216 cookie = _Py_ActivateActCtx(); 217 #endif 218 /* We use LoadLibraryEx so Windows looks for dependent DLLs 219 in directory of pathname first. */ 220 /* XXX This call doesn't exist in Windows CE */ 221 hDLL = LoadLibraryExW(wpathname, NULL, 222 LOAD_WITH_ALTERED_SEARCH_PATH); 223 #if HAVE_SXS 224 _Py_DeactivateActCtx(cookie); 225 #endif 226 227 /* restore old error mode settings */ 228 SetErrorMode(old_mode); 229 230 if (hDLL==NULL){ 231 PyObject *message; 232 unsigned int errorCode; 233 234 /* Get an error string from Win32 error code */ 235 wchar_t theInfo[256]; /* Pointer to error text 236 from system */ 237 int theLength; /* Length of error text */ 238 239 errorCode = GetLastError(); 240 241 theLength = FormatMessageW( 242 FORMAT_MESSAGE_FROM_SYSTEM | 243 FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */ 244 NULL, /* message source */ 245 errorCode, /* the message (error) ID */ 246 MAKELANGID(LANG_NEUTRAL, 247 SUBLANG_DEFAULT), 248 /* Default language */ 249 theInfo, /* the buffer */ 250 sizeof(theInfo) / sizeof(wchar_t), /* size in wchars */ 251 NULL); /* no additional format args. */ 252 253 /* Problem: could not get the error message. 254 This should not happen if called correctly. */ 255 if (theLength == 0) { 256 message = PyUnicode_FromFormat( 257 "DLL load failed with error code %d", 258 errorCode); 259 } else { 260 /* For some reason a \r\n 261 is appended to the text */ 262 if (theLength >= 2 && 263 theInfo[theLength-2] == '\r' && 264 theInfo[theLength-1] == '\n') { 265 theLength -= 2; 266 theInfo[theLength] = '\0'; 267 } 268 message = PyUnicode_FromString( 269 "DLL load failed: "); 270 271 PyUnicode_AppendAndDel(&message, 272 PyUnicode_FromWideChar( 273 theInfo, 274 theLength)); 275 } 276 if (message != NULL) { 277 PyObject *shortname_obj = PyUnicode_FromString(shortname); 278 PyErr_SetImportError(message, shortname_obj, pathname); 279 Py_XDECREF(shortname_obj); 280 Py_DECREF(message); 281 } 282 return NULL; 283 } else { 284 char buffer[256]; 285 286 PyOS_snprintf(buffer, sizeof(buffer), 287 #ifdef _DEBUG 288 "python%d%d_d.dll", 289 #else 290 "python%d%d.dll", 291 #endif 292 PY_MAJOR_VERSION,PY_MINOR_VERSION); 293 import_python = GetPythonImport(hDLL); 294 295 if (import_python && 296 strcasecmp(buffer,import_python)) { 297 PyErr_Format(PyExc_ImportError, 298 "Module use of %.150s conflicts " 299 "with this version of Python.", 300 import_python); 301 FreeLibrary(hDLL); 302 return NULL; 303 } 304 } 305 p = GetProcAddress(hDLL, funcname); 306 } 307 308 return p; 309 } 310