Bug 353360 - deadlock between KServiceTypeProfiles::hasProfile / KServiceTypeProfiles::clear
Summary: deadlock between KServiceTypeProfiles::hasProfile / KServiceTypeProfiles::clear
Status: RESOLVED FIXED
Alias: None
Product: frameworks-kservice
Classification: Frameworks and Libraries
Component: general (show other bugs)
Version: unspecified
Platform: Other Linux
: NOR crash
Target Milestone: ---
Assignee: David Faure
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-09-30 08:37 UTC by Milian Wolff
Modified: 2015-10-04 10:04 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In:
Sentry Crash Report:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Milian Wolff 2015-09-30 08:37:18 UTC
Hey,

I just encountered this deadlock with kservice v4.100.0-rc1-244-g16e6b2b:

(gdb) bt
#0  0x00007f7e289d7cf9 in syscall () from /usr/lib/libc.so.6
#1  0x00007f7e290cc988 in QBasicMutex::lockInternal() () from /usr/lib/libQt5Core.so.5
#2  0x00007f7e2af33cfd in QMutexLocker::QMutexLocker (this=0x7ffd71155890, 
    m=0x7f7e2afb0f08 <(anonymous namespace)::Q_QGS_s_serviceTypeProfiles::innerFunction()::holder+8>)
    at /usr/include/qt/QtCore/qmutex.h:128
#3  0x00007f7e2af33e2f in KServiceTypeProfiles::clear (
    this=0x7f7e2afb0f00 <(anonymous namespace)::Q_QGS_s_serviceTypeProfiles::innerFunction()::holder>)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypeprofile.cpp:49
#4  0x00007f7e2af3305b in KServiceTypeProfile::clearCache ()
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypeprofile.cpp:111
#5  0x00007f7e2af31a15 in KServiceTypeFactory::~KServiceTypeFactory (this=0x624b110, __in_chrg=<optimized out>)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypefactory.cpp:58
#6  0x00007f7e2af31a60 in KServiceTypeFactory::~KServiceTypeFactory (this=0x624b110, __in_chrg=<optimized out>)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypefactory.cpp:60
#7  0x00007f7e2af4c526 in qDeleteAll<QList<KSycocaFactory*>::const_iterator> (begin=..., end=...)
    at /usr/include/qt/QtCore/qalgorithms.h:317
#8  0x00007f7e2af4bfee in qDeleteAll<KSycocaFactoryList> (c=...) at /usr/include/qt/QtCore/qalgorithms.h:325
#9  0x00007f7e2af4915a in KSycocaPrivate::closeDatabase (this=0x18c4300)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/sycoca/ksycoca.cpp:397
#10 0x00007f7e2af4a4f7 in KSycocaPrivate::buildSycoca (this=0x18c4300)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/sycoca/ksycoca.cpp:666
#11 0x00007f7e2af4a418 in KSycocaPrivate::checkDirectories (this=0x18c4300)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/sycoca/ksycoca.cpp:647
#12 0x00007f7e2af495fe in KSycocaPrivate::checkDatabase (this=0x18c4300, ifNotFound=...)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/sycoca/ksycoca.cpp:492
#13 0x00007f7e2af49690 in KSycoca::findFactory (this=0x18b4740, id=KST_KServiceTypeFactory)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/sycoca/ksycoca.cpp:512
#14 0x00007f7e2af51af6 in KSycocaFactory::KSycocaFactory (this=0x624aef0, factory_id=KST_KServiceTypeFactory, 
    sycoca=0x18b4740) at /home/milian/projects/kf5/src/frameworks/kservice/src/sycoca/ksycocafactory.cpp:54
#15 0x00007f7e2af318b7 in KServiceTypeFactory::KServiceTypeFactory (this=0x624aef0, db=0x18b4740)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypefactory.cpp:30
---Type <return> to continue, or q <return> to quit---
#16 0x00007f7e2af48ea7 in KSycocaPrivate::serviceTypeFactory (this=0x18c4300)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/sycoca/ksycoca.cpp:340
#17 0x00007f7e2af32c1c in KServiceTypeProfiles::ensureParsed (
    this=0x7f7e2afb0f00 <(anonymous namespace)::Q_QGS_s_serviceTypeProfiles::innerFunction()::holder>)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypeprofile.cpp:76
#18 0x00007f7e2af33e92 in KServiceTypeProfiles::hasProfile (
    this=0x7f7e2afb0f00 <(anonymous namespace)::Q_QGS_s_serviceTypeProfiles::innerFunction()::holder>, serviceType=...)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypeprofile.cpp:57
#19 0x00007f7e2af33356 in KServiceTypeProfile::hasProfile (serviceType=...)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypeprofile.cpp:175
#20 0x00007f7e2af35f36 in KServiceTypeTrader::query (
    this=0x7f7e2afb0f30 <(anonymous namespace)::Q_QGS_s_globalServiceTypeTrader::innerFunction()::holder>, serviceType=..., 
    constraint=...) at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypetrader.cpp:153
#21 0x00007f7d7820a559 in TaskManager::TaskItem::launcherUrlFromTask(TaskManager::GroupManager*, TaskManager::Task*, TaskManager::Startup*) () from /usr/lib/libtaskmanager.so.5
#22 0x00007f7d781ce92e in ?? () from /usr/lib/libtaskmanager.so.5
#23 0x00007f7d781d4f90 in ?? () from /usr/lib/libtaskmanager.so.5
#24 0x00007f7e292e2fea in QMetaObject::activate(QObject*, int, int, void**) () from /usr/lib/libQt5Core.so.5
#25 0x00007f7d7820adaf in TaskManager::TaskManager::taskAdded(TaskManager::Task*) () from /usr/lib/libtaskmanager.so.5
#26 0x00007f7d7820b7dd in TaskManager::TaskManager::windowAdded(unsigned long long) () from /usr/lib/libtaskmanager.so.5
#27 0x00007f7d7820e52f in ?? () from /usr/lib/libtaskmanager.so.5
#28 0x00007f7e292e2fea in QMetaObject::activate(QObject*, int, int, void**) () from /usr/lib/libQt5Core.so.5
#29 0x00007f7e2b049809 in KWindowSystem::windowAdded (
    this=0x7f7e2b061ba0 <(anonymous namespace)::Q_QGS_g_kwmInstanceContainer::innerFunction()::holder>, _t1=117440518)
    at /ssd/milian/projects/kf5/build-dbg/frameworks/kwindowsystem/src/moc_kwindowsystem.cpp:289
#30 0x00007f7e133e4205 in ?? () from /usr/lib/qt/plugins/kf5/org.kde.kwindowsystem.platforms/KF5WindowSystemX11Plugin.so
#31 0x00007f7e2b038465 in NETRootInfo::update (this=0x4cbf7b0, properties=..., properties2=...)
    at /home/milian/projects/kf5/src/frameworks/kwindowsystem/src/platforms/xcb/netwm.cpp:2261
#32 0x00007f7e2b037554 in NETRootInfo::event (this=0x4cbf7b0, event=0x7f7e14004cd0, properties=0x7ffd71156f20, 
    properties2=0x7ffd71156f10) at /home/milian/projects/kf5/src/frameworks/kwindowsystem/src/platforms/xcb/netwm.cpp:2098
#33 0x00007f7e2b036d25 in NETRootInfo::event (this=0x4cbf7b0, ev=0x7f7e14004cd0, properties=0x7ffd71156fb0, 
---Type <return> to continue, or q <return> to quit---
    properties_size=5) at /home/milian/projects/kf5/src/frameworks/kwindowsystem/src/platforms/xcb/netwm.cpp:1883
#34 0x00007f7e133e38b7 in ?? () from /usr/lib/qt/plugins/kf5/org.kde.kwindowsystem.platforms/KF5WindowSystemX11Plugin.so
#35 0x00007f7e292b13ff in QAbstractEventDispatcher::filterNativeEvent(QByteArray const&, void*, long*) ()
   from /usr/lib/libQt5Core.so.5
#36 0x00007f7e1a865554 in QXcbConnection::handleXcbEvent(xcb_generic_event_t*) () from /usr/lib/libQt5XcbQpa.so.5
#37 0x00007f7e1a866303 in QXcbConnection::processXcbEvents() () from /usr/lib/libQt5XcbQpa.so.5
#38 0x00007f7e292e3eb1 in QObject::event(QEvent*) () from /usr/lib/libQt5Core.so.5
#39 0x00007f7e2a48b00c in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib/libQt5Widgets.so.5
#40 0x00007f7e2a4904e6 in QApplication::notify(QObject*, QEvent*) () from /usr/lib/libQt5Widgets.so.5
#41 0x00007f7e292b489b in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /usr/lib/libQt5Core.so.5
#42 0x00007f7e292b6c96 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) ()
   from /usr/lib/libQt5Core.so.5
#43 0x00007f7e2930ae33 in ?? () from /usr/lib/libQt5Core.so.5
#44 0x00007f7e24a219fd in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
#45 0x00007f7e24a21ce0 in ?? () from /usr/lib/libglib-2.0.so.0
#46 0x00007f7e24a21d8c in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0
#47 0x00007f7e2930b23f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) ()
   from /usr/lib/libQt5Core.so.5
#48 0x00007f7e292b226a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib/libQt5Core.so.5
#49 0x00007f7e292ba20c in QCoreApplication::exec() () from /usr/lib/libQt5Core.so.5
#50 0x00000000004300f3 in main ()


(gdb) 
#3  0x00007f7e2af33e2f in KServiceTypeProfiles::clear (
    this=0x7f7e2afb0f00 <(anonymous namespace)::Q_QGS_s_serviceTypeProfiles::innerFunction()::holder>)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypeprofile.cpp:49
49              QMutexLocker lock(&m_mutex);
(gdb) list
44          {
45              clear();
46          }
47          void clear()
48          {
49              QMutexLocker lock(&m_mutex);
50              qDeleteAll(*this);
51              QHash<QString, KServiceTypeProfileEntry *>::clear();
52              m_parsed = false;
53          }
(gdb) down
#18 0x00007f7e2af33e92 in KServiceTypeProfiles::hasProfile (
    this=0x7f7e2afb0f00 <(anonymous namespace)::Q_QGS_s_serviceTypeProfiles::innerFunction()::holder>, serviceType=...)
    at /home/milian/projects/kf5/src/frameworks/kservice/src/services/kservicetypeprofile.cpp:57
57              ensureParsed();
(gdb) list
52              m_parsed = false;
53          }
54          bool hasProfile(const QString &serviceType)
55          {
56              QMutexLocker lock(&m_mutex);
57              ensureParsed();
58              return contains(serviceType);
59          }
60          void ensureParsed(); // mutex must be locked when calling this
61          QMutex m_mutex;

This should be fixed. While a recursive mutex could be a hotfix, I think a proper solution should be found which separates the code and guards itself against reentrancy.

Reproducible: Sometimes

Steps to Reproduce:
I just started plasmashell and it deadlocked after some time

Actual Results:  
deadlock

Expected Results:  
no deadlock

I could successfully unblock plasma via gdb with `call m_mutex.unlock()` followed by `continue`.
Comment 1 David Faure 2015-10-02 23:47:30 UTC
Still trying to write a unit test that triggers this.... there's some nastiness involved in the KServiceTypeProfile re-entrancy that happens in this patch.
Comment 2 David Faure 2015-10-04 10:04:26 UTC
Git commit 94ae1a54991212d30b95f690e4086d9a7aec07c8 by David Faure.
Committed on 04/10/2015 at 10:04.
Pushed by dfaure into branch 'master'.

KServiceTypeProfile: remove unnecessary factory creation.

This led to a deadlock in some cases (although I didn't manage to write
a unittest that triggers it). Still, adding the unittest I wrote, it's
always good to have more.
REVIEW: 125504

M  +10   -1    autotests/kservicetest.cpp
M  +1    -0    autotests/kservicetest.h
M  +1    -5    src/services/kservicetypeprofile.cpp

http://commits.kde.org/kservice/94ae1a54991212d30b95f690e4086d9a7aec07c8