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

Large D-Bus messages sometimes trigger assertion failure in qDBusToggleWatch

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Reported
    • Priority: P1: Critical
    • Resolution: Unresolved
    • Affects Version/s: 5.11.0
    • Fix Version/s: None
    • Component/s: D-Bus
    • Labels:
      None
    • Platform/s:
      Linux/X11, Windows

      Description

      Sometimes, when a QDBusMessage is received with a payload of ~1MB or greater (I haven't tested the exact threshold at which the problem appears, but I suspect it is 512KB), it appears to trigger processing on the main thread instead of the dedicated D-Bus helper thread.

      In debug builds, this triggers the following assertion failure in qDBusToggleWatch:

      ASSERT: "QThread::currentThread() == d->thread()" in file qdbusintegrator.cpp, line 258
      

      In optimized builds, we get a little bit farther, resulting in the following errors being logged:

      QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

      and the QDBusMessage that arrives then contains the error "org.freedesktop.DBus.Error.NoReply."

      The stack trace at which the assertion error occurs looks like this:

           Qt5Cored.dll!qt_message_fatal(QtMsgType __formal, const QMessageLogContext & context, const QString & message) Line 1833    C++
           Qt5Cored.dll!QMessageLogger::fatal(const char * msg, ...) Line 877    C++
           Qt5Cored.dll!qt_assert(const char * assertion, const char * file, int line) Line 3180    C++
      >    Qt5DBusd.dll!qDBusToggleWatch(DBusWatch * watch, void * data) Line 259    C++
           dbus-1d.dll!_dbus_watch_list_toggle_watch(DBusWatchList * watch_list, DBusWatch * watch, unsigned int enabled) Line 463    C
           dbus-1d.dll!protected_change_watch(DBusConnection * connection, DBusWatch * watch, unsigned int(*)(DBusWatchList *, DBusWatch *) add_function, void(*)(DBusWatchList *, DBusWatch *) remove_function, void(*)(DBusWatchList *, DBusWatch *, unsigned int) toggle_function, unsigned int enabled) Line 724    C
           dbus-1d.dll!_dbus_connection_toggle_watch_unlocked(DBusConnection * connection, DBusWatch * watch, unsigned int enabled) Line 791    C
           dbus-1d.dll!check_read_watch(DBusTransport * transport) Line 232    C
           dbus-1d.dll!socket_live_messages_changed(DBusTransport * transport) Line 1255    C
           dbus-1d.dll!live_messages_notify(DBusCounter * counter, void * user_data) Line 84    C
           dbus-1d.dll!_dbus_counter_notify(DBusCounter * counter) Line 223    C
           dbus-1d.dll!free_counter(void * element, void * data) Line 619    C
           dbus-1d.dll!_dbus_list_foreach(DBusList * * list, void(*)(void *, void *) function, void * data) Line 772    C
           dbus-1d.dll!dbus_message_cache_or_finalize(DBusMessage * message) Line 642    C
           dbus-1d.dll!dbus_message_unref(DBusMessage * message) Line 1731    C
           Qt5DBusd.dll!q_dbus_message_unref(DBusMessage * message) Line 378    C++
           Qt5DBusd.dll!QDBusMessagePrivate::~QDBusMessagePrivate() Line 81    C++
           Qt5DBusd.dll!QDBusMessagePrivate::`scalar deleting destructor'(unsigned int)    C++
           Qt5DBusd.dll!QDBusMessage::~QDBusMessage() Line 571    C++
           dbustest.exe!client::__l2::<lambda>() Line 89    C++
           dbustest.exe!std::_Invoker_functor::_Call<void <lambda>(void) &>(client::__l2::void <lambda>(void) & _Obj)    C++
           dbustest.exe!std::invoke<void <lambda>(void) &>(client::__l2::void <lambda>(void) & _Obj)    C++
           dbustest.exe!std::_Invoker_ret<void,1>::_Call<void <lambda>(void) &>(client::__l2::void <lambda>(void) & <_Vals_0>)    C++
           dbustest.exe!std::_Func_impl_no_alloc<void <lambda>(void),void>::_Do_call()    C++
           dbustest.exe!std::_Func_class<void>::operator()()    C++
           dbustest.exe!client::__l2::<lambda>() Line 100    C++
           dbustest.exe!QtPrivate::FunctorCall<QtPrivate::IndexesList<>,QtPrivate::List<>,void,void <lambda>(void) >::call(client::__l2::void <lambda>(void) & f, void * * arg) Line 128    C++
           dbustest.exe!QtPrivate::Functor<void <lambda>(void),0>::call<QtPrivate::List<>,void>(client::__l2::void <lambda>(void) & f, void * __formal, void * * arg) Line 239    C++
           dbustest.exe!QtPrivate::QFunctorSlotObject<void <lambda>(void),0,QtPrivate::List<>,void>::impl(int which, QtPrivate::QSlotObjectBase * this_, QObject * r, void * * a, bool * ret) Line 427    C++
           Qt5Cored.dll!QtPrivate::QSlotObjectBase::call(QObject * r, void * * a) Line 376    C++
           Qt5Cored.dll!QMetaObject::activate(QObject * sender, int signalOffset, int local_signal_index, void * * argv) Line 3759    C++
           Qt5Cored.dll!QMetaObject::activate(QObject * sender, const QMetaObject * m, int local_signal_index, void * * argv) Line 3634    C++
           Qt5Cored.dll!QTimer::timeout(QTimer::QPrivateSignal _t1) Line 201    C++
           Qt5Cored.dll!QTimer::timerEvent(QTimerEvent * e) Line 257    C++
           Qt5Cored.dll!QObject::event(QEvent * e) Line 1233    C++
           Qt5Widgetsd.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3713    C++
           Qt5Widgetsd.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3085    C++
           Qt5Cored.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1048    C++
           Qt5Cored.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 234    C++
           Qt5Cored.dll!QEventDispatcherWin32Private::sendTimerEvent(int timerId) Line 450    C++
           Qt5Cored.dll!QEventDispatcherWin32::event(QEvent * e) Line 1078    C++
           Qt5Widgetsd.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3713    C++
           Qt5Widgetsd.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3085    C++
           Qt5Cored.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1048    C++
           Qt5Cored.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 234    C++
           Qt5Cored.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1745    C++
           Qt5Cored.dll!QEventDispatcherWin32::sendPostedEvents() Line 1085    C++
           qwindowsd.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 82    C++
           Qt5Cored.dll!qt_internal_proc(HWND__ * hwnd, unsigned int message, unsigned __int64 wp, __int64 lp) Line 239    C++
           user32.dll!UserCallWinProcCheckWow()    Unknown
           user32.dll!DispatchMessageWorker()    Unknown
           Qt5Cored.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 630    C++
           qwindowsd.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 74    C++
           Qt5Cored.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 137    C++
           Qt5Cored.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 214    C++
           Qt5Cored.dll!QCoreApplication::exec() Line 1336    C++
           Qt5Guid.dll!QGuiApplication::exec() Line 1751    C++
           Qt5Widgetsd.dll!QApplication::exec() Line 2899    C++
           dbustest.exe!client() Line 104    C++
           dbustest.exe!main(int argc, char * * argv) Line 125    C++
           dbustest.exe!invoke_main() Line 79    C++
           dbustest.exe!__scrt_common_main_seh() Line 283    C++
           dbustest.exe!__scrt_common_main() Line 326    C++
           dbustest.exe!mainCRTStartup() Line 17    C++
           kernel32.dll!BaseThreadInitThunk()    Unknown
           ntdll.dll!RtlUserThreadStart()    Unknown
      

       

      I've attached a sample program which demonstrates the problem.

      If this program is launched with -l (for listen), it will create a QObject and put it on the D-Bus. This object defines a slot which returns a large QByteArray, and another which causes a signal to be emitted with a large QByteArray as its argument

      If run with -c (for client), it will connect to the D-Bus and connect to the object's signal. It will then randomly invoke the QObject's two slots, and listen for the signal.

      To reproduce, run one instance with a -l argument, then run a second instance with -c

      Within 10-60 seconds, the client (-c) instance will fail with the errors listed above, or faster if I run multiple client instances.

      I can reproduce the problem on both Linux (CentOS 7) and Windows 10.

        Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              jalf jalf
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:

                Gerrit Reviews

                There are no open Gerrit changes