Commit: patch 9.1.1324: undefined behaviour if X11 connection dies

0 views
Skip to first unread message

Christian Brabandt

unread,
Apr 19, 2025, 5:45:14 AM4/19/25
to vim...@googlegroups.com
patch 9.1.1324: undefined behaviour if X11 connection dies

Commit: https://github.com/vim/vim/commit/6924eb81f4e69726f59eaa0c121b7442343d770d
Author: Foxe Chen <chen...@gmail.com>
Date: Sat Apr 19 11:25:18 2025 +0200

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...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/main.c b/src/main.c
index 9a862c4be..31494e3e8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -449,6 +449,35 @@ main
#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 @@ vim_main2(void)
getout(1);
}

- // Execute any "+", "-c" and "-S" arguments.
- if (params.n_commands > 0)
- exe_commands(&params);
+#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(&params);
+#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 @@ main_loop(
#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);
diff --git a/src/version.c b/src/version.c
index db77e4538..e3b55fa94 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1324,
/**/
1323,
/**/
Reply all
Reply to author
Forward
0 new messages