From 2bac9d469398c0453e8026430e0f84a74a7b602f Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 12 Nov 2022 18:52:36 +0800 Subject: [PATCH] Handle request serial wraparound more correctly * src/xterm.c (X_COMPARE_SERIALS): Remove macro. (x_is_serial_more_than, x_is_serial_more_than_or_equal_to) (x_is_serial_less_than, x_is_serial_less_than_or_equal_to): New functions. (x_find_error_handler, x_request_can_fail) (x_clean_failable_requests, x_stop_ignoring_errors): Use those functions to perform request serial comparison. --- src/xterm.c | 70 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index b1e74199d71..e50f669e671 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -912,11 +912,6 @@ struct x_selection_request_event struct x_selection_request_event *pending_selection_requests; -/* Compare two request serials A and B with OP, handling - wraparound. */ -#define X_COMPARE_SERIALS(a, op ,b) \ - (((long) (a) - (long) (b)) op 0) - struct x_atom_ref { /* Atom name. */ @@ -25084,6 +25079,48 @@ static struct x_error_message_stack *x_error_message; /* The amount of items (depth) in that stack. */ int x_error_message_count; +/* Compare various request serials while handling wraparound. Treat a + difference of more than X_ULONG_MAX / 2 as wraparound. + + Note that these functions truncate serials to 32 bits before + comparison. */ + +static bool +x_is_serial_more_than (unsigned int a, unsigned int b) +{ + if (a > b) + return true; + + return (b - a > X_ULONG_MAX / 2); +} + +static bool +x_is_serial_more_than_or_equal_to (unsigned int a, unsigned int b) +{ + if (a >= b) + return true; + + return (b - a > X_ULONG_MAX / 2); +} + +static bool +x_is_serial_less_than (unsigned int a, unsigned int b) +{ + if (a < b) + return true; + + return (a - b > X_ULONG_MAX / 2); +} + +static bool +x_is_serial_less_than_or_equal_to (unsigned int a, unsigned int b) +{ + if (a <= b) + return true; + + return (a - b > X_ULONG_MAX / 2); +} + static struct x_error_message_stack * x_find_error_handler (Display *dpy, XErrorEvent *event) { @@ -25093,8 +25130,8 @@ x_find_error_handler (Display *dpy, XErrorEvent *event) while (stack) { - if (X_COMPARE_SERIALS (event->serial, >=, - stack->first_request) + if (x_is_serial_more_than_or_equal_to (event->serial, + stack->first_request) && dpy == stack->dpy) return stack; @@ -25197,11 +25234,11 @@ x_request_can_fail (struct x_display_info *dpyinfo, failable_requests < dpyinfo->next_failable_request; failable_requests++) { - if (X_COMPARE_SERIALS (request, >=, - failable_requests->start) + if (x_is_serial_more_than_or_equal_to (request, + failable_requests->start) && (!failable_requests->end - || X_COMPARE_SERIALS (request, <=, - failable_requests->end))) + || x_is_serial_less_than_or_equal_to (request, + failable_requests->end))) return failable_requests; } @@ -25219,11 +25256,11 @@ x_clean_failable_requests (struct x_display_info *dpyinfo) for (first = dpyinfo->failable_requests; first < last; first++) { - if (X_COMPARE_SERIALS (first->start, >, - LastKnownRequestProcessed (dpyinfo->display)) + if (x_is_serial_more_than (first->start, + LastKnownRequestProcessed (dpyinfo->display)) || !first->end - || X_COMPARE_SERIALS (first->end, >, - LastKnownRequestProcessed (dpyinfo->display))) + || x_is_serial_more_than (first->end, + LastKnownRequestProcessed (dpyinfo->display))) break; } @@ -25302,8 +25339,7 @@ x_stop_ignoring_errors (struct x_display_info *dpyinfo) /* Abort if no request was made since `x_ignore_errors_for_next_request'. */ - if (X_COMPARE_SERIALS (range->end, <, - range->start)) + if (x_is_serial_less_than (range->end, range->start)) emacs_abort (); #ifdef HAVE_GTK3 -- 2.39.5