emacs-diffs
[Top][All Lists]
Advanced

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

master 9bd91a3751 2/3: Fix overflows in HAVE_XSYNC timestamp handling


From: Paul Eggert
Subject: master 9bd91a3751 2/3: Fix overflows in HAVE_XSYNC timestamp handling
Date: Thu, 25 Aug 2022 21:32:24 -0400 (EDT)

branch: master
commit 9bd91a3751cfb01c9499a5ee7080349b9c8f0f65
Author: Paul Eggert <eggert@cs.ucla.edu>
Commit: Paul Eggert <eggert@cs.ucla.edu>

    Fix overflows in HAVE_XSYNC timestamp handling
    
    Also, port to platforms lacking CLOCK_MONOTONIC and int64_t, and
    use 0 more consistently to represent missing timestamps.
    * src/xterm.h (struct x_display_info):
    Omit server_time_monotonic_p and server_time_offset if
    !HAVE_CLOCK_GETTIME since they are unused in that case.
    * src/xterm.h (struct x_display_info, struct x_output):
    * src/xterm.c (x_sync_get_monotonic_time)
    (x_sync_current_monotonic_time, x_sync_note_frame_times):
    Use int_fast64_t instead of int64_t as POSIX doesn't
    guarantee the latter.  Similarly for uint_fast64_t.
    (x_sync_get_monotonic_time, x_sync_current_monotonic_time)
    (x_sync_note_frame_times, x_display_set_last_user_time):
    Check for integer overflow in time arithmetic.
    (CLOCK_MONOTONIC): Define to CLOCK_REALTIME if absent.
    (x_sync_current_monotonic_time): Check for clock_gettime failure
    and fall back on CLOCK_REALTIME if CLOCK_MONOTONIC does not work,
    which POSIX allows.
    (x_sync_current_monotonic_time, x_sync_note_frame_times)
    (x_display_set_last_user_time):
    Use 0 more consistently to represent missing timestamps.
---
 src/xterm.c | 76 +++++++++++++++++++++++++++++++++++--------------------------
 src/xterm.h | 10 ++++----
 2 files changed, 49 insertions(+), 37 deletions(-)

diff --git a/src/xterm.c b/src/xterm.c
index fb4c0c74db..5a36aa0302 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -6714,9 +6714,9 @@ x_if_event (Display *dpy, XEvent *event_return,
    server timestamp TIMESTAMP.  Return 0 if the necessary information
    is not available.  */
 
-static uint64_t
+static uint_fast64_t
 x_sync_get_monotonic_time (struct x_display_info *dpyinfo,
-                          uint64_t timestamp)
+                          uint_fast64_t timestamp)
 {
   if (dpyinfo->server_time_monotonic_p)
     return timestamp;
@@ -6725,19 +6725,29 @@ x_sync_get_monotonic_time (struct x_display_info 
*dpyinfo,
   if (!dpyinfo->server_time_offset)
     return 0;
 
-  return timestamp - dpyinfo->server_time_offset;
+  uint_fast64_t t;
+  return (INT_SUBTRACT_WRAPV (timestamp, dpyinfo->server_time_offset, &t)
+         ? 0 : t);
 }
 
+# ifndef CLOCK_MONOTONIC
+#  define CLOCK_MONOTONIC CLOCK_REALTIME
+# endif
+
 /* Return the current monotonic time in the same format as a
-   high-resolution server timestamp.  */
+   high-resolution server timestamp, or 0 if not available.  */
 
-static uint64_t
+static uint_fast64_t
 x_sync_current_monotonic_time (void)
 {
   struct timespec time;
-
-  clock_gettime (CLOCK_MONOTONIC, &time);
-  return time.tv_sec * 1000000 + time.tv_nsec / 1000;
+  uint_fast64_t t;
+  return (((clock_gettime (CLOCK_MONOTONIC, &time) != 0
+           && (CLOCK_MONOTONIC == CLOCK_REALTIME
+               || clock_gettime (CLOCK_REALTIME, &time) != 0))
+          || INT_MULTIPLY_WRAPV (time.tv_sec, 1000000, &t)
+          || INT_ADD_WRAPV (t, time.tv_nsec / 1000, &t))
+         ? 0 : t);
 }
 
 /* Decode a _NET_WM_FRAME_DRAWN message and calculate the time it took
@@ -6747,7 +6757,7 @@ static void
 x_sync_note_frame_times (struct x_display_info *dpyinfo,
                         struct frame *f, XEvent *event)
 {
-  uint64_t low, high, time;
+  uint_fast64_t low, high, time;
   struct x_output *output;
 
   low = event->xclient.data.l[2];
@@ -6756,12 +6766,16 @@ x_sync_note_frame_times (struct x_display_info *dpyinfo,
 
   time = x_sync_get_monotonic_time (dpyinfo, low | (high << 32));
 
-  if (time)
-    output->last_frame_time = time - output->temp_frame_time;
+  if (!time || !output->temp_frame_time
+      || INT_SUBTRACT_WRAPV (time, output->temp_frame_time,
+                            &output->last_frame_time))
+    output->last_frame_time = 0;
 
 #ifdef FRAME_DEBUG
-  fprintf (stderr, "Drawing the last frame took: %lu ms (%lu)\n",
-          output->last_frame_time / 1000, time);
+  uint_fast64_t last_frame_ms = output->last_frame_time / 1000;
+  fprintf (stderr,
+          "Drawing the last frame took: %"PRIuFAST64" ms (%"PRIuFAST64")\n",
+          last_frame_ms, time);
 #endif
 }
 
@@ -6891,22 +6905,16 @@ x_sync_update_begin (struct frame *f)
 static void
 x_sync_trigger_fence (struct frame *f, XSyncValue value)
 {
-  uint64_t n, low, high, idx;
-
   /* Sync fences aren't supported by the X server.  */
   if (FRAME_DISPLAY_INFO (f)->xsync_major < 3
       || (FRAME_DISPLAY_INFO (f)->xsync_major == 3
          && FRAME_DISPLAY_INFO (f)->xsync_minor < 1))
     return;
 
-  low = XSyncValueLow32 (value);
-  high = XSyncValueHigh32 (value);
-
-  n = low | (high << 32);
-  idx = (n / 4) % 2;
+  bool idx = !! (XSyncValueLow32 (value) & 4);
 
 #ifdef FRAME_DEBUG
-  fprintf (stderr, "Triggering synchronization fence: %lu\n", idx);
+  fprintf (stderr, "Triggering synchronization fence: %d\n", idx);
 #endif
 
   XSyncTriggerFence (FRAME_X_DISPLAY (f),
@@ -7600,9 +7608,6 @@ x_display_set_last_user_time (struct x_display_info 
*dpyinfo, Time time,
 #ifndef USE_GTK
   struct frame *focus_frame;
   Time old_time;
-#if defined HAVE_XSYNC && defined HAVE_CLOCK_GETTIME
-  uint64_t monotonic_time;
-#endif
 
   focus_frame = dpyinfo->x_focus_frame;
   old_time = dpyinfo->last_user_time;
@@ -7620,19 +7625,26 @@ x_display_set_last_user_time (struct x_display_info 
*dpyinfo, Time time,
     {
       /* See if the current CLOCK_MONOTONIC time is reasonably close
         to the X server time.  */
-      monotonic_time = x_sync_current_monotonic_time ();
+      uint_fast64_t monotonic_time = x_sync_current_monotonic_time ();
+      uint_fast64_t monotonic_ms = monotonic_time / 1000;
+      int_fast64_t diff_ms;
 
-      if (time * 1000 > monotonic_time - 500 * 1000
-         && time * 1000 < monotonic_time + 500 * 1000)
-       dpyinfo->server_time_monotonic_p = true;
-      else
+      dpyinfo->server_time_monotonic_p
+       = (monotonic_time != 0
+          && !INT_SUBTRACT_WRAPV (time, monotonic_ms, &diff_ms)
+          && -500 < diff_ms && diff_ms < 500);
+
+      if (!dpyinfo->server_time_monotonic_p)
        {
          /* Compute an offset that can be subtracted from the server
             time to estimate the monotonic time on the X server.  */
 
-         dpyinfo->server_time_monotonic_p = false;
-         dpyinfo->server_time_offset
-           = ((int64_t) time * 1000) - monotonic_time;
+         if (!monotonic_time
+             || INT_MULTIPLY_WRAPV (time, 1000, &dpyinfo->server_time_offset)
+             || INT_SUBTRACT_WRAPV (dpyinfo->server_time_offset,
+                                    monotonic_time,
+                                    &dpyinfo->server_time_offset))
+           dpyinfo->server_time_offset = 0;
        }
     }
 #endif
diff --git a/src/xterm.h b/src/xterm.h
index 9d9675428f..3654c3d5db 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -828,14 +828,14 @@ struct x_display_info
      drag-and-drop emulation.  */
   Time pending_dnd_time;
 
-#if defined HAVE_XSYNC && !defined USE_GTK
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
   /* Whether or not the server time is probably the same as
      "clock_gettime (CLOCK_MONOTONIC, ...)".  */
   bool server_time_monotonic_p;
 
   /* The time difference between the X server clock and the monotonic
-     clock.  */
-  int64_t server_time_offset;
+     clock, or 0 if unknown (FIXME: what if the difference is zero?).  */
+  int_fast64_t server_time_offset;
 #endif
 };
 
@@ -1131,10 +1131,10 @@ struct x_output
   bool_bf use_vsync_p : 1;
 
   /* The time (in microseconds) it took to draw the last frame.  */
-  uint64_t last_frame_time;
+  uint_fast64_t last_frame_time;
 
   /* A temporary time used to calculate that value.  */
-  uint64_t temp_frame_time;
+  uint_fast64_t temp_frame_time;
 
 #ifdef HAVE_XSYNCTRIGGERFENCE
   /* An array of two sync fences that are triggered in order after a



reply via email to

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