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.

Raspunde prin e-mail lui