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