patch 9.1.1324: undefined behaviour if X11 connection dies
Problem: undefined behaviour if X11 connection dies
Solution: call setjmp() before the main_loop() and restore x11 state
if the X11 connection dies (Foxe Chen)
fixes: #698
closes: #17142
Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/main.c b/src/main.c
index 9a862c4..31494e3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -449,6 +449,35 @@
#endif // NO_VIM_MAIN
#endif // PROTO
+#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+/*
+ * Restore the state after a fatal X error.
+ */
+ static void
+x_restore_state(void)
+{
+ State = MODE_NORMAL;
+ VIsual_active = FALSE;
+ got_int = TRUE;
+ need_wait_return = FALSE;
+ global_busy = FALSE;
+ exmode_active = 0;
+ skip_redraw = FALSE;
+ RedrawingDisabled = 0;
+ no_wait_return = 0;
+ vgetc_busy = 0;
+# ifdef FEAT_EVAL
+ emsg_skip = 0;
+# endif
+ emsg_off = 0;
+ setmouse();
+ settmode(TMODE_RAW);
+ starttermcap();
+ scroll_start();
+ redraw_later_clear();
+}
+#endif
+
/*
* vim_main2() is needed for FEAT_MZSCHEME, but we define it always to keep
* things simple.
@@ -790,9 +819,28 @@
getout(1);
}
- // Execute any "+", "-c" and "-S" arguments.
- if (params.n_commands > 0)
- exe_commands(¶ms);
+#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+ // Temporarily set x_jump_env to here in case there is an X11 IO error,
+ // because x_jump_env is only actually set in main_loop(), before
+ // exe_commands(). May not be the best solution since commands passed via
+ // the command line can be very broad like sourcing a file, in which case
+ // an X IO error results in the command being partially done. In theory we
+ // could use SETJMP in RealWaitForChar(), but the stack frame for that may
+ // possibly exit and then LONGJMP is called on it.
+ int jump_result = SETJMP(x_jump_env);
+
+ if (jump_result == 0)
+ {
+#endif
+ // Execute any "+", "-c" and "-S" arguments.
+ if (params.n_commands > 0)
+ exe_commands(¶ms);
+#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+ }
+ else
+ // Restore state and continue just like what main_loop() does.
+ x_restore_state();
+#endif
// Must come before the may_req_ calls.
starting = 0;
@@ -1242,30 +1290,10 @@
#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
// Setup to catch a terminating error from the X server. Just ignore
// it, restore the state and continue. This might not always work
- // properly, but at least we don't exit unexpectedly when the X server
- // exits while Vim is running in a console.
+ // properly, but at least we hopefully don't exit unexpectedly when the X
+ // server exits while Vim is running in a console.
if (!cmdwin && !noexmode && SETJMP(x_jump_env))
- {
- State = MODE_NORMAL;
- VIsual_active = FALSE;
- got_int = TRUE;
- need_wait_return = FALSE;
- global_busy = FALSE;
- exmode_active = 0;
- skip_redraw = FALSE;
- RedrawingDisabled = 0;
- no_wait_return = 0;
- vgetc_busy = 0;
-# ifdef FEAT_EVAL
- emsg_skip = 0;
-# endif
- emsg_off = 0;
- setmouse();
- settmode(TMODE_RAW);
- starttermcap();
- scroll_start();
- redraw_later_clear();
- }
+ x_restore_state();
#endif
clear_oparg(&oa);