summaryrefslogtreecommitdiffstats
path: root/src/os_win32.c
diff options
context:
space:
mode:
authorKen Takata <kentkt@csc.jp>2023-10-04 20:05:05 +0200
committerChristian Brabandt <cb@256bit.org>2023-10-04 20:05:05 +0200
commit119fdd9293f63614ed2ca60a78993466435db639 (patch)
tree0de7811d4f2982b04385c8d7cacf83134604c353 /src/os_win32.c
parent317468aaceb48e136ed7e3fa6d233345fd5360c6 (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.c70
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"