Mercurial > vim
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 |