emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 2267b48cac: Fix two crashes when a display connection is lost


From: Po Lu
Subject: master 2267b48cac: Fix two crashes when a display connection is lost
Date: Mon, 6 Jun 2022 21:27:31 -0400 (EDT)

branch: master
commit 2267b48cac3c8e8a834b4faaa5390f2ad6a54281
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Fix two crashes when a display connection is lost
    
    This fixes errors caused by invalid error traps being left on
    the error handler stack if an IO error causes a non-local exit
    out of the protected code, and another crash caused by
    delete_frame trying to read async input.
    
    * src/eval.c (unwind_to_catch, push_handler_nosignal): Save and
    restore the X error handler stack.
    * src/lisp.h (struct handler): [HAVE_X_WINDOWS]: New field
    `x_error_handler_depth'.
    
    * src/xterm.c (struct x_error_message_stack): Make string a
    regular string.
    (x_unwind_errors_to): New function.
    (x_error_catcher, x_catch_errors_with_handler)
    (x_uncatch_errors_after_check, x_uncatch_errors): Update the
    stack depth.
    (x_check_errors): Stop manually unwinding since unwind_to_catch
    now does that for us.
    (x_had_errors_p, x_clear_errors): Update for new type of
    `string'.
    (x_connection_closed): Block input between just before
    delete_frame to when the terminal is unlinked.
    
    * src/xterm.h: Update prototypes.
---
 src/eval.c  | 10 ++++++++++
 src/lisp.h  |  4 ++++
 src/xterm.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++-------------
 src/xterm.h |  2 ++
 4 files changed, 67 insertions(+), 14 deletions(-)

diff --git a/src/eval.c b/src/eval.c
index c3be1dc12c..d4d4a6cfdd 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1251,6 +1251,13 @@ unwind_to_catch (struct handler *catch, enum 
nonlocal_exit type,
   set_poll_suppress_count (catch->poll_suppress_count);
   unblock_input_to (catch->interrupt_input_blocked);
 
+#ifdef HAVE_X_WINDOWS
+  /* Restore the X error handler stack.  This is important because
+     otherwise a display disconnect won't unwind the stack of error
+     traps to the right depth.  */
+  x_unwind_errors_to (catch->x_error_handler_depth);
+#endif
+
   do
     {
       /* Unwind the specpdl stack, and then restore the proper set of
@@ -1625,6 +1632,9 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum 
handlertype handlertype)
   c->act_rec = get_act_rec (current_thread);
   c->poll_suppress_count = poll_suppress_count;
   c->interrupt_input_blocked = interrupt_input_blocked;
+#ifdef HAVE_X_WINDOWS
+  c->x_error_handler_depth = x_error_message_count;
+#endif
   handlerlist = c;
   return c;
 }
diff --git a/src/lisp.h b/src/lisp.h
index ff6f0aaf54..499bacc330 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3631,6 +3631,10 @@ struct handler
   struct bc_frame *act_rec;
   int poll_suppress_count;
   int interrupt_input_blocked;
+
+#ifdef HAVE_X_WINDOWS
+  int x_error_handler_depth;
+#endif
 };
 
 extern Lisp_Object memory_signal_data;
diff --git a/src/xterm.c b/src/xterm.c
index fa7e285425..ee396f38cc 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -21781,13 +21781,12 @@ x_text_icon (struct frame *f, const char *icon_name)
   return false;
 }
 
-#define X_ERROR_MESSAGE_SIZE 200
 
 struct x_error_message_stack
 {
-  /* Buffer containing the error message of any error that was
-     generated.  */
-  char string[X_ERROR_MESSAGE_SIZE];
+  /* Pointer to the error message of any error that was generated, or
+     NULL.  */
+  char *string;
 
   /* The display this error handler applies to.  */
   Display *dpy;
@@ -21817,6 +21816,9 @@ struct x_error_message_stack
    placed before 2006.  */
 static struct x_error_message_stack *x_error_message;
 
+/* The amount of items (depth) in that stack.  */
+int x_error_message_count;
+
 static struct x_error_message_stack *
 x_find_error_handler (Display *dpy, XErrorEvent *event)
 {
@@ -21837,6 +21839,17 @@ x_find_error_handler (Display *dpy, XErrorEvent *event)
   return NULL;
 }
 
+void
+x_unwind_errors_to (int depth)
+{
+  while (x_error_message_count > depth)
+    /* This is safe to call because we check whether or not
+       x_error_message->dpy is still alive before calling XSync.  */
+    x_uncatch_errors ();
+}
+
+#define X_ERROR_MESSAGE_SIZE 200
+
 /* An X error handler which stores the error message in the first
    applicable handler in the x_error_message stack.  This is called
    from *x_error_handler if an x_catch_errors for DISPLAY is in
@@ -21846,8 +21859,15 @@ static void
 x_error_catcher (Display *display, XErrorEvent *event,
                 struct x_error_message_stack *stack)
 {
+  char buf[X_ERROR_MESSAGE_SIZE];
+
   XGetErrorText (display, event->error_code,
-                stack->string, X_ERROR_MESSAGE_SIZE);
+                buf, X_ERROR_MESSAGE_SIZE);
+
+  if (stack->string)
+    xfree (stack->string);
+
+  stack->string = xstrdup (buf);
 
   if (stack->handler)
     stack->handler (display, event, stack->string,
@@ -21875,15 +21895,17 @@ void
 x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
                             void *handler_data)
 {
-  struct x_error_message_stack *data = xmalloc (sizeof *data);
+  struct x_error_message_stack *data;
 
+  data = xzalloc (sizeof *data);
   data->dpy = dpy;
-  data->string[0] = 0;
   data->handler = handler;
   data->handler_data = handler_data;
   data->prev = x_error_message;
   data->first_request = NextRequest (dpy);
   x_error_message = data;
+
+  ++x_error_message_count;
 }
 
 void
@@ -21907,6 +21929,9 @@ x_uncatch_errors_after_check (void)
   block_input ();
   tmp = x_error_message;
   x_error_message = x_error_message->prev;
+  --x_error_message_count;
+  if (tmp->string)
+    xfree (tmp->string);
   xfree (tmp);
   unblock_input ();
 }
@@ -21942,6 +21967,9 @@ x_uncatch_errors (void)
 
   tmp = x_error_message;
   x_error_message = x_error_message->prev;
+  --x_error_message_count;
+  if (tmp->string)
+    xfree (tmp->string);
   xfree (tmp);
   unblock_input ();
 }
@@ -21953,7 +21981,7 @@ x_uncatch_errors (void)
 void
 x_check_errors (Display *dpy, const char *format)
 {
-  char string[X_ERROR_MESSAGE_SIZE];
+  char *string;
 
   /* This shouldn't happen, since x_check_errors should be called
      immediately inside an x_catch_errors block.  */
@@ -21968,11 +21996,11 @@ x_check_errors (Display *dpy, const char *format)
          > x_error_message->first_request))
     XSync (dpy, False);
 
-  if (x_error_message->string[0])
+  if (x_error_message->string)
     {
-      memcpy (string, x_error_message->string,
-             X_ERROR_MESSAGE_SIZE);
-      x_uncatch_errors ();
+      string = alloca (strlen (x_error_message->string) + 1);
+      strcpy (string, x_error_message->string);
+
       error (format, string);
     }
 }
@@ -21995,7 +22023,7 @@ x_had_errors_p (Display *dpy)
          > x_error_message->first_request))
     XSync (dpy, False);
 
-  return x_error_message->string[0] != 0;
+  return x_error_message->string;
 }
 
 /* Forget about any errors we have had, since we did x_catch_errors on
@@ -22009,7 +22037,8 @@ x_clear_errors (Display *dpy)
   if (dpy != x_error_message->dpy)
     emacs_abort ();
 
-  x_error_message->string[0] = 0;
+  xfree (x_error_message->string);
+  x_error_message->string = NULL;
 }
 
 #if false
@@ -22142,6 +22171,12 @@ x_connection_closed (Display *dpy, const char 
*error_message, bool ioerror)
        dpyinfo->display = 0;
     }
 
+  /* delete_frame can still try to read async input (even though we
+     tell pass `noelisp'), because looking up the `delete-before'
+     parameter calls Fassq which then calls maybe_quit.  So block
+     input while deleting frames.  */
+  block_input ();
+
   /* First delete frames whose mini-buffers are on frames
      that are on the dead display.  */
   FOR_EACH_FRAME (tail, frame)
@@ -22206,6 +22241,8 @@ For details, see etc/PROBLEMS.\n",
       }
     }
 
+  unblock_input ();
+
   if (terminal_list == 0)
     {
       fprintf (stderr, "%s\n", error_msg);
diff --git a/src/xterm.h b/src/xterm.h
index 22c6b55176..c6be30d73e 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1396,6 +1396,7 @@ extern void x_catch_errors_with_handler (Display *, 
x_special_error_handler,
 extern void x_check_errors (Display *, const char *)
   ATTRIBUTE_FORMAT_PRINTF (2, 0);
 extern bool x_had_errors_p (Display *);
+extern void x_unwind_errors_to (int);
 extern void x_uncatch_errors (void);
 extern void x_uncatch_errors_after_check (void);
 extern void x_clear_errors (Display *);
@@ -1615,6 +1616,7 @@ extern bool x_dnd_waiting_for_finish;
 extern struct frame *x_dnd_frame;
 extern struct frame *x_dnd_finish_frame;
 extern unsigned x_dnd_unsupported_event_level;
+extern int x_error_message_count;
 
 #ifdef HAVE_XINPUT2
 extern struct xi_device_t *xi_device_from_id (struct x_display_info *, int);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]