Patch 8.2.4317
Problem: MS-Windows: Vim exits when Python 3 initialisation fails.
Solution: Hook into the exit() function to recover from the failure.
(Ken Takata, closes #9710)
Files: runtime/doc/if_pyth.txt, src/if_python3.c, src/os_win32.c,
src/errors.h, src/proto/os_win32.pro
*** ../vim-8.2.4316/runtime/doc/if_pyth.txt 2020-04-14 19:15:45.284566193
+0100
--- runtime/doc/if_pyth.txt 2022-02-07 13:29:13.758512584 +0000
***************
*** 63,68 ****
--- 63,73 ----
There is no need to import sys, it's done by default.
+ *python-environment*
+ Environment variables set in Vim are not always available in Python. This
+ depends on how Vim and Python were build. Also see
+ https://docs.python.org/3/library/os.html#os.environ
+
Note: Python is very sensitive to the indenting. Make sure the "class" line
and "EOF" do not have any indent.
***************
*** 829,834 ****
--- 834,852 ----
Raising SystemExit exception in python isn't endorsed way to quit vim, use: >
:py vim.command("qall!")
<
+ *E1266*
+ This error can occur when python 3 cannot load the required modules. This
+ means that your python 3 is not correctly installed or there are some mistakes
+ in your settings. Please check the following items:
+ 1. Make sure that python 3 is correctly installed. Also check the version of
+ python.
+ 2. Check the 'pythonthreedll' option.
+ 3. Check the 'pythonthreehome' option.
+ 4. Check the PATH environment variable if you don't set 'pythonthreedll'.
+ On MS-Windows, you can use where.exe to check which dll will be loaded.
+ E.g. >
+ where.exe python310.dll
+ 5. Check the PYTHONPATH and PYTHONHOME environment variables.
*has-python*
You can test what Python version is available with: >
*** ../vim-8.2.4316/src/if_python3.c 2022-01-05 17:49:10.877225131 +0000
--- src/if_python3.c 2022-02-07 13:41:01.885775623 +0000
***************
*** 112,123 ****
typedef PySliceObject PySliceObject_T;
#endif
#if defined(DYNAMIC_PYTHON3) || defined(PROTO)
# ifndef MSWIN
# include <dlfcn.h>
# define FARPROC void*
- # define HINSTANCE void*
# if defined(PY_NO_RTLD_GLOBAL) && defined(PY3_NO_RTLD_GLOBAL)
# define load_dll(n) dlopen((n), RTLD_LAZY)
# else
--- 112,129 ----
typedef PySliceObject PySliceObject_T;
#endif
+ #ifndef MSWIN
+ # define HINSTANCE void *
+ #endif
+ #if defined(DYNAMIC_PYTHON3) || defined(MSWIN)
+ static HINSTANCE hinstPy3 = 0; // Instance of python.dll
+ #endif
+
#if defined(DYNAMIC_PYTHON3) || defined(PROTO)
# ifndef MSWIN
# include <dlfcn.h>
# define FARPROC void*
# if defined(PY_NO_RTLD_GLOBAL) && defined(PY3_NO_RTLD_GLOBAL)
# define load_dll(n) dlopen((n), RTLD_LAZY)
# else
***************
*** 459,466 ****
static void(*py3_PyObject_GC_UnTrack)(void *);
static int (*py3_PyType_IsSubtype)(PyTypeObject *, PyTypeObject *);
- static HINSTANCE hinstPy3 = 0; // Instance of python.dll
-
// Imported exception objects
static PyObject *p3imp_PyExc_AttributeError;
static PyObject *p3imp_PyExc_IndexError;
--- 465,470 ----
***************
*** 1032,1044 ****
{
FILE *(*py__acrt_iob_func)(unsigned) = NULL;
FILE *(*pyfreopen)(const char *, const char *, FILE *) = NULL;
! HINSTANCE hinst;
- # ifdef DYNAMIC_PYTHON3
- hinst = hinstPy3;
- # else
- hinst = GetModuleHandle(PYTHON3_DLL);
- # endif
if (hinst == NULL || is_stdin_readable())
return;
--- 1036,1043 ----
{
FILE *(*py__acrt_iob_func)(unsigned) = NULL;
FILE *(*pyfreopen)(const char *, const char *, FILE *) = NULL;
! HINSTANCE hinst = hinstPy3;
if (hinst == NULL || is_stdin_readable())
return;
***************
*** 1063,1068 ****
--- 1062,1118 ----
# define reset_stdin()
#endif
+ // Python 3.2 or later will abort inside Py_Initialize() when mandatory
+ // modules cannot be loaded (e.g. 'pythonthreehome' is wrongly set.).
+ // Install a hook to python dll's exit() and recover from it.
+ #if defined(MSWIN) && (PY_VERSION_HEX >= 0x030200f0)
+ # define HOOK_EXIT
+ # include <setjmp.h>
+
+ static jmp_buf exit_hook_jump_buf;
+ static void *orig_exit = NULL;
+
+ /*
+ * Function that replaces exit() while calling Py_Initialize().
+ */
+ static void
+ hooked_exit(int ret)
+ {
+ // Recover from exit.
+ longjmp(exit_hook_jump_buf, 1);
+ }
+
+ /*
+ * Install a hook to python dll's exit().
+ */
+ static void
+ hook_py_exit(void)
+ {
+ HINSTANCE hinst = hinstPy3;
+
+ if (hinst == NULL || orig_exit != NULL)
+ return;
+
+ orig_exit = hook_dll_import_func(hinst, "exit", (void *)hooked_exit);
+ }
+
+ /*
+ * Remove the hook installed by hook_py_exit().
+ */
+ static void
+ restore_py_exit(void)
+ {
+ HINSTANCE hinst = hinstPy3;
+
+ if (hinst == NULL)
+ return;
+
+ if (orig_exit != NULL)
+ hook_dll_import_func(hinst, "exit", orig_exit);
+ orig_exit = NULL;
+ }
+ #endif
+
static int
Python3_Init(void)
{
***************
*** 1095,1102 ****
PyImport_AppendInittab("vim", Py3Init_vim);
reset_stdin();
! Py_Initialize();
#if PY_VERSION_HEX < 0x03090000
// Initialise threads. This is deprecated since Python 3.9.
--- 1145,1175 ----
PyImport_AppendInittab("vim", Py3Init_vim);
+ #if !defined(DYNAMIC_PYTHON3) && defined(MSWIN)
+ hinstPy3 = GetModuleHandle(PYTHON3_DLL);
+ #endif
reset_stdin();
!
! #ifdef HOOK_EXIT
! // Catch exit() called in Py_Initialize().
! hook_py_exit();
! if (setjmp(exit_hook_jump_buf) == 0)
! #endif
! {
! Py_Initialize();
! #ifdef HOOK_EXIT
! restore_py_exit();
! #endif
! }
! #ifdef HOOK_EXIT
! else
! {
! // exit() was called in Py_Initialize().
! restore_py_exit();
!
emsg(_(e_critical_error_in_python3_initialization_check_your_installation));
! goto fail;
! }
! #endif
#if PY_VERSION_HEX < 0x03090000
// Initialise threads. This is deprecated since Python 3.9.
*** ../vim-8.2.4316/src/os_win32.c 2022-02-04 10:45:34.944240854 +0000
--- src/os_win32.c 2022-02-07 13:29:13.758512584 +0000
***************
*** 572,585 ****
}
#endif
! #if defined(DYNAMIC_ICONV) || defined(DYNAMIC_GETTEXT) || defined(PROTO)
/*
* Get related information about 'funcname' which is imported by 'hInst'.
* If 'info' is 0, return the function address.
* If 'info' is 1, return the module name which the function is imported from.
*/
static void *
! get_imported_func_info(HINSTANCE hInst, const char *funcname, int info)
{
PBYTE pImage = (PBYTE)hInst;
PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)hInst;
--- 572,589 ----
}
#endif
! #if defined(DYNAMIC_ICONV) || defined(DYNAMIC_GETTEXT) \
! || defined(FEAT_PYTHON3) || defined(PROTO)
/*
* Get related information about 'funcname' which is imported by 'hInst'.
* If 'info' is 0, return the function address.
* If 'info' is 1, return the module name which the function is imported from.
+ * If 'info' is 2, hook the function with 'ptr', and return the original
+ * function address.
*/
static void *
! get_imported_func_info(HINSTANCE hInst, const char *funcname, int info,
! const void *ptr)
{
PBYTE pImage = (PBYTE)hInst;
PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)hInst;
***************
*** 611,622 ****
--- 615,637 ----
+ (UINT_PTR)(pINT->u1.AddressOfData));
if (strcmp((char *)pImpName->Name, funcname) == 0)
{
+ void *original;
+ DWORD old, new = PAGE_READWRITE;
+
switch (info)
{
case 0:
return (void *)pIAT->u1.Function;
case 1:
return (void *)(pImage + pImpDesc->Name);
+ case 2:
+ original = (void *)pIAT->u1.Function;
+ VirtualProtect(&pIAT->u1.Function, sizeof(void *),
+ new, &old);
+ pIAT->u1.Function = (UINT_PTR)ptr;
+ VirtualProtect(&pIAT->u1.Function, sizeof(void *),
+ old, &new);
+ return original;
default:
return NULL;
}
***************
*** 634,640 ****
{
char *modulename;
! modulename = (char *)get_imported_func_info(hInst, funcname, 1);
if (modulename != NULL)
return GetModuleHandleA(modulename);
return NULL;
--- 649,655 ----
{
char *modulename;
! modulename = (char *)get_imported_func_info(hInst, funcname, 1, NULL);
if (modulename != NULL)
return GetModuleHandleA(modulename);
return NULL;
***************
*** 646,652 ****
void *
get_dll_import_func(HINSTANCE hInst, const char *funcname)
{
! return get_imported_func_info(hInst, funcname, 0);
}
#endif
--- 661,677 ----
void *
get_dll_import_func(HINSTANCE hInst, const char *funcname)
{
! return get_imported_func_info(hInst, funcname, 0, NULL);
! }
!
! /*
! * Hook the function named 'funcname' which is imported by 'hInst' DLL,
! * and return the original function address.
! */
! void *
! hook_dll_import_func(HINSTANCE hInst, const char *funcname, const void *hook)
! {
! return get_imported_func_info(hInst, funcname, 2, hook);
}
#endif
*** ../vim-8.2.4316/src/errors.h 2022-02-03 20:09:15.507340313 +0000
--- src/errors.h 2022-02-07 13:35:16.546142365 +0000
***************
*** 3224,3226 ****
--- 3224,3230 ----
EXTERN char e_cannot_use_partial_here[]
INIT(= N_("E1265: Cannot use a partial here"));
#endif
+ #if defined(FEAT_PYTHON3) && defined(MSWIN)
+ EXTERN char
e_critical_error_in_python3_initialization_check_your_installation[]
+ INIT(= N_("E1266: Critical error in python3 initialization, check your
python3 installation"));
+ #endif
*** ../vim-8.2.4316/src/proto/os_win32.pro 2022-01-24 11:23:59.859900461
+0000
--- src/proto/os_win32.pro 2022-02-07 13:29:13.758512584 +0000
***************
*** 3,8 ****
--- 3,9 ----
int mch_is_gui_executable(void);
HINSTANCE find_imported_module_by_funcname(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);
int dyn_libintl_init(void);
void dyn_libintl_end(void);
void PlatformId(void);
*** ../vim-8.2.4316/src/version.c 2022-02-07 10:45:12.803027327 +0000
--- src/version.c 2022-02-07 13:53:13.068980795 +0000
***************
*** 748,749 ****
--- 748,751 ----
{ /* Add new patch number below this line */
+ /**/
+ 4317,
/**/
--
hundred-and-one symptoms of being an internet addict:
20. When looking at a pageful of someone else's links, you notice all of them
are already highlighted in purple.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/20220207135531.5BF1D1C071D%40moolenaar.net.