Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-74478

mouse flicking on qtabwidget non-current tab causes segfault

    XMLWordPrintable

Details

    • macOS, Windows
    • 6736118b8 (dev), f7eb63ef4 (6.5), 1e393e82c (tqtc/lts-6.2), f4872d909 (tqtc/lts-5.15)

    Description

      Reproducible segfault from "pressing on and flicking to one side" a non current tab in a QTabWidget. Segfault happens in QTabBarPrivate::layoutTab() with index of -1 passed in.

      The backtrace is here:
      Time Awake Since Boot: 14000 seconds

      System Integrity Protection: enabled

      Crashed Thread: 0 Dispatch queue: com.apple.main-thread

      Exception Type: EXC_BAD_ACCESS (SIGSEGV)
      Exception Codes: KERN_INVALID_ADDRESS at 0x0000000400000078
      Exception Note: EXC_CORPSE_NOTIFY

      Termination Signal: Segmentation fault: 11
      Termination Reason: Namespace SIGNAL, Code 0xb
      Terminating Process: exc handler [0]

      VM Regions Near 0x400000078:
      WebKit Malloc 0000000137a00000-0000000137c00000 [ 2048K] rw-/rwx SM=PRV
      -->
      JS JIT generated code 00004b0ceb200000-00004b0ceb201000 [ 4K] ---/rwx SM=NUL
      {{
      Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
      0 org.qt-project.QtWidgets 0x000000010aa3cf19 QTabBarPrivate::layoutTab(int) + 105
      1 org.qt-project.QtWidgets 0x000000010aa42a63 QTabBar::mouseMoveEvent(QMouseEvent*) + 947
      2 org.qt-project.QtWidgets 0x000000010a8c864c QWidget::event(QEvent*) + 492
      3 org.qt-project.QtWidgets 0x000000010aa401c3 QTabBar::event(QEvent*) + 131
      4 org.qt-project.QtWidgets 0x000000010a88e9ed QApplicationPrivate::notify_helper(QObject*, QEvent*) + 269
      5 org.qt-project.QtWidgets 0x000000010a89188c QApplication::notify(QObject*, QEvent*) + 7500
      6 org.qt-project.QtCore 0x000000010e49a004 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 212
      7 org.qt-project.QtWidgets 0x000000010a88f321 QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 913
      8 org.qt-project.QtWidgets 0x000000010a8e80e2 0x10a87e000 + 434402
      9 org.qt-project.QtWidgets 0x000000010a8e6a45 0x10a87e000 + 428613
      10 org.qt-project.QtWidgets 0x000000010a88e9ed QApplicationPrivate::notify_helper(QObject*, QEvent*) + 269
      11 org.qt-project.QtWidgets 0x000000010a88fd7e QApplication::notify(QObject*, QEvent*) + 574
      12 org.qt-project.QtCore 0x000000010e49a004 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 212
      13 org.qt-project.QtGui 0x000000010ddba5e3 QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 3411
      14 org.qt-project.QtGui 0x000000010dda1cdb QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 219
      15 libqcocoa.dylib 0x0000000110eac500 0x110e80000 + 181504
      16 libqcocoa.dylib 0x0000000110eab975 0x110e80000 + 178549
      17 org.qt-project.QtCore 0x000000010e49a4f7 QCoreApplication::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 39
      18 com.sigil-ebook.Sigil.app 0x0000000109c56b98 PreviewWindow::UpdatePage(QString, QString, QList<ViewEditor::ElementIndex>) + 952
      19 com.sigil-ebook.Sigil.app 0x0000000109c2253f MainWindow::UpdatePreview() + 639
      20 org.qt-project.QtCore 0x000000010e4ca97c QMetaObject::activate(QObject*, int, int, void**) + 3132
      21 com.sigil-ebook.Sigil.app 0x0000000109c699bb TabManager::TabChanged(ContentTab*, ContentTab*) + 75
      22 com.sigil-ebook.Sigil.app 0x0000000109931712 TabManager::EmitTabChanged() + 98
      23 org.qt-project.QtCore 0x000000010e4ca97c QMetaObject::activate(QObject*, int, int, void**) + 3132
      24 org.qt-project.QtWidgets 0x000000010aa5c3cd 0x10a87e000 + 1958861
      25 org.qt-project.QtCore 0x000000010e4ca97c QMetaObject::activate(QObject*, int, int, void**) + 3132
      26 org.qt-project.QtWidgets 0x000000010aa3e166 QTabBar::setCurrentIndex(int) + 406
      27 org.qt-project.QtWidgets 0x000000010aa4252b QTabBar::mousePressEvent(QMouseEvent*) + 699
      28 com.sigil-ebook.Sigil.app 0x000000010992f0d6 TabBar::mousePressEvent(QMouseEvent*) + 342
      29 org.qt-project.QtWidgets 0x000000010a8c860d QWidget::event(QEvent*) + 429
      30 org.qt-project.QtWidgets 0x000000010aa401c3 QTabBar::event(QEvent*) + 131
      31 org.qt-project.QtWidgets 0x000000010a88e9ed QApplicationPrivate::notify_helper(QObject*, QEvent*) + 269
      32 org.qt-project.QtWidgets 0x000000010a89188c QApplication::notify(QObject*, QEvent*) + 7500
      33 org.qt-project.QtCore 0x000000010e49a004 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 212
      34 org.qt-project.QtWidgets 0x000000010a88f321 QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 913
      35 org.qt-project.QtWidgets 0x000000010a8e80e2 0x10a87e000 + 434402
      36 org.qt-project.QtWidgets 0x000000010a8e6a45 0x10a87e000 + 428613
      37 org.qt-project.QtWidgets 0x000000010a88e9ed QApplicationPrivate::notify_helper(QObject*, QEvent*) + 269
      38 org.qt-project.QtWidgets 0x000000010a88fd7e QApplication::notify(QObject*, QEvent*) + 574
      39 org.qt-project.QtCore 0x000000010e49a004 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 212
      40 org.qt-project.QtGui 0x000000010ddba5e3 QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 3411
      41 org.qt-project.QtGui 0x000000010dda1cdb QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 219
      42 libqcocoa.dylib 0x0000000110eac500 0x110e80000 + 181504
      43 libqcocoa.dylib 0x0000000110eacd70 0x110e80000 + 183664
      44 com.apple.CoreFoundation 0x00007fff4c2d28f1 _CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION_ + 17
      45 com.apple.CoreFoundation 0x00007fff4c38c30c __CFRunLoopDoSource0 + 108
      46 com.apple.CoreFoundation 0x00007fff4c2b5350 __CFRunLoopDoSources0 + 208
      47 com.apple.CoreFoundation 0x00007fff4c2b47cd __CFRunLoopRun + 1293
      48 com.apple.CoreFoundation 0x00007fff4c2b4033 CFRunLoopRunSpecific + 483
      49 com.apple.HIToolbox 0x00007fff4b59ed96 RunCurrentEventLoopInMode + 286
      50 com.apple.HIToolbox 0x00007fff4b59ea0f ReceiveNextEventCommon + 366
      51 com.apple.HIToolbox 0x00007fff4b59e884 _BlockUntilNextEventMatchingListInModeWithFilter + 64
      52 com.apple.AppKit 0x00007fff4984ea73 _DPSNextEvent + 2085
      53 com.apple.AppKit 0x00007fff49fe4e34 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 3044
      54 com.apple.AppKit 0x00007fff49843885 -[NSApplication run] + 764
      55 libqcocoa.dylib 0x0000000110eabc17 0x110e80000 + 179223
      56 org.qt-project.QtCore 0x000000010e49565f QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 431
      57 org.qt-project.QtCore 0x000000010e49a612 QCoreApplication::exec() + 130
      58 com.sigil-ebook.Sigil.app 0x000000010992b9aa main + 5146
      59 libdyld.dylib 0x00007fff741e6015 start + 1
      }}

      When flicking on a non-current tab, the mouse button press is properly detected and the tab "flicked" on becomes the current tb (see QTabBar::setCurrentIndex in the backtrace) which does an EmitTabChanged() which in our app is used to load a QWebView in a separate "preview" window with the selected tab contents. During this load initiated by the signal, a wait loop for the load is used in which a call to processEvents is done. This results in a mouseMoveEvent being detected and processed by the QTabBar in its mouseMoveEvent routine. That routine skips most everything except for the call to layoutTab() but it consistently is passing in an index of -1.

      Since this is in release mode, the QAssert(index >= 0) in QTabBarPrivate::layoutTab() does not fire and the result is a nasty segfault.

      All that said, the following simple patch to QTabBarPrivate::layoutTab(, seems to reliably prevent the segfault and any other damage.

      {{--- qtbase/src/widgets/widgets/qtabbar.cpp.orig 2019-03-14 18:56:40.000000000 -0400
      +++ qtbase/src/widgets/widgets/qtabbar.cpp 2019-03-14 18:58:29.000000000 -0400
      @@ -721,6 +721,8 @@
      {
      Q_Q(QTabBar);
      Q_ASSERT(index >= 0);
      + // to be safe
      + if (index < 0) return;

      Tab &tab = tabList[index];
      bool vertical = verticalTabs(shape);
      }}

      An alternative change could be used in QTabBar's mousemoveEvent handler to prevent the call to layoutTab() if the index to be passed in is negative.

      It is interesting to note that the "if" 0 code that was Mac specific from Qt 4 in qtabbar.cpp would seem to be seeing the same possibility of a negative 1 index being passed around.

      The "flicking" happened by accident on a touchpad and with a mouse, but for stability reasons, the resulting segfault is undesirable.

      Please consider including this or a better patch into Qt 5.12.3

      Attachments

        For Gerrit Dashboard: QTBUG-74478
        # Subject Branch Project Status CR V

        Activity

          People

            qt.team.quick.subscriptions Qt Quick and Widgets Team
            kevinhendricks Kevin B. Hendricks
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews