diff options
author | Ken Takata <kentkt@csc.jp> | 2023-10-04 20:05:05 +0200 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2023-10-04 20:05:05 +0200 |
commit | 119fdd9293f63614ed2ca60a78993466435db639 (patch) | |
tree | 0de7811d4f2982b04385c8d7cacf83134604c353 /src/os_win32.c | |
parent | 317468aaceb48e136ed7e3fa6d233345fd5360c6 (diff) |
patch 9.0.1980: win32: issues with stable python ABIv9.0.1980
Problem: win32: issues with stable python ABI
Solution: if_python3,win32: Fix Python3 stable ABI
There were some issues in current stable ABI implementation on Windows:
* Python DLL name should be `python3.dll` instead of `python311.dll` and
so on. (See: https://docs.python.org/3/c-api/stable.html)
* Some non-stable API functions were used:
- `_PyObject_NextNotImplemented`
- `PyStdPrinter_Type`
* `reset_stdin()` and `hook_py_exit()` didn't work with `python3.dll`.
`python3.dll` is a special type of DLL called forwarder DLL.
It just forwards the functions to other DLL (e.g. `python311.dll`).
There were two issues regarding these functions:
- `python3.dll` doesn't have import tables. This caused a crash in
`get_imported_func_info()`. Add a check whether the specified DLL
has an import table.
- `reset_stdin()` and `hook_py_exit()` should be applied to the
forwarded DLL (e.g. `python311.dll`), not to `python3.dll`.
Check the export directory of `python3.dll` to find the forwarded
DLL and apply the functions to it.
closes: #13260
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Ken Takata <kentkt@csc.jp>
Diffstat (limited to 'src/os_win32.c')
-rw-r--r-- | src/os_win32.c | 70 |
1 files changed, 67 insertions, 3 deletions
diff --git a/src/os_win32.c b/src/os_win32.c index 7891944dab..92bc8c157f 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -626,15 +626,20 @@ get_imported_func_info(HINSTANCE hInst, const char *funcname, int info, PIMAGE_THUNK_DATA pIAT; // Import Address Table PIMAGE_THUNK_DATA pINT; // Import Name Table PIMAGE_IMPORT_BY_NAME pImpName; + DWORD ImpVA; if (pDOS->e_magic != IMAGE_DOS_SIGNATURE) return NULL; pPE = (PIMAGE_NT_HEADERS)(pImage + pDOS->e_lfanew); if (pPE->Signature != IMAGE_NT_SIGNATURE) return NULL; - pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage - + pPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] - .VirtualAddress); + + ImpVA = pPE->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + if (ImpVA == 0) + return NULL; // No Import Table + pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage + ImpVA); + for (; pImpDesc->FirstThunk; ++pImpDesc) { if (!pImpDesc->OriginalFirstThunk) @@ -709,6 +714,65 @@ hook_dll_import_func(HINSTANCE hInst, const char *funcname, const void *hook) } #endif +#if defined(FEAT_PYTHON3) || defined(PROTO) +/* + * Check if the specified DLL is a function forwarder. + * If yes, return the instance of the forwarded DLL. + * If no, return the specified DLL. + * If error, return NULL. + * This assumes that the DLL forwards all the function to a single DLL. + */ + HINSTANCE +get_forwarded_dll(HINSTANCE hInst) +{ + PBYTE pImage = (PBYTE)hInst; + PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)hInst; + PIMAGE_NT_HEADERS pPE; + PIMAGE_EXPORT_DIRECTORY pExpDir; + DWORD ExpVA; + DWORD ExpSize; + LPDWORD pFunctionTable; + + if (pDOS->e_magic != IMAGE_DOS_SIGNATURE) + return NULL; + pPE = (PIMAGE_NT_HEADERS)(pImage + pDOS->e_lfanew); + if (pPE->Signature != IMAGE_NT_SIGNATURE) + return NULL; + + ExpVA = pPE->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + ExpSize = pPE->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + if (ExpVA == 0) + return hInst; // No Export Directory + pExpDir = (PIMAGE_EXPORT_DIRECTORY)(pImage + ExpVA); + pFunctionTable = (LPDWORD)(pImage + pExpDir->AddressOfFunctions); + + if (pExpDir->NumberOfNames == 0) + return hInst; // No export names. + + // Check only the first entry. + if ((pFunctionTable[0] < ExpVA) || (pFunctionTable[0] >= ExpVA + ExpSize)) + // The first entry is not a function forwarder. + return hInst; + + // The first entry is a function forwarder. + // The name is represented as "DllName.FunctionName". + const char *name = (const char *)(pImage + pFunctionTable[0]); + const char *p = strchr(name, '.'); + if (p == NULL) + return hInst; + + // Extract DllName. + char buf[MAX_PATH]; + if (p - name + 1 > sizeof(buf)) + return NULL; + strncpy(buf, name, p - name); + buf[p - name] = '\0'; + return GetModuleHandleA(buf); +} +#endif + #if defined(DYNAMIC_GETTEXT) || defined(PROTO) # ifndef GETTEXT_DLL # define GETTEXT_DLL "libintl.dll" |