aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2022-08-23 18:18:13 -0700
committerPaul Eggert2022-08-25 18:30:11 -0700
commit9bd91a3751cfb01c9499a5ee7080349b9c8f0f65 (patch)
tree3a701007f17cd937d00ec0e844fd5426014c4efc /src
parent97067349a8d75ab720ff2e98653a6b21f60b221e (diff)
downloademacs-9bd91a3751cfb01c9499a5ee7080349b9c8f0f65.tar.gz
emacs-9bd91a3751cfb01c9499a5ee7080349b9c8f0f65.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/xterm.c76
-rw-r--r--src/xterm.h10
2 files changed, 49 insertions, 37 deletions
diff --git a/src/xterm.c b/src/xterm.c
index fb4c0c74db3..5a36aa03029 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -6714,9 +6714,9 @@ x_if_event (Display *dpy, XEvent *event_return,
6714 server timestamp TIMESTAMP. Return 0 if the necessary information 6714 server timestamp TIMESTAMP. Return 0 if the necessary information
6715 is not available. */ 6715 is not available. */
6716 6716
6717static uint64_t 6717static uint_fast64_t
6718x_sync_get_monotonic_time (struct x_display_info *dpyinfo, 6718x_sync_get_monotonic_time (struct x_display_info *dpyinfo,
6719 uint64_t timestamp) 6719 uint_fast64_t timestamp)
6720{ 6720{
6721 if (dpyinfo->server_time_monotonic_p) 6721 if (dpyinfo->server_time_monotonic_p)
6722 return timestamp; 6722 return timestamp;
@@ -6725,19 +6725,29 @@ x_sync_get_monotonic_time (struct x_display_info *dpyinfo,
6725 if (!dpyinfo->server_time_offset) 6725 if (!dpyinfo->server_time_offset)
6726 return 0; 6726 return 0;
6727 6727
6728 return timestamp - dpyinfo->server_time_offset; 6728 uint_fast64_t t;
6729 return (INT_SUBTRACT_WRAPV (timestamp, dpyinfo->server_time_offset, &t)
6730 ? 0 : t);
6729} 6731}
6730 6732
6733# ifndef CLOCK_MONOTONIC
6734# define CLOCK_MONOTONIC CLOCK_REALTIME
6735# endif
6736
6731/* Return the current monotonic time in the same format as a 6737/* Return the current monotonic time in the same format as a
6732 high-resolution server timestamp. */ 6738 high-resolution server timestamp, or 0 if not available. */
6733 6739
6734static uint64_t 6740static uint_fast64_t
6735x_sync_current_monotonic_time (void) 6741x_sync_current_monotonic_time (void)
6736{ 6742{
6737 struct timespec time; 6743 struct timespec time;
6738 6744 uint_fast64_t t;
6739 clock_gettime (CLOCK_MONOTONIC, &time); 6745 return (((clock_gettime (CLOCK_MONOTONIC, &time) != 0
6740 return time.tv_sec * 1000000 + time.tv_nsec / 1000; 6746 && (CLOCK_MONOTONIC == CLOCK_REALTIME
6747 || clock_gettime (CLOCK_REALTIME, &time) != 0))
6748 || INT_MULTIPLY_WRAPV (time.tv_sec, 1000000, &t)
6749 || INT_ADD_WRAPV (t, time.tv_nsec / 1000, &t))
6750 ? 0 : t);
6741} 6751}
6742 6752
6743/* Decode a _NET_WM_FRAME_DRAWN message and calculate the time it took 6753/* Decode a _NET_WM_FRAME_DRAWN message and calculate the time it took
@@ -6747,7 +6757,7 @@ static void
6747x_sync_note_frame_times (struct x_display_info *dpyinfo, 6757x_sync_note_frame_times (struct x_display_info *dpyinfo,
6748 struct frame *f, XEvent *event) 6758 struct frame *f, XEvent *event)
6749{ 6759{
6750 uint64_t low, high, time; 6760 uint_fast64_t low, high, time;
6751 struct x_output *output; 6761 struct x_output *output;
6752 6762
6753 low = event->xclient.data.l[2]; 6763 low = event->xclient.data.l[2];
@@ -6756,12 +6766,16 @@ x_sync_note_frame_times (struct x_display_info *dpyinfo,
6756 6766
6757 time = x_sync_get_monotonic_time (dpyinfo, low | (high << 32)); 6767 time = x_sync_get_monotonic_time (dpyinfo, low | (high << 32));
6758 6768
6759 if (time) 6769 if (!time || !output->temp_frame_time
6760 output->last_frame_time = time - output->temp_frame_time; 6770 || INT_SUBTRACT_WRAPV (time, output->temp_frame_time,
6771 &output->last_frame_time))
6772 output->last_frame_time = 0;
6761 6773
6762#ifdef FRAME_DEBUG 6774#ifdef FRAME_DEBUG
6763 fprintf (stderr, "Drawing the last frame took: %lu ms (%lu)\n", 6775 uint_fast64_t last_frame_ms = output->last_frame_time / 1000;
6764 output->last_frame_time / 1000, time); 6776 fprintf (stderr,
6777 "Drawing the last frame took: %"PRIuFAST64" ms (%"PRIuFAST64")\n",
6778 last_frame_ms, time);
6765#endif 6779#endif
6766} 6780}
6767 6781
@@ -6891,22 +6905,16 @@ x_sync_update_begin (struct frame *f)
6891static void 6905static void
6892x_sync_trigger_fence (struct frame *f, XSyncValue value) 6906x_sync_trigger_fence (struct frame *f, XSyncValue value)
6893{ 6907{
6894 uint64_t n, low, high, idx;
6895
6896 /* Sync fences aren't supported by the X server. */ 6908 /* Sync fences aren't supported by the X server. */
6897 if (FRAME_DISPLAY_INFO (f)->xsync_major < 3 6909 if (FRAME_DISPLAY_INFO (f)->xsync_major < 3
6898 || (FRAME_DISPLAY_INFO (f)->xsync_major == 3 6910 || (FRAME_DISPLAY_INFO (f)->xsync_major == 3
6899 && FRAME_DISPLAY_INFO (f)->xsync_minor < 1)) 6911 && FRAME_DISPLAY_INFO (f)->xsync_minor < 1))
6900 return; 6912 return;
6901 6913
6902 low = XSyncValueLow32 (value); 6914 bool idx = !! (XSyncValueLow32 (value) & 4);
6903 high = XSyncValueHigh32 (value);
6904
6905 n = low | (high << 32);
6906 idx = (n / 4) % 2;
6907 6915
6908#ifdef FRAME_DEBUG 6916#ifdef FRAME_DEBUG
6909 fprintf (stderr, "Triggering synchronization fence: %lu\n", idx); 6917 fprintf (stderr, "Triggering synchronization fence: %d\n", idx);
6910#endif 6918#endif
6911 6919
6912 XSyncTriggerFence (FRAME_X_DISPLAY (f), 6920 XSyncTriggerFence (FRAME_X_DISPLAY (f),
@@ -7600,9 +7608,6 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time,
7600#ifndef USE_GTK 7608#ifndef USE_GTK
7601 struct frame *focus_frame; 7609 struct frame *focus_frame;
7602 Time old_time; 7610 Time old_time;
7603#if defined HAVE_XSYNC && defined HAVE_CLOCK_GETTIME
7604 uint64_t monotonic_time;
7605#endif
7606 7611
7607 focus_frame = dpyinfo->x_focus_frame; 7612 focus_frame = dpyinfo->x_focus_frame;
7608 old_time = dpyinfo->last_user_time; 7613 old_time = dpyinfo->last_user_time;
@@ -7620,19 +7625,26 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time,
7620 { 7625 {
7621 /* See if the current CLOCK_MONOTONIC time is reasonably close 7626 /* See if the current CLOCK_MONOTONIC time is reasonably close
7622 to the X server time. */ 7627 to the X server time. */
7623 monotonic_time = x_sync_current_monotonic_time (); 7628 uint_fast64_t monotonic_time = x_sync_current_monotonic_time ();
7629 uint_fast64_t monotonic_ms = monotonic_time / 1000;
7630 int_fast64_t diff_ms;
7624 7631
7625 if (time * 1000 > monotonic_time - 500 * 1000 7632 dpyinfo->server_time_monotonic_p
7626 && time * 1000 < monotonic_time + 500 * 1000) 7633 = (monotonic_time != 0
7627 dpyinfo->server_time_monotonic_p = true; 7634 && !INT_SUBTRACT_WRAPV (time, monotonic_ms, &diff_ms)
7628 else 7635 && -500 < diff_ms && diff_ms < 500);
7636
7637 if (!dpyinfo->server_time_monotonic_p)
7629 { 7638 {
7630 /* Compute an offset that can be subtracted from the server 7639 /* Compute an offset that can be subtracted from the server
7631 time to estimate the monotonic time on the X server. */ 7640 time to estimate the monotonic time on the X server. */
7632 7641
7633 dpyinfo->server_time_monotonic_p = false; 7642 if (!monotonic_time
7634 dpyinfo->server_time_offset 7643 || INT_MULTIPLY_WRAPV (time, 1000, &dpyinfo->server_time_offset)
7635 = ((int64_t) time * 1000) - monotonic_time; 7644 || INT_SUBTRACT_WRAPV (dpyinfo->server_time_offset,
7645 monotonic_time,
7646 &dpyinfo->server_time_offset))
7647 dpyinfo->server_time_offset = 0;
7636 } 7648 }
7637 } 7649 }
7638#endif 7650#endif
diff --git a/src/xterm.h b/src/xterm.h
index 9d9675428ff..3654c3d5db1 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -828,14 +828,14 @@ struct x_display_info
828 drag-and-drop emulation. */ 828 drag-and-drop emulation. */
829 Time pending_dnd_time; 829 Time pending_dnd_time;
830 830
831#if defined HAVE_XSYNC && !defined USE_GTK 831#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
832 /* Whether or not the server time is probably the same as 832 /* Whether or not the server time is probably the same as
833 "clock_gettime (CLOCK_MONOTONIC, ...)". */ 833 "clock_gettime (CLOCK_MONOTONIC, ...)". */
834 bool server_time_monotonic_p; 834 bool server_time_monotonic_p;
835 835
836 /* The time difference between the X server clock and the monotonic 836 /* The time difference between the X server clock and the monotonic
837 clock. */ 837 clock, or 0 if unknown (FIXME: what if the difference is zero?). */
838 int64_t server_time_offset; 838 int_fast64_t server_time_offset;
839#endif 839#endif
840}; 840};
841 841
@@ -1131,10 +1131,10 @@ struct x_output
1131 bool_bf use_vsync_p : 1; 1131 bool_bf use_vsync_p : 1;
1132 1132
1133 /* The time (in microseconds) it took to draw the last frame. */ 1133 /* The time (in microseconds) it took to draw the last frame. */
1134 uint64_t last_frame_time; 1134 uint_fast64_t last_frame_time;
1135 1135
1136 /* A temporary time used to calculate that value. */ 1136 /* A temporary time used to calculate that value. */
1137 uint64_t temp_frame_time; 1137 uint_fast64_t temp_frame_time;
1138 1138
1139#ifdef HAVE_XSYNCTRIGGERFENCE 1139#ifdef HAVE_XSYNCTRIGGERFENCE
1140 /* An array of two sync fences that are triggered in order after a 1140 /* An array of two sync fences that are triggered in order after a