[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);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 2267b48cac: Fix two crashes when a display connection is lost,
Po Lu <=