Details
-
Bug
-
Resolution: Invalid
-
P1: Critical
-
5.11.1, 5.11.2, 5.11.3, 5.12.0, 5.12.1
-
None
-
Windows and Mac OS X 10.13.6 and later, have not tried earlier versions of the OS
-
-
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 |
467782,2 | Guard QTabBar against nested event processing during moving tabs | dev | qt/qtbase | Status: MERGED | +2 | 0 |
469404,2 | Guard QTabBar against nested event processing during moving tabs | 6.5 | qt/qtbase | Status: MERGED | +2 | 0 |
469408,2 | Guard QTabBar against nested event processing during moving tabs | tqtc/lts-6.2 | qt/tqtc-qtbase | Status: MERGED | +2 | 0 |
469409,2 | Guard QTabBar against nested event processing during moving tabs | tqtc/lts-5.15 | qt/tqtc-qtbase | Status: MERGED | +2 | 0 |