Make QGuiApplicationPrivate::lastCursorPosition.toPoint() safe to use

QGuiApplicationPrivate::lastCursorPosition is initialized with qInf();
so before Qt has seen a mouse move event, attempting to convert to
QPoint is an error. It's best to have one place where we do the qIsInf()
check rather than several (and otherwise prefer using the QPointF as-is
rather than converting to QPoint at all).

Introduce a helper class that contains a QPointF, and provides a safe
conversion to QPoint, as well as simple accessors for clients using
QPointF.

Fixes: QTBUG-52472
Task-number: QTBUG-45045
Change-Id: I83fad1bfb658e03fa876344552f1d5bb751d9f81
Pick-to: 6.2 6.3
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Shawn Rutledge 2022-02-01 07:56:23 +01:00 committed by Volker Hilsheimer
parent 29a7489769
commit c5792dcfd6
3 changed files with 26 additions and 4 deletions

View File

@ -130,6 +130,7 @@
#include <qtgui_tracepoints_p.h>
#include <ctype.h>
#include <limits>
QT_BEGIN_NAMESPACE
@ -147,7 +148,7 @@ Q_GUI_EXPORT bool qt_is_tty_app = false;
Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
Qt::KeyboardModifiers QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
QPointF QGuiApplicationPrivate::lastCursorPosition(qt_inf(), qt_inf());
QGuiApplicationPrivate::QLastCursorPosition QGuiApplicationPrivate::lastCursorPosition;
QWindow *QGuiApplicationPrivate::currentMouseWindow = nullptr;
@ -711,7 +712,7 @@ QGuiApplication::~QGuiApplication()
QGuiApplicationPrivate::desktopFileName = nullptr;
QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
QGuiApplicationPrivate::lastCursorPosition = {qreal(qInf()), qreal(qInf())};
QGuiApplicationPrivate::lastCursorPosition.reset();
QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr;
QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
QGuiApplicationPrivate::currentDragWindow = nullptr;
@ -4144,6 +4145,14 @@ QPixmap QGuiApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
return QPixmap();
}
QPoint QGuiApplicationPrivate::QLastCursorPosition::toPoint() const noexcept
{
// Guard against the default initialization of qInf() (avoid UB or SIGFPE in conversion).
if (Q_UNLIKELY(qIsInf(thePoint.x())))
return QPoint(std::numeric_limits<int>::max(), std::numeric_limits<int>::max());
return thePoint.toPoint();
}
void QGuiApplicationPrivate::notifyThemeChanged()
{
updatePalette();

View File

@ -60,6 +60,7 @@
#include <QtCore/qnativeinterface.h>
#include <QtCore/private/qnativeinterface_p.h>
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/private/qthread_p.h>
#include <qpa/qwindowsysteminterface.h>
@ -227,7 +228,19 @@ public:
virtual bool closeAllPopups() { return false; }
static Qt::MouseButton mousePressButton;
static QPointF lastCursorPosition;
static struct QLastCursorPosition {
constexpr inline QLastCursorPosition() noexcept : thePoint(qt_inf(), qt_inf()) {}
constexpr inline Q_IMPLICIT QLastCursorPosition(QPointF p) noexcept : thePoint(p) {}
constexpr inline Q_IMPLICIT operator QPointF() const noexcept { return thePoint; }
constexpr inline qreal x() const noexcept{ return thePoint.x(); }
constexpr inline qreal y() const noexcept{ return thePoint.y(); }
Q_GUI_EXPORT QPoint toPoint() const noexcept;
constexpr void reset() noexcept { *this = QLastCursorPosition{}; }
private:
QPointF thePoint;
} lastCursorPosition;
static QWindow *currentMouseWindow;
static QWindow *currentMousePressWindow;
static Qt::ApplicationState applicationState;

View File

@ -402,7 +402,7 @@ void QWidgetWindow::handleEnterLeaveEvent(QEvent *event)
QWindowSystemInterfacePrivate::EnterEvent *systemEvent =
static_cast<QWindowSystemInterfacePrivate::EnterEvent *>
(QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::Enter));
const QPointF globalPosF = systemEvent ? systemEvent->globalPos : QGuiApplicationPrivate::lastCursorPosition;
const QPointF globalPosF = systemEvent ? systemEvent->globalPos : QPointF(QGuiApplicationPrivate::lastCursorPosition);
if (systemEvent) {
if (QWidgetWindow *enterWindow = qobject_cast<QWidgetWindow *>(systemEvent->enter))
{