From f197456481ef799b38ce37a7462e898214d6d899 Mon Sep 17 00:00:00 2001 From: David Faure Date: Wed, 19 Mar 2025 00:39:20 +0100 Subject: [PATCH] Don't call elapsed() on an invalid QElapsedTimer It's UB, and it returns garbage. In QWaylandWindow::timerEvent the value was unused if the timer was invalid (but that was tested only later). In QWaylandInputDevice / QWaylandTabletToolV2 however the garbage value was passed on to wl_cursor_frame_and_duration. Testcase: running tests/auto/client/client/tst_client and tests/auto/client/tabletv2/tst_tabletv2 in a UBSAN build. Pick-to: 6.9 6.8 6.5 Change-Id: Ie0f8610bbca49913942b2247d3e968197e12f47e Reviewed-by: Konstantin Ritt --- src/plugins/platforms/wayland/qwaylandinputdevice.cpp | 3 ++- src/plugins/platforms/wayland/qwaylandtabletv2.cpp | 3 ++- src/plugins/platforms/wayland/qwaylandwindow.cpp | 7 ++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp index dfd87bdec6f..9224e5fb43f 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -245,7 +245,8 @@ void QWaylandInputDevice::Pointer::updateCursor() return; // Set from shape using theme - uint time = seat()->mCursor.animationTimer.elapsed(); + const QElapsedTimer &timer = seat()->mCursor.animationTimer; + const uint time = timer.isValid() ? timer.elapsed() : 0; if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) { uint duration = 0; diff --git a/src/plugins/platforms/wayland/qwaylandtabletv2.cpp b/src/plugins/platforms/wayland/qwaylandtabletv2.cpp index 3cfcdfe7d00..8973d67b72f 100644 --- a/src/plugins/platforms/wayland/qwaylandtabletv2.cpp +++ b/src/plugins/platforms/wayland/qwaylandtabletv2.cpp @@ -113,7 +113,8 @@ void QWaylandTabletToolV2::updateCursor() return; // Set from shape using theme - uint time = m_tabletSeat->seat()->mCursor.animationTimer.elapsed(); + QElapsedTimer &timer = m_tabletSeat->seat()->mCursor.animationTimer; + const uint time = timer.isValid() ? timer.elapsed() : 0; if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) { uint duration = 0; diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index 92a338663d8..a1534c0b0ff 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -1682,12 +1682,13 @@ void QWaylandWindow::timerEvent(QTimerEvent *event) { QMutexLocker lock(&mFrameSyncMutex); - bool callbackTimerExpired = mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout); - if (!mFrameCallbackElapsedTimer.isValid() || callbackTimerExpired ) { + const bool callbackTimerValid = mFrameCallbackElapsedTimer.isValid(); + const bool callbackTimerExpired = callbackTimerValid && mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout); + if (!callbackTimerValid || callbackTimerExpired) { killTimer(mFrameCallbackCheckIntervalTimerId); mFrameCallbackCheckIntervalTimerId = -1; } - if (!mFrameCallbackElapsedTimer.isValid() || !callbackTimerExpired) { + if (!callbackTimerValid || !callbackTimerExpired) { return; } mFrameCallbackElapsedTimer.invalidate();