forked from aniani/vim
patch 9.0.1980: win32: issues with stable python ABI
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>
This commit is contained in:
committed by
Christian Brabandt
parent
317468aace
commit
119fdd9293
@@ -394,16 +394,21 @@ DYNAMIC_PYTHON3=yes
|
|||||||
|
|
||||||
ifndef PYTHON3_VER
|
ifndef PYTHON3_VER
|
||||||
PYTHON3_VER=36
|
PYTHON3_VER=36
|
||||||
|
endif
|
||||||
|
ifeq ($(DYNAMIC_PYTHON3_STABLE_ABI),yes)
|
||||||
|
PYTHON3_NAME=python3
|
||||||
|
else
|
||||||
|
PYTHON3_NAME=python$(PYTHON3_VER)
|
||||||
endif
|
endif
|
||||||
ifndef DYNAMIC_PYTHON3_DLL
|
ifndef DYNAMIC_PYTHON3_DLL
|
||||||
DYNAMIC_PYTHON3_DLL=python$(PYTHON3_VER).dll
|
DYNAMIC_PYTHON3_DLL=$(PYTHON3_NAME).dll
|
||||||
endif
|
endif
|
||||||
ifdef PYTHON3_HOME
|
ifdef PYTHON3_HOME
|
||||||
PYTHON3_HOME_DEF=-DPYTHON3_HOME=L\"$(PYTHON3_HOME)\"
|
PYTHON3_HOME_DEF=-DPYTHON3_HOME=L\"$(PYTHON3_HOME)\"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq (no,$(DYNAMIC_PYTHON3))
|
ifeq (no,$(DYNAMIC_PYTHON3))
|
||||||
PYTHON3LIB=-L$(PYTHON3)/libs -lpython$(PYTHON3_VER)
|
PYTHON3LIB=-L$(PYTHON3)/libs -l$(PYTHON3_NAME)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef PYTHON3INC
|
ifndef PYTHON3INC
|
||||||
|
@@ -937,8 +937,13 @@ PYTHON_LIB = "$(PYTHON)\libs\python$(PYTHON_VER).lib"
|
|||||||
! ifndef PYTHON3_VER
|
! ifndef PYTHON3_VER
|
||||||
PYTHON3_VER = 36
|
PYTHON3_VER = 36
|
||||||
! endif
|
! endif
|
||||||
|
! if "$(DYNAMIC_PYTHON3_STABLE_ABI)" == "yes"
|
||||||
|
PYTHON3_NAME = python3
|
||||||
|
! else
|
||||||
|
PYTHON3_NAME = python$(PYTHON3_VER)
|
||||||
|
! endif
|
||||||
! ifndef DYNAMIC_PYTHON3_DLL
|
! ifndef DYNAMIC_PYTHON3_DLL
|
||||||
DYNAMIC_PYTHON3_DLL = python$(PYTHON3_VER).dll
|
DYNAMIC_PYTHON3_DLL = $(PYTHON3_NAME).dll
|
||||||
! endif
|
! endif
|
||||||
! message Python3 requested (version $(PYTHON3_VER)) - root dir is "$(PYTHON3)"
|
! message Python3 requested (version $(PYTHON3_VER)) - root dir is "$(PYTHON3)"
|
||||||
! if "$(DYNAMIC_PYTHON3)" == "yes"
|
! if "$(DYNAMIC_PYTHON3)" == "yes"
|
||||||
@@ -953,13 +958,11 @@ CFLAGS = $(CFLAGS) -DDYNAMIC_PYTHON3 \
|
|||||||
! if "$(DYNAMIC_PYTHON3_STABLE_ABI)" == "yes"
|
! if "$(DYNAMIC_PYTHON3_STABLE_ABI)" == "yes"
|
||||||
CFLAGS = $(CFLAGS) -DDYNAMIC_PYTHON3_STABLE_ABI
|
CFLAGS = $(CFLAGS) -DDYNAMIC_PYTHON3_STABLE_ABI
|
||||||
PYTHON3_INC = $(PYTHON3_INC) -DPy_LIMITED_API=0x3080000
|
PYTHON3_INC = $(PYTHON3_INC) -DPy_LIMITED_API=0x3080000
|
||||||
PYTHON3_LIB = /nodefaultlib:python3.lib
|
|
||||||
! else
|
|
||||||
PYTHON3_LIB = /nodefaultlib:python$(PYTHON3_VER).lib
|
|
||||||
! endif
|
! endif
|
||||||
|
PYTHON3_LIB = /nodefaultlib:$(PYTHON3_NAME).lib
|
||||||
! else
|
! else
|
||||||
CFLAGS = $(CFLAGS) -DPYTHON3_DLL=\"$(DYNAMIC_PYTHON3_DLL)\"
|
CFLAGS = $(CFLAGS) -DPYTHON3_DLL=\"$(DYNAMIC_PYTHON3_DLL)\"
|
||||||
PYTHON3_LIB = "$(PYTHON3)\libs\python$(PYTHON3_VER).lib"
|
PYTHON3_LIB = "$(PYTHON3)\libs\$(PYTHON3_NAME).lib"
|
||||||
! endif
|
! endif
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
|
@@ -242,7 +242,7 @@ static HINSTANCE hinstPy3 = 0; // Instance of python.dll
|
|||||||
# if PY_VERSION_HEX >= 0x03040000
|
# if PY_VERSION_HEX >= 0x03040000
|
||||||
# define PyType_GetFlags py3_PyType_GetFlags
|
# define PyType_GetFlags py3_PyType_GetFlags
|
||||||
# endif
|
# endif
|
||||||
#undef Py_BuildValue
|
# undef Py_BuildValue
|
||||||
# define Py_BuildValue py3_Py_BuildValue
|
# define Py_BuildValue py3_Py_BuildValue
|
||||||
# define Py_SetPythonHome py3_Py_SetPythonHome
|
# define Py_SetPythonHome py3_Py_SetPythonHome
|
||||||
# define Py_Initialize py3_Py_Initialize
|
# define Py_Initialize py3_Py_Initialize
|
||||||
@@ -251,7 +251,9 @@ static HINSTANCE hinstPy3 = 0; // Instance of python.dll
|
|||||||
# define _Py_NoneStruct (*py3__Py_NoneStruct)
|
# define _Py_NoneStruct (*py3__Py_NoneStruct)
|
||||||
# define _Py_FalseStruct (*py3__Py_FalseStruct)
|
# define _Py_FalseStruct (*py3__Py_FalseStruct)
|
||||||
# define _Py_TrueStruct (*py3__Py_TrueStruct)
|
# define _Py_TrueStruct (*py3__Py_TrueStruct)
|
||||||
|
# ifndef USE_LIMITED_API
|
||||||
# define _PyObject_NextNotImplemented (*py3__PyObject_NextNotImplemented)
|
# define _PyObject_NextNotImplemented (*py3__PyObject_NextNotImplemented)
|
||||||
|
# endif
|
||||||
# define PyModule_AddObject py3_PyModule_AddObject
|
# define PyModule_AddObject py3_PyModule_AddObject
|
||||||
# define PyImport_AppendInittab py3_PyImport_AppendInittab
|
# define PyImport_AppendInittab py3_PyImport_AppendInittab
|
||||||
# define PyImport_AddModule py3_PyImport_AddModule
|
# define PyImport_AddModule py3_PyImport_AddModule
|
||||||
@@ -288,7 +290,9 @@ static HINSTANCE hinstPy3 = 0; // Instance of python.dll
|
|||||||
# define PyFloat_AsDouble py3_PyFloat_AsDouble
|
# define PyFloat_AsDouble py3_PyFloat_AsDouble
|
||||||
# define PyObject_GenericGetAttr py3_PyObject_GenericGetAttr
|
# define PyObject_GenericGetAttr py3_PyObject_GenericGetAttr
|
||||||
# define PyType_Type (*py3_PyType_Type)
|
# define PyType_Type (*py3_PyType_Type)
|
||||||
|
# ifndef USE_LIMITED_API
|
||||||
# define PyStdPrinter_Type (*py3_PyStdPrinter_Type)
|
# define PyStdPrinter_Type (*py3_PyStdPrinter_Type)
|
||||||
|
# endif
|
||||||
# define PySlice_Type (*py3_PySlice_Type)
|
# define PySlice_Type (*py3_PySlice_Type)
|
||||||
# define PyFloat_Type (*py3_PyFloat_Type)
|
# define PyFloat_Type (*py3_PyFloat_Type)
|
||||||
# define PyNumber_Check (*py3_PyNumber_Check)
|
# define PyNumber_Check (*py3_PyNumber_Check)
|
||||||
@@ -449,7 +453,9 @@ static void (*py3_PyErr_Clear)(void);
|
|||||||
static PyObject* (*py3_PyErr_Format)(PyObject *, const char *, ...);
|
static PyObject* (*py3_PyErr_Format)(PyObject *, const char *, ...);
|
||||||
static void (*py3_PyErr_PrintEx)(int);
|
static void (*py3_PyErr_PrintEx)(int);
|
||||||
static PyObject*(*py3__PyObject_Init)(PyObject *, PyTypeObject *);
|
static PyObject*(*py3__PyObject_Init)(PyObject *, PyTypeObject *);
|
||||||
|
# ifndef USE_LIMITED_API
|
||||||
static iternextfunc py3__PyObject_NextNotImplemented;
|
static iternextfunc py3__PyObject_NextNotImplemented;
|
||||||
|
# endif
|
||||||
static PyObject* py3__Py_NoneStruct;
|
static PyObject* py3__Py_NoneStruct;
|
||||||
static PyObject* py3__Py_FalseStruct;
|
static PyObject* py3__Py_FalseStruct;
|
||||||
static PyObject* py3__Py_TrueStruct;
|
static PyObject* py3__Py_TrueStruct;
|
||||||
@@ -485,7 +491,9 @@ static PyObject* (*py3_PyObject_GenericGetAttr)(PyObject *obj, PyObject *name);
|
|||||||
static PyObject* (*py3_PyType_GenericAlloc)(PyTypeObject *type, Py_ssize_t nitems);
|
static PyObject* (*py3_PyType_GenericAlloc)(PyTypeObject *type, Py_ssize_t nitems);
|
||||||
static PyObject* (*py3_PyType_GenericNew)(PyTypeObject *type, PyObject *args, PyObject *kwds);
|
static PyObject* (*py3_PyType_GenericNew)(PyTypeObject *type, PyObject *args, PyObject *kwds);
|
||||||
static PyTypeObject* py3_PyType_Type;
|
static PyTypeObject* py3_PyType_Type;
|
||||||
|
# ifndef USE_LIMITED_API
|
||||||
static PyTypeObject* py3_PyStdPrinter_Type;
|
static PyTypeObject* py3_PyStdPrinter_Type;
|
||||||
|
# endif
|
||||||
static PyTypeObject* py3_PySlice_Type;
|
static PyTypeObject* py3_PySlice_Type;
|
||||||
static PyTypeObject* py3_PyFloat_Type;
|
static PyTypeObject* py3_PyFloat_Type;
|
||||||
PyTypeObject* py3_PyBool_Type;
|
PyTypeObject* py3_PyBool_Type;
|
||||||
@@ -633,7 +641,9 @@ static struct
|
|||||||
{"PyEval_SaveThread", (PYTHON_PROC*)&py3_PyEval_SaveThread},
|
{"PyEval_SaveThread", (PYTHON_PROC*)&py3_PyEval_SaveThread},
|
||||||
{"_PyArg_Parse_SizeT", (PYTHON_PROC*)&py3_PyArg_Parse},
|
{"_PyArg_Parse_SizeT", (PYTHON_PROC*)&py3_PyArg_Parse},
|
||||||
{"Py_IsInitialized", (PYTHON_PROC*)&py3_Py_IsInitialized},
|
{"Py_IsInitialized", (PYTHON_PROC*)&py3_Py_IsInitialized},
|
||||||
|
# ifndef USE_LIMITED_API
|
||||||
{"_PyObject_NextNotImplemented", (PYTHON_PROC*)&py3__PyObject_NextNotImplemented},
|
{"_PyObject_NextNotImplemented", (PYTHON_PROC*)&py3__PyObject_NextNotImplemented},
|
||||||
|
# endif
|
||||||
{"_Py_NoneStruct", (PYTHON_PROC*)&py3__Py_NoneStruct},
|
{"_Py_NoneStruct", (PYTHON_PROC*)&py3__Py_NoneStruct},
|
||||||
{"_Py_FalseStruct", (PYTHON_PROC*)&py3__Py_FalseStruct},
|
{"_Py_FalseStruct", (PYTHON_PROC*)&py3__Py_FalseStruct},
|
||||||
{"_Py_TrueStruct", (PYTHON_PROC*)&py3__Py_TrueStruct},
|
{"_Py_TrueStruct", (PYTHON_PROC*)&py3__Py_TrueStruct},
|
||||||
@@ -681,7 +691,9 @@ static struct
|
|||||||
{"PyType_GenericAlloc", (PYTHON_PROC*)&py3_PyType_GenericAlloc},
|
{"PyType_GenericAlloc", (PYTHON_PROC*)&py3_PyType_GenericAlloc},
|
||||||
{"PyType_GenericNew", (PYTHON_PROC*)&py3_PyType_GenericNew},
|
{"PyType_GenericNew", (PYTHON_PROC*)&py3_PyType_GenericNew},
|
||||||
{"PyType_Type", (PYTHON_PROC*)&py3_PyType_Type},
|
{"PyType_Type", (PYTHON_PROC*)&py3_PyType_Type},
|
||||||
|
# ifndef USE_LIMITED_API
|
||||||
{"PyStdPrinter_Type", (PYTHON_PROC*)&py3_PyStdPrinter_Type},
|
{"PyStdPrinter_Type", (PYTHON_PROC*)&py3_PyStdPrinter_Type},
|
||||||
|
# endif
|
||||||
{"PySlice_Type", (PYTHON_PROC*)&py3_PySlice_Type},
|
{"PySlice_Type", (PYTHON_PROC*)&py3_PySlice_Type},
|
||||||
{"PyFloat_Type", (PYTHON_PROC*)&py3_PyFloat_Type},
|
{"PyFloat_Type", (PYTHON_PROC*)&py3_PyFloat_Type},
|
||||||
# if PY_VERSION_HEX < 0x030c00b0
|
# if PY_VERSION_HEX < 0x030c00b0
|
||||||
@@ -1167,7 +1179,7 @@ reset_stdin(void)
|
|||||||
{
|
{
|
||||||
FILE *(*py__acrt_iob_func)(unsigned) = NULL;
|
FILE *(*py__acrt_iob_func)(unsigned) = NULL;
|
||||||
FILE *(*pyfreopen)(const char *, const char *, FILE *) = NULL;
|
FILE *(*pyfreopen)(const char *, const char *, FILE *) = NULL;
|
||||||
HINSTANCE hinst = hinstPy3;
|
HINSTANCE hinst = get_forwarded_dll(hinstPy3);
|
||||||
|
|
||||||
if (hinst == NULL || is_stdin_readable())
|
if (hinst == NULL || is_stdin_readable())
|
||||||
return;
|
return;
|
||||||
@@ -1219,7 +1231,7 @@ hooked_exit(int ret)
|
|||||||
static void
|
static void
|
||||||
hook_py_exit(void)
|
hook_py_exit(void)
|
||||||
{
|
{
|
||||||
HINSTANCE hinst = hinstPy3;
|
HINSTANCE hinst = get_forwarded_dll(hinstPy3);
|
||||||
|
|
||||||
if (hinst == NULL || orig_exit != NULL)
|
if (hinst == NULL || orig_exit != NULL)
|
||||||
return;
|
return;
|
||||||
|
@@ -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 pIAT; // Import Address Table
|
||||||
PIMAGE_THUNK_DATA pINT; // Import Name Table
|
PIMAGE_THUNK_DATA pINT; // Import Name Table
|
||||||
PIMAGE_IMPORT_BY_NAME pImpName;
|
PIMAGE_IMPORT_BY_NAME pImpName;
|
||||||
|
DWORD ImpVA;
|
||||||
|
|
||||||
if (pDOS->e_magic != IMAGE_DOS_SIGNATURE)
|
if (pDOS->e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
return NULL;
|
return NULL;
|
||||||
pPE = (PIMAGE_NT_HEADERS)(pImage + pDOS->e_lfanew);
|
pPE = (PIMAGE_NT_HEADERS)(pImage + pDOS->e_lfanew);
|
||||||
if (pPE->Signature != IMAGE_NT_SIGNATURE)
|
if (pPE->Signature != IMAGE_NT_SIGNATURE)
|
||||||
return NULL;
|
return NULL;
|
||||||
pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage
|
|
||||||
+ pPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
ImpVA = pPE->OptionalHeader
|
||||||
.VirtualAddress);
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
||||||
|
if (ImpVA == 0)
|
||||||
|
return NULL; // No Import Table
|
||||||
|
pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage + ImpVA);
|
||||||
|
|
||||||
for (; pImpDesc->FirstThunk; ++pImpDesc)
|
for (; pImpDesc->FirstThunk; ++pImpDesc)
|
||||||
{
|
{
|
||||||
if (!pImpDesc->OriginalFirstThunk)
|
if (!pImpDesc->OriginalFirstThunk)
|
||||||
@@ -709,6 +714,65 @@ hook_dll_import_func(HINSTANCE hInst, const char *funcname, const void *hook)
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
#if defined(DYNAMIC_GETTEXT) || defined(PROTO)
|
||||||
# ifndef GETTEXT_DLL
|
# ifndef GETTEXT_DLL
|
||||||
# define GETTEXT_DLL "libintl.dll"
|
# define GETTEXT_DLL "libintl.dll"
|
||||||
|
@@ -5,6 +5,7 @@ int mch_is_gui_executable(void);
|
|||||||
HINSTANCE find_imported_module_by_funcname(HINSTANCE hInst, const char *funcname);
|
HINSTANCE find_imported_module_by_funcname(HINSTANCE hInst, const char *funcname);
|
||||||
void *get_dll_import_func(HINSTANCE hInst, const char *funcname);
|
void *get_dll_import_func(HINSTANCE hInst, const char *funcname);
|
||||||
void *hook_dll_import_func(HINSTANCE hInst, const char *funcname, const void *hook);
|
void *hook_dll_import_func(HINSTANCE hInst, const char *funcname, const void *hook);
|
||||||
|
HINSTANCE get_forwarded_dll(HINSTANCE hInst);
|
||||||
int dyn_libintl_init(void);
|
int dyn_libintl_init(void);
|
||||||
void dyn_libintl_end(void);
|
void dyn_libintl_end(void);
|
||||||
void PlatformId(void);
|
void PlatformId(void);
|
||||||
|
@@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1980,
|
||||||
/**/
|
/**/
|
||||||
1979,
|
1979,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user