comparison src/if_python3.c @ 27581:78e3b38b0d33 v8.2.4317

patch 8.2.4317: MS-Windows: Vim exits when Python 3 initialisation fails Commit: https://github.com/vim/vim/commit/63ff72aab91679725077eab5c5405267792268bd Author: Bram Moolenaar <Bram@vim.org> Date: Mon Feb 7 13:54:01 2022 +0000 patch 8.2.4317: MS-Windows: Vim exits when Python 3 initialisation fails 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)
author Bram Moolenaar <Bram@vim.org>
date Mon, 07 Feb 2022 15:00:04 +0100
parents 85866e069c24
children b15485413b9a
comparison
equal deleted inserted replaced
27580:bd5169e86dc5 27581:78e3b38b0d33
110 typedef PyObject PySliceObject_T; 110 typedef PyObject PySliceObject_T;
111 #else 111 #else
112 typedef PySliceObject PySliceObject_T; 112 typedef PySliceObject PySliceObject_T;
113 #endif 113 #endif
114 114
115 #ifndef MSWIN
116 # define HINSTANCE void *
117 #endif
118 #if defined(DYNAMIC_PYTHON3) || defined(MSWIN)
119 static HINSTANCE hinstPy3 = 0; // Instance of python.dll
120 #endif
121
115 #if defined(DYNAMIC_PYTHON3) || defined(PROTO) 122 #if defined(DYNAMIC_PYTHON3) || defined(PROTO)
116 123
117 # ifndef MSWIN 124 # ifndef MSWIN
118 # include <dlfcn.h> 125 # include <dlfcn.h>
119 # define FARPROC void* 126 # define FARPROC void*
120 # define HINSTANCE void*
121 # if defined(PY_NO_RTLD_GLOBAL) && defined(PY3_NO_RTLD_GLOBAL) 127 # if defined(PY_NO_RTLD_GLOBAL) && defined(PY3_NO_RTLD_GLOBAL)
122 # define load_dll(n) dlopen((n), RTLD_LAZY) 128 # define load_dll(n) dlopen((n), RTLD_LAZY)
123 # else 129 # else
124 # define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL) 130 # define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
125 # endif 131 # endif
457 static PyObject*(*py3__PyObject_GC_New)(PyTypeObject *); 463 static PyObject*(*py3__PyObject_GC_New)(PyTypeObject *);
458 static void(*py3_PyObject_GC_Del)(void *); 464 static void(*py3_PyObject_GC_Del)(void *);
459 static void(*py3_PyObject_GC_UnTrack)(void *); 465 static void(*py3_PyObject_GC_UnTrack)(void *);
460 static int (*py3_PyType_IsSubtype)(PyTypeObject *, PyTypeObject *); 466 static int (*py3_PyType_IsSubtype)(PyTypeObject *, PyTypeObject *);
461 467
462 static HINSTANCE hinstPy3 = 0; // Instance of python.dll
463
464 // Imported exception objects 468 // Imported exception objects
465 static PyObject *p3imp_PyExc_AttributeError; 469 static PyObject *p3imp_PyExc_AttributeError;
466 static PyObject *p3imp_PyExc_IndexError; 470 static PyObject *p3imp_PyExc_IndexError;
467 static PyObject *p3imp_PyExc_KeyError; 471 static PyObject *p3imp_PyExc_KeyError;
468 static PyObject *p3imp_PyExc_KeyboardInterrupt; 472 static PyObject *p3imp_PyExc_KeyboardInterrupt;
1030 static void 1034 static void
1031 reset_stdin(void) 1035 reset_stdin(void)
1032 { 1036 {
1033 FILE *(*py__acrt_iob_func)(unsigned) = NULL; 1037 FILE *(*py__acrt_iob_func)(unsigned) = NULL;
1034 FILE *(*pyfreopen)(const char *, const char *, FILE *) = NULL; 1038 FILE *(*pyfreopen)(const char *, const char *, FILE *) = NULL;
1035 HINSTANCE hinst; 1039 HINSTANCE hinst = hinstPy3;
1036 1040
1037 # ifdef DYNAMIC_PYTHON3
1038 hinst = hinstPy3;
1039 # else
1040 hinst = GetModuleHandle(PYTHON3_DLL);
1041 # endif
1042 if (hinst == NULL || is_stdin_readable()) 1041 if (hinst == NULL || is_stdin_readable())
1043 return; 1042 return;
1044 1043
1045 // Get "freopen" and "stdin" which are used in the python DLL. 1044 // Get "freopen" and "stdin" which are used in the python DLL.
1046 // "stdin" is defined as "__acrt_iob_func(0)" in VC++ 2015 or later. 1045 // "stdin" is defined as "__acrt_iob_func(0)" in VC++ 2015 or later.
1059 else 1058 else
1060 freopen("CONIN$", "r", stdin); 1059 freopen("CONIN$", "r", stdin);
1061 } 1060 }
1062 #else 1061 #else
1063 # define reset_stdin() 1062 # define reset_stdin()
1063 #endif
1064
1065 // Python 3.2 or later will abort inside Py_Initialize() when mandatory
1066 // modules cannot be loaded (e.g. 'pythonthreehome' is wrongly set.).
1067 // Install a hook to python dll's exit() and recover from it.
1068 #if defined(MSWIN) && (PY_VERSION_HEX >= 0x030200f0)
1069 # define HOOK_EXIT
1070 # include <setjmp.h>
1071
1072 static jmp_buf exit_hook_jump_buf;
1073 static void *orig_exit = NULL;
1074
1075 /*
1076 * Function that replaces exit() while calling Py_Initialize().
1077 */
1078 static void
1079 hooked_exit(int ret)
1080 {
1081 // Recover from exit.
1082 longjmp(exit_hook_jump_buf, 1);
1083 }
1084
1085 /*
1086 * Install a hook to python dll's exit().
1087 */
1088 static void
1089 hook_py_exit(void)
1090 {
1091 HINSTANCE hinst = hinstPy3;
1092
1093 if (hinst == NULL || orig_exit != NULL)
1094 return;
1095
1096 orig_exit = hook_dll_import_func(hinst, "exit", (void *)hooked_exit);
1097 }
1098
1099 /*
1100 * Remove the hook installed by hook_py_exit().
1101 */
1102 static void
1103 restore_py_exit(void)
1104 {
1105 HINSTANCE hinst = hinstPy3;
1106
1107 if (hinst == NULL)
1108 return;
1109
1110 if (orig_exit != NULL)
1111 hook_dll_import_func(hinst, "exit", orig_exit);
1112 orig_exit = NULL;
1113 }
1064 #endif 1114 #endif
1065 1115
1066 static int 1116 static int
1067 Python3_Init(void) 1117 Python3_Init(void)
1068 { 1118 {
1093 Py_SetPythonHome(PYTHON3_HOME); 1143 Py_SetPythonHome(PYTHON3_HOME);
1094 #endif 1144 #endif
1095 1145
1096 PyImport_AppendInittab("vim", Py3Init_vim); 1146 PyImport_AppendInittab("vim", Py3Init_vim);
1097 1147
1148 #if !defined(DYNAMIC_PYTHON3) && defined(MSWIN)
1149 hinstPy3 = GetModuleHandle(PYTHON3_DLL);
1150 #endif
1098 reset_stdin(); 1151 reset_stdin();
1099 Py_Initialize(); 1152
1153 #ifdef HOOK_EXIT
1154 // Catch exit() called in Py_Initialize().
1155 hook_py_exit();
1156 if (setjmp(exit_hook_jump_buf) == 0)
1157 #endif
1158 {
1159 Py_Initialize();
1160 #ifdef HOOK_EXIT
1161 restore_py_exit();
1162 #endif
1163 }
1164 #ifdef HOOK_EXIT
1165 else
1166 {
1167 // exit() was called in Py_Initialize().
1168 restore_py_exit();
1169 emsg(_(e_critical_error_in_python3_initialization_check_your_installation));
1170 goto fail;
1171 }
1172 #endif
1100 1173
1101 #if PY_VERSION_HEX < 0x03090000 1174 #if PY_VERSION_HEX < 0x03090000
1102 // Initialise threads. This is deprecated since Python 3.9. 1175 // Initialise threads. This is deprecated since Python 3.9.
1103 PyEval_InitThreads(); 1176 PyEval_InitThreads();
1104 #endif 1177 #endif