diff options
| author | Paul Eggert | 2022-08-23 18:18:13 -0700 |
|---|---|---|
| committer | Paul Eggert | 2022-08-25 18:30:11 -0700 |
| commit | 9bd91a3751cfb01c9499a5ee7080349b9c8f0f65 (patch) | |
| tree | 3a701007f17cd937d00ec0e844fd5426014c4efc /src | |
| parent | 97067349a8d75ab720ff2e98653a6b21f60b221e (diff) | |
| download | emacs-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.c | 76 | ||||
| -rw-r--r-- | src/xterm.h | 10 |
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 | ||
| 6717 | static uint64_t | 6717 | static uint_fast64_t |
| 6718 | x_sync_get_monotonic_time (struct x_display_info *dpyinfo, | 6718 | x_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 | ||
| 6734 | static uint64_t | 6740 | static uint_fast64_t |
| 6735 | x_sync_current_monotonic_time (void) | 6741 | x_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 | |||
| 6747 | x_sync_note_frame_times (struct x_display_info *dpyinfo, | 6757 | x_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) | |||
| 6891 | static void | 6905 | static void |
| 6892 | x_sync_trigger_fence (struct frame *f, XSyncValue value) | 6906 | x_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 |