I am working on developing a big project that cannot share the source code. In that project, we are getting some poorly reproducible stack overflow errors in windows (not in ubuntu) and the stack trace of the debugger shows that the progress dialog set to window modal, is calling QProgressDialog::setValue(int) recursively.
I have created this small example of a QProgressDialog to try to reproduce the error. Although I have not gotten into a stack overflow error using this example (neither in Windows or Ubuntu), when I look into QProgressDailog::setValue by adding a breakpoint in the debugger, I see that it also calls itself recursively (in both OS), just not enough times to produce the stack overflow. The most impressive thing is that sometimes it does call the QPrigressDialog::setValue only once.
See an example of the call stack or windows:
Qt5Widgets.dll!QProgressDialog::setValue(int progress) Line 653 C++
[Inline Frame] Qt5Core.dll!QtPrivate::QSlotObjectBase::call(QObject *) Line 398 C++
Qt5Core.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 626 C++
Qt5Core.dll!QObject::event(QEvent * e) Line 1339 C++
Qt5Widgets.dll!QWidget::event(QEvent * event) Line 9094 C++
Qt5Widgets.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3687 C++
Qt5Widgets.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3639 C++
Qt5Core.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1075 C++
[Inline Frame] Qt5Core.dll!QCoreApplication::sendEvent(QObject *) Line 1470 C++
Qt5Core.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1815 C++
qwindows.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 82 C++
Qt5Core.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 525 C++
qwindows.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 75 C++
Qt5Widgets.dll!QProgressDialog::setValue(int progress) Line 663 C++
[Inline Frame] Qt5Core.dll!QtPrivate::QSlotObjectBase::call(QObject *) Line 398 C++
Qt5Core.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 626 C++
Qt5Core.dll!QObject::event(QEvent * e) Line 1339 C++
Qt5Widgets.dll!QWidget::event(QEvent * event) Line 9094 C++
Qt5Widgets.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3687 C++
Qt5Widgets.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3639 C++
Qt5Core.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1075 C++
[Inline Frame] Qt5Core.dll!QCoreApplication::sendEvent(QObject *) Line 1470 C++
Qt5Core.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1815 C++
qwindows.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 82 C++
Qt5Core.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 525 C++
qwindows.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 75 C++
Qt5Widgets.dll!QProgressDialog::setValue(int progress) Line 663 C++
[Inline Frame] Qt5Core.dll!QtPrivate::QSlotObjectBase::call(QObject *) Line 398 C++
Qt5Core.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 626 C++
Qt5Core.dll!QObject::event(QEvent * e) Line 1339 C++
Qt5Widgets.dll!QWidget::event(QEvent * event) Line 9094 C++
Qt5Widgets.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3687 C++
Qt5Widgets.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3639 C++
Qt5Core.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1075 C++
[Inline Frame] Qt5Core.dll!QCoreApplication::sendEvent(QObject *) Line 1470 C++
Qt5Core.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1815 C++
qwindows.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 82 C++
Qt5Core.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 525 C++
qwindows.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 75 C++
Qt5Widgets.dll!QProgressDialog::setValue(int progress) Line 663 C++
[Inline Frame] Qt5Core.dll!QtPrivate::QSlotObjectBase::call(QObject *) Line 398 C++
Qt5Core.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 626 C++
Qt5Core.dll!QObject::event(QEvent * e) Line 1339 C++
Qt5Widgets.dll!QWidget::event(QEvent * event) Line 9094 C++
Qt5Widgets.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3687 C++
Qt5Widgets.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3639 C++
Qt5Core.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1075 C++
[Inline Frame] Qt5Core.dll!QCoreApplication::sendEvent(QObject *) Line 1470 C++
Qt5Core.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1815 C++
qwindows.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 82 C++
Qt5Core.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 525 C++
qwindows.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 75 C++
Qt5Widgets.dll!QProgressDialog::setValue(int progress) Line 663 C++
[Inline Frame] Qt5Core.dll!QtPrivate::QSlotObjectBase::call(QObject *) Line 398 C++
Qt5Core.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 626 C++
Qt5Core.dll!QObject::event(QEvent * e) Line 1339 C++
Qt5Widgets.dll!QWidget::event(QEvent * event) Line 9094 C++
Qt5Widgets.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3687 C++
Qt5Widgets.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3639 C++
Qt5Core.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1075 C++
[Inline Frame] Qt5Core.dll!QCoreApplication::sendEvent(QObject *) Line 1470 C++
Qt5Core.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1815 C++
qwindows.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 82 C++
Qt5Core.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 525 C++
qwindows.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 75 C++
Qt5Widgets.dll!QProgressDialog::setValue(int progress) Line 663 C++
[Inline Frame] Qt5Core.dll!QtPrivate::QSlotObjectBase::call(QObject *) Line 398 C++
Qt5Core.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 626 C++
Qt5Core.dll!QObject::event(QEvent * e) Line 1339 C++
Qt5Widgets.dll!QWidget::event(QEvent * event) Line 9094 C++
Qt5Widgets.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3687 C++
Qt5Widgets.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3639 C++
Qt5Core.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1075 C++
[Inline Frame] Qt5Core.dll!QCoreApplication::sendEvent(QObject *) Line 1470 C++
Qt5Core.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1815 C++
qwindows.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 82 C++
Qt5Core.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 525 C++
qwindows.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 75 C++
Qt5Widgets.dll!QProgressDialog::setValue(int progress) Line 663 C++
[Inline Frame] Qt5Core.dll!QtPrivate::QSlotObjectBase::call(QObject *) Line 398 C++
Qt5Core.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 626 C++
Qt5Core.dll!QObject::event(QEvent * e) Line 1339 C++
Qt5Widgets.dll!QWidget::event(QEvent * event) Line 9094 C++
Qt5Widgets.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3687 C++
Qt5Widgets.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3639 C++
Qt5Core.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1075 C++
[Inline Frame] Qt5Core.dll!QCoreApplication::sendEvent(QObject *) Line 1470 C++
Qt5Core.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1815 C++
qwindows.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 82 C++
Qt5Core.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 525 C++
qwindows.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 75 C++
[Inline Frame] Qt5Core.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag>) Line 138 C++
Qt5Core.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 225 C++
Qt5Core.dll!QCoreApplication::exec() Line 1383 C++
progress_bar.exe!main(int argc, char * * argv) Line 9 C++
[External Code]
See an example of the call stack on ubuntu:
#0 0x00007ffff76fa330 in QProgressDialog::setValue(int) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#1 0x00007ffff60a3dec in QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<int>, void, void (QProgressDialog::*)(int)>::call(void (QProgressDialog::*)(int), QProgressDialog*, void**) ()
at /home/apalomer/programming_workspace/progress_bar_example/build/libthreadedworker.so
#2 0x00007ffff60a3ba4 in void QtPrivate::FunctionPointer<void (QProgressDialog::*)(int)>::call<QtPrivate::List<int>, void>(void (QProgressDialog::*)(int), QProgressDialog*, void**) ()
at /home/apalomer/programming_workspace/progress_bar_example/build/libthreadedworker.so
#3 0x00007ffff60a3759 in QtPrivate::QSlotObject<void (QProgressDialog::*)(int), QtPrivate::List<int>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) ()
at /home/apalomer/programming_workspace/progress_bar_example/build/libthreadedworker.so
#4 0x00007ffff6ef30c2 in QObject::event(QEvent*) (this=0x555555b74610, e=<optimized out>) at kernel/qobject.cpp:1247
#5 0x00007ffff751775b in QWidget::event(QEvent*) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#6 0x00007ffff74d883c in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#7 0x00007ffff74e0104 in QApplication::notify(QObject*, QEvent*) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#8 0x00007ffff6ec38d8 in QCoreApplication::notifyInternal2(QObject*, QEvent*) (receiver=0x555555b74610, event=event@entry=0x7fffc80037a0) at kernel/qcoreapplication.cpp:1024
#9 0x00007ffff6ec604d in QCoreApplication::sendEvent(QObject*, QEvent*) (event=0x7fffc80037a0, receiver=<optimized out>) at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:233
#10 0x00007ffff6ec604d in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (receiver=receiver@entry=0x0, event_type=event_type@entry=0, data=0x55555576fef0)
at kernel/qcoreapplication.cpp:1699
#11 0x00007ffff6ec65d8 in QCoreApplication::sendPostedEvents(QObject*, int) (receiver=receiver@entry=0x0, event_type=event_type@entry=0) at kernel/qcoreapplication.cpp:1553
#12 0x00007ffff6f1d263 in postEventSourceDispatch(GSource*, GSourceFunc, gpointer) (s=0x5555558952a0) at kernel/qeventdispatcher_glib.cpp:276
#13 0x00007ffff4221417 in g_main_context_dispatch () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#14 0x00007ffff4221650 in () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#15 0x00007ffff42216dc in g_main_context_iteration () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#16 0x00007ffff6f1c88f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (this=0x5555558d2b80, flags=...) at kernel/qeventdispatcher_glib.cpp:423
#17 0x00007ffff76fa4c7 in QProgressDialog::setValue(int) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#18 0x00007ffff60a3dec in QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<int>, void, void (QProgressDialog::*)(int)>::call(void (QProgressDialog::*)(int), QProgressDialog*, void**) ()
at /home/apalomer/programming_workspace/progress_bar_example/build/libthreadedworker.so
#19 0x00007ffff60a3ba4 in void QtPrivate::FunctionPointer<void (QProgressDialog::*)(int)>::call<QtPrivate::List<int>, void>(void (QProgressDialog::*)(int), QProgressDialog*, void**) ()
at /home/apalomer/programming_workspace/progress_bar_example/build/libthreadedworker.so
#20 0x00007ffff60a3759 in QtPrivate::QSlotObject<void (QProgressDialog::*)(int), QtPrivate::List<int>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) ()
at /home/apalomer/programming_workspace/progress_bar_example/build/libthreadedworker.so
#21 0x00007ffff6ef30c2 in QObject::event(QEvent*) (this=0x555555b74610, e=<optimized out>) at kernel/qobject.cpp:1247
#22 0x00007ffff751775b in QWidget::event(QEvent*) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#23 0x00007ffff74d883c in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#24 0x00007ffff74e0104 in QApplication::notify(QObject*, QEvent*) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#25 0x00007ffff6ec38d8 in QCoreApplication::notifyInternal2(QObject*, QEvent*) (receiver=0x555555b74610, event=event@entry=0x7fffc8002ef0) at kernel/qcoreapplication.cpp:1024
#26 0x00007ffff6ec604d in QCoreApplication::sendEvent(QObject*, QEvent*) (event=0x7fffc8002ef0, receiver=<optimized out>) at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:233
#27 0x00007ffff6ec604d in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (receiver=receiver@entry=0x0, event_type=event_type@entry=0, data=0x55555576fef0)
at kernel/qcoreapplication.cpp:1699
#28 0x00007ffff6ec65d8 in QCoreApplication::sendPostedEvents(QObject*, int) (receiver=receiver@entry=0x0, event_type=event_type@entry=0) at kernel/qcoreapplication.cpp:1553
#29 0x00007ffff6f1d263 in postEventSourceDispatch(GSource*, GSourceFunc, gpointer) (s=0x5555558952a0) at kernel/qeventdispatcher_glib.cpp:276
#30 0x00007ffff4221417 in g_main_context_dispatch () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#31 0x00007ffff4221650 in () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#32 0x00007ffff42216dc in g_main_context_iteration () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#33 0x00007ffff6f1c88f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (this=0x5555558d2b80, flags=...) at kernel/qeventdispatcher_glib.cpp:423
#34 0x00007ffff6ec190a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) (this=this@entry=0x7fffffffcfb0, flags=..., flags@entry=...) at kernel/qeventloop.cpp:212
#35 0x00007ffff6eca9b4 in QCoreApplication::exec() () at kernel/qcoreapplication.cpp:1297
#36 0x0000555555554cb4 in main ()
Any ideas on how to fix this recursion? Should I move it to a bug report? It happens especially if I manually step through the program.
I have tested this in Windows 10, Visual Studio 16.5.2, MSVC 19.25.28612.0 and Qt 5.14.2 as well as Qt 5.14.1, Qt 5.9.5. Also, I have tried in Ubuntu 18.04, g++ 7.5.0 and Qt 5.9.5.
From what I can gather from your sample code:
So, to induce a stack overflow, one thread should have been capable of posting enough events in the dialog's thread event loop before the dialog begins to process them.
Once it will begin to process this events chain, it will recurse on itself and may cause a stack overflow. If you are stepping in the main thread with the debugger, it may explains why the other thread is able to accumulate so much events in the main even loop.
I do not know it this is something that may qualify as a bug for the Qt project, but you could still ask on their IRC channel or open an issue and see where it gets.
Nevertheless, a possible ad-hoc solution would be to avoid bursting signals from the worker thread to avoid falling in this pitfall (like triggering a status update every second instead on short unoticeable intervals for the end user).