File 0001-xcb-prevent-crash-with-pixmap-cursors-on-XRender-less-system.patch of Package libqt5-qtbase.18762
From: Max Lin <mlin@suse.com>
Date: Tue, 25 Sep 2018 15:50:31 +0800
Subject: [PATCH] xcb: prevent crash with pixmap cursors on XRender-less X
servers
This is a backport of 6c10c54aa805f79100a29b0648be51d8af41f26a and
d5ac11891d8237ca2f02390ffd0ff103578b520e.
We were using xcb_render_* APIs without checking if the server even
supports this extension. Attempting to use an extension which is
not present will always result in a crash. This patch adds the required
guards and refactors how we detect presence of XRender extension.
Also instead of falling back to some odd-looking bitmapped version
just leave the current cursor unchanged. That is how we did it in
Qt4 AFAICT.
Task-number: QTBUG-66935
---
src/plugins/platforms/xcb/qxcbconnection.cpp | 11 ++++++++---
src/plugins/platforms/xcb/qxcbconnection.h | 10 +++++++++-
src/plugins/platforms/xcb/qxcbcursor.cpp | 15 +++++++++++----
3 files changed, 28 insertions(+), 8 deletions(-)
Index: qtbase-opensource-src-5.9.4/src/plugins/platforms/xcb/qxcbconnection.cpp
===================================================================
--- qtbase-opensource-src-5.9.4.orig/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ qtbase-opensource-src-5.9.4/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -556,6 +556,7 @@ QXcbConnection::QXcbConnection(QXcbNativ
, m_defaultVisualId(defaultVisualId)
, m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
, m_nativeInterface(nativeInterface)
+ , has_render_extension(false)
{
#if QT_CONFIG(xcb_xlib)
Display *dpy = XOpenDisplay(m_displayName.constData());
@@ -1223,7 +1224,7 @@ void QXcbConnection::handleXcbEvent(xcb_
}
if (!handled) {
- if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
+ if (has_xfixes && response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
xcb_xfixes_selection_notify_event_t *notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event);
setTime(notify_event->timestamp);
#ifndef QT_NO_CLIPBOARD
@@ -2059,7 +2060,6 @@ void QXcbConnection::initializeXFixes()
if (!reply || !reply->present)
return;
- xfixes_first_event = reply->first_event;
xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection,
XCB_XFIXES_MAJOR_VERSION,
XCB_XFIXES_MINOR_VERSION);
@@ -2068,8 +2068,10 @@ void QXcbConnection::initializeXFixes()
if (!xfixes_query || error || xfixes_query->major_version < 2) {
qWarning("QXcbConnection: Failed to initialize XFixes");
free(error);
- xfixes_first_event = 0;
+ return;
}
+ xfixes_first_event = reply->first_event;
+ has_xfixes = true;
free(xfixes_query);
}
@@ -2077,8 +2079,10 @@ void QXcbConnection::initializeXRender()
{
#if QT_CONFIG(xcb_render)
const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_render_id);
- if (!reply || !reply->present)
+ if (!reply || !reply->present) {
+ qDebug("XRender extension not present on the X server");
return;
+ }
xcb_generic_error_t *error = 0;
xcb_render_query_version_cookie_t xrender_query_cookie = xcb_render_query_version(m_connection,
@@ -2086,10 +2090,14 @@ void QXcbConnection::initializeXRender()
XCB_RENDER_MINOR_VERSION);
xcb_render_query_version_reply_t *xrender_query = xcb_render_query_version_reply(m_connection,
xrender_query_cookie, &error);
- if (!xrender_query || error || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) {
- qWarning("QXcbConnection: Failed to initialize XRender");
+ if (!xrender_query) {
+ qWarning("xcb_render_query_version failed");
free(error);
+ return;
}
+ has_render_extension = true;
+ m_xrenderVersion.first = xrender_query->major_version;
+ m_xrenderVersion.second = xrender_query->minor_version;
free(xrender_query);
#endif
}
Index: qtbase-opensource-src-5.9.4/src/plugins/platforms/xcb/qxcbconnection.h
===================================================================
--- qtbase-opensource-src-5.9.4.orig/src/plugins/platforms/xcb/qxcbconnection.h
+++ qtbase-opensource-src-5.9.4/src/plugins/platforms/xcb/qxcbconnection.h
@@ -464,11 +464,18 @@ public:
inline xcb_timestamp_t netWmUserTime() const { return m_netWmUserTime; }
inline void setNetWmUserTime(xcb_timestamp_t t) { if (t > m_netWmUserTime) m_netWmUserTime = t; }
- bool hasXFixes() const { return xfixes_first_event > 0; }
+ bool hasXFixes() const { return has_xfixes; }
bool hasXShape() const { return has_shape_extension; }
bool hasXRandr() const { return has_randr_extension; }
bool hasInputShape() const { return has_input_shape; }
bool hasXKB() const { return has_xkb; }
+ bool hasXRender(int major = -1, int minor = -1) const
+ {
+ if (has_render_extension && major != -1 && minor != -1)
+ return m_xrenderVersion >= qMakePair(major, minor);
+
+ return has_render_extension;
+ }
bool supportsThreadedRendering() const { return m_reader->isRunning(); }
bool threadedEventHandling() const { return m_reader->isRunning(); }
@@ -674,11 +681,15 @@ private:
uint32_t xrandr_first_event = 0;
uint32_t xkb_first_event = 0;
+ bool has_xfixes = false;
bool has_xinerama_extension = false;
bool has_shape_extension = false;
bool has_randr_extension = false;
bool has_input_shape;
bool has_xkb = false;
+ bool has_render_extension = false;
+
+ QPair<int, int> m_xrenderVersion;
Qt::MouseButtons m_buttons = 0;
Index: qtbase-opensource-src-5.9.4/src/plugins/platforms/xcb/qxcbcursor.cpp
===================================================================
--- qtbase-opensource-src-5.9.4.orig/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ qtbase-opensource-src-5.9.4/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -607,12 +607,19 @@ xcb_cursor_t QXcbCursor::createFontCurso
xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
{
- xcb_connection_t *conn = xcb_connection();
QPoint spot = cursor->hotSpot();
xcb_cursor_t c = XCB_NONE;
- if (cursor->pixmap().depth() > 1)
- c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot);
- if (!c) {
+ if (cursor->pixmap().depth() > 1) {
+#if QT_CONFIG(xcb_render)
+ if (connection()->hasXRender(0, 5))
+ c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot);
+ else
+ qWarning("xrender >= 0.5 required to create pixmap cursors");
+#else
+ qWarning("This build of Qt does not support pixmap cursors");
+#endif
+ } else {
+ xcb_connection_t *conn = xcb_connection();
xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage());
xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->toImage());
c = xcb_generate_id(conn);