[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#970641: libqtgui4: QDialog randomly misplaced invisible in buster, patches



Package: libqtgui4
Version: 4:4.8.7+dfsg-18
Severity: normal
Tags: patch


Introduction:

After migrating a legacy application from jessie to buster without making major
changes we experienced QDialogs and QMessageBoxes randomly showing up outside
the visible area.
In most of the occurences the invisible dialog didn't have focus despite being
modal, rendering the GUI frozen from the user's perspective.


Bugs:

We finally tracked it down to QDesktopWidget::availableGeometry(int screen)
parsing the response of XGetWindowProperty(_NET_WORKAREA) as array of 4 64 bit
integers despite format==32 clearly guaranteeing 32 bit integers.

This 'compresses' the 4 good values received in the first 2 values of the QRect
workArea c'tor, x and y, and pulls random memory content in the other 2 values,
width and heigth.

As a consequence QMessageBoxPrivate::updateSize() calculated hardLimit,
softLimit, width and height to crazy negative values like -123456789.
That whole method, QMessageBoxPrivate::updateSize(), has some wild heuristics
and should not use negative values, but that's not the root cause.

Depending on the window manager and system configuration the bad code path in
QDesktopWidget::availableGeometry(int) might be used or not.
It's always used in our customer's setup that facilitates   matchbox-window-
manager -use_titlebar no   for a kiosk-like user experience.


Patches:

Our main patch, qdesktopwidget_fix_availableGeometry.diff, fixes the main error
described above, in src/gui/kernel/qdesktopwidget_x11.cpp:304.

Our side patch qmessagebox_ironize_updatesize.diff makes
QMessageBoxPrivate::updateSize() ignore non-positive softLimits and hardLimits.
We're not 100% sure it's a good idea to apply that. Concerns
src/gui/dialogs/qmessagebox.cpp lines 345, 349, 375, 390.


Non-Patches:

On the assumption that such code is often copied'n'change we grepped for other
uses of XGetWindowProperty() (there are 51), quickly (not too thouroghly)
checked for similar mistakes and found serveral suspicious blocks of code.
This was done after 'apt-get source qt4-x11' to *.cpp under
qt4-x11-4.8.7+dfsg/src/, i.e. after debian patches have been applied to the
source code. Line numbers in upstream tarball might differ.

In QETWidget::translatePropertyEvent(),
  src/gui/kernel/qapplication_x11.cpp:5008ff
XGetWindowProperty(_KDE_NET_WM_FRAME_STRUT) seems to make a similar mistake,
but I haven't researched wether the contradiction between '// struts are 4
longs' and the check 'format == 32' is a bug or maybe a legitimate-ish hack.

Other XGetWindowProperty() calls with suspicious result processing can be found
in
  src/gui/kernel/qapplication_x11.cpp:2831, which someone has thought about
with // quint32, but seems not in use
  src/gui/kernel/qapplication_x11.cpp:5027
  src/gui/kernel/qapplication_x11.cpp:5106
  src/gui/kernel/qapplication_x11.cpp:5165
  src/gui/kernel/qx11embed_x11.cpp:415
  src/gui/kernel/qx11embed_x11.cpp:829
  src/gui/kernel/qx11embed_x11.cpp:1673


Patched amd64 packages:

Packages that include our 2 patches can be found on https://deb.clazzes.org/debian/pool/buster-xpkg-1/

To use them with apt or the like perform something like this:
  wget -O /etc/apt/trusted.gpg.d/pba-archiver.clazzes.org.gpg https://deb.clazzes.org/gpg/pba-archiver.clazzes.org.gpg
  cd /etc/apt/sources.list.d
  wget https://deb.clazzes.org/debian/sources.list.d/buster/buster-xpkg-1.list
  apt-get update
  apt-get upgrade

We'd be willing to add armhf packages if anyone's interested.
Our clean room build infrastructure has been relieved from i386 and we don't support other archs.


Regards, Christoph Lechleitner


-- 

Christoph Lechleitner

Geschäftsführung

------------------------------------------------------------------------
ITEG IT-Engineers GmbH | Salurner Straße 18, A-6020 Innsbruck
FN 365826f | Handelsgericht Innsbruck | Mobiltelefon: +43 676 3674710
Mail: christoph.lechleitner@iteg.at | Web: http://www.iteg.at/
------------------------------------------------------------------------

--- qt4-x11-4.8.7+dfsg.orig/src/gui/kernel/qdesktopwidget_x11.cpp	2015-05-07 16:14:43.000000000 +0200
+++ qt4-x11-4.8.7+dfsg/src/gui/kernel/qdesktopwidget_x11.cpp	2020-09-20 15:49:52.089122544 +0200
@@ -301,7 +301,8 @@
         QRect workArea;
         if (e == Success && ret == XA_CARDINAL &&
             format == 32 && nitems == 4) {
-            long *workarea = (long *) data;
+            //long *workarea = (long *) data;
+            qint32 *workarea = (qint32 *) data;
             workArea = QRect(workarea[0], workarea[1], workarea[2], workarea[3]);
         } else {
             workArea = screenGeometry(screen);
--- qt4-x11-4.8.7+dfsg.orig/src/gui/dialogs/qmessagebox.cpp	2015-05-07 16:14:43.000000000 +0200
+++ qt4-x11-4.8.7+dfsg/src/gui/dialogs/qmessagebox.cpp	2020-09-20 15:49:20.787609493 +0200
@@ -342,11 +342,11 @@
     label->setWordWrap(false); // makes the label return min size
     int width = layoutMinimumWidth();
 
-    if (width > softLimit) {
+    if ((softLimit > 0) && (width > softLimit)) {
         label->setWordWrap(true);
         width = qMax(softLimit, layoutMinimumWidth());
 
-        if (width > hardLimit) {
+        if ((hardLimit > 0) && (width > hardLimit)) {
             label->d_func()->ensureTextControl();
             if (QTextControl *control = label->d_func()->control) {
                 QTextOption opt = control->document()->defaultTextOption();
@@ -372,7 +372,7 @@
         policy.setHeightForWidth(true);
         informativeLabel->setSizePolicy(policy);
         width = qMax(width, layoutMinimumWidth());
-        if (width > hardLimit) { // longest word is really big, so wrap anywhere
+        if ((hardLimit > 0) && (width > hardLimit)) { // longest word is really big, so wrap anywhere
             informativeLabel->d_func()->ensureTextControl();
             if (QTextControl *control = informativeLabel->d_func()->control) {
                 QTextOption opt = control->document()->defaultTextOption();
@@ -386,7 +386,10 @@
     }
 
     QFontMetrics fm(QApplication::font("QWorkspaceTitleBar"));
-    int windowTitleWidth = qMin(fm.width(q->windowTitle()) + 50, hardLimit);
+    int windowTitleWidth = fm.width(q->windowTitle()) + 50;
+    if (hardLimit > 0) {
+        windowTitleWidth = qMin(fm.width(q->windowTitle()) + 50, hardLimit);
+    }
     if (windowTitleWidth > width)
         width = windowTitleWidth;
 

Reply to: