Bug 370646 - Crash because of stale (dangling) pointers in the attribute registry
Summary: Crash because of stale (dangling) pointers in the attribute registry
Status: RESOLVED UNMAINTAINED
Alias: None
Product: kontact
Classification: Applications
Component: general (show other bugs)
Version: GIT (master)
Platform: Compiled Sources macOS
: NOR crash
Target Milestone: ---
Assignee: kdepim bugs
URL: http://arstechnica.com/civis/viewtopi...
Keywords:
Depends on:
Blocks:
 
Reported: 2016-10-13 12:02 UTC by RJVB
Modified: 2018-02-01 09:54 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description RJVB 2016-10-13 12:02:07 UTC
Kontact built from the latest 4.14 branch sources crashes on OS X whenever I open the Kontact preferences dialog.

Reproducible: Always

Steps to Reproduce:
1. Start Kontact
2. Select Settings/Configure Kontact


Actual Results:  
DrKonqi appears

Expected Results:  
Kontact preferences dialog appears

The actual crash is in line 141 of attributefactory.cpp (`AttributeFactory::registerAttribute(Attribute *attr)`):

delete *it;

For now I haven't seen it happen when I comment that line out; I hope this only leads to a minor memory leak (which I find preferable over a crash).

I hope this info is useful for the KF5 version but would appreciate a backported fix.
Comment 1 Laurent Montel 2016-10-13 13:15:52 UTC
Could you provide a backtrace ?:)

I will not create a patch in 4.14 but if we can reproduce bug and fix it I can provide your patch for it.
Comment 2 RJVB 2016-10-13 16:14:08 UTC
Backtrace below.

Among the things I tried was not deleting only attributes of type NoteDisplayAttribute. That actually made things worse, somehow, causing crashes even when the application was starting up.

I do wonder about the delete, which appears to be a recent addition. QHash::insert doesn't make copies as far as I read its documentation, so why the delete? To allow the code registering an attribute to forget about it? Maybe libnoteshared registers attributes it then deletes itself?

Application: Kontact (kontact), signal: Segmentation fault: 11
(lldb) process attach --pid 59010
Process 59010 stopped
Executable module set to "/opt/local/bin/kontact".
Architecture set to: x86_64-apple-macosx.
(lldb) set set term-width 200
(lldb) thread info
thread #1: tid = 0x354337, 0x00007fff8f109e20 libsystem_kernel.dylib`__wait4 + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP

(lldb) bt all
* thread #1: tid = 0x354337, 0x00007fff8f109e20 libsystem_kernel.dylib`__wait4 + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00007fff8f109e20 libsystem_kernel.dylib`__wait4 + 8
    frame #1: 0x0000000107fc616e libkdeui.5.dylib`KCrash::startProcess(int, char const**, bool) + 286
    frame #2: 0x0000000107fc5295 libkdeui.5.dylib`KCrash::defaultCrashHandler(int) + 1189
    frame #3: 0x00007fff8b6e15aa libsystem_platform.dylib`_sigtramp + 26
    frame #4: 0x000000010a5249ca libakonadi-kde.4.dylib`Akonadi::AttributeFactory::registerAttribute(this=0x00007f97dbc28870, attr=0x00007f97e1d8b980) + 538 at attributefactory.cpp:141
    frame #5: 0x0000000120e3c2cf libnoteshared.4.dylib`_GLOBAL__I_a [inlined] void Akonadi::AttributeFactory::registerAttribute<NoteShared::NoteDisplayAttribute>() + 47 at attributefactory.h:61
    frame #6: 0x0000000120e3c2a4 libnoteshared.4.dylib`_GLOBAL__I_a [inlined] (anonymous namespace)::dummy() at attributeregistrar.cpp:30
    frame #7: 0x0000000120e3c2a4 libnoteshared.4.dylib`_GLOBAL__I_a [inlined] __cxx_global_var_init at attributeregistrar.cpp:38
    frame #8: 0x0000000120e3c2a4 libnoteshared.4.dylib`_GLOBAL__I_a + 4 at attributeregistrar.cpp:0
    frame #9: 0x00007fff61468c6e dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 268
    frame #10: 0x00007fff61468dfa dyld`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 40
    frame #11: 0x00007fff61465aa2 dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) + 308
    frame #12: 0x00007fff61465a2b dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) + 189
    frame #13: 0x00007fff61465a2b dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) + 189
    frame #14: 0x00007fff61465936 dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 54
    frame #15: 0x00007fff6145bb0e dyld`dyld::runInitializers(ImageLoader*) + 89
    frame #16: 0x00007fff6146280f dyld`dlopen + 538
    frame #17: 0x00007fff8eb347ee libdyld.dylib`dlopen + 59
    frame #18: 0x000000010981aafd QtCore`QLibraryPrivate::load_sys() + 2589
    frame #19: 0x0000000109818000 QtCore`QLibrary::load() + 80
    frame #20: 0x00000001093b5281 libkdecore.5.dylib`KLibLoader::library(QString const&, QFlags<QLibrary::LoadHint>) + 145
    frame #21: 0x000000010a0acb73 libkcmutils.4.dylib`KCModuleLoader::loadModule(KCModuleInfo const&, KCModuleLoader::ErrorReporting, QWidget*, QStringList const&) + 3635
    frame #22: 0x000000010a0b470c libkcmutils.4.dylib`KCModuleProxyPrivate::loadModule() + 668
    frame #23: 0x000000010a0b4432 libkcmutils.4.dylib`KCModuleProxy::realModule() const + 66
    frame #24: 0x000000010a0b0791 libkcmutils.4.dylib`KCMultiDialog::addModule(KCModuleInfo const&, KPageWidgetItem*, QStringList const&) + 385
    frame #25: 0x000000010a0caf6b libkcmutils.4.dylib`KSettings::DialogPrivate::createDialogFromServices() + 2715
    frame #26: 0x000000010a0ca053 libkcmutils.4.dylib`KSettings::Dialog::showEvent(QShowEvent*) + 1923
    frame #27: 0x00000001085ce1f6 QtGui`QWidget::event(QEvent*) + 1334
    frame #28: 0x0000000108574afc QtGui`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 332
    frame #29: 0x0000000108577e99 QtGui`QApplication::notify(QObject*, QEvent*) + 8281
    frame #30: 0x0000000109830126 QtCore`QCoreApplication::notifyInternal(QObject*, QEvent*) + 118
    frame #31: 0x00000001085ccf0c QtGui`QWidgetPrivate::show_helper() + 668
    frame #32: 0x00000001085cd9ae QtGui`QWidget::setVisible(bool) + 974
    frame #33: 0x0000000108a314b9 QtGui`QDialog::setVisible(bool) + 169
    frame #34: 0x000000010732b8fc libkontactprivate.4.dylib`Kontact::MainWindow::slotPreferences() [inlined] QWidget::show(this=<unavailable>) + 668 at qwidget.h:497
    frame #35: 0x000000010732b8f1 libkontactprivate.4.dylib`Kontact::MainWindow::slotPreferences(this=<unavailable>) + 657 at mainwindow.cpp:1062
    frame #36: 0x000000010984fce6 QtCore`QMetaObject::activate(QObject*, QMetaObject const*, int, void**) + 3366
    frame #37: 0x000000010856b7d0 QtGui`QAction::activate(QAction::ActionEvent) + 224
    frame #38: 0x00000001089ab875 QtGui`QMenuPrivate::activateCausedStack(QList<QPointer<QWidget> > const&, QAction*, QAction::ActionEvent, bool) + 101
    frame #39: 0x00000001089a9a5e QtGui`QMenuPrivate::activateAction(QAction*, QAction::ActionEvent, bool) + 494
    frame #40: 0x00000001089af42a QtGui`QMenu::mouseReleaseEvent(QMouseEvent*) + 218
    frame #41: 0x000000010804191d libkdeui.5.dylib`KMenu::mouseReleaseEvent(QMouseEvent*) + 525
    frame #42: 0x00000001085cdf8a QtGui`QWidget::event(QEvent*) + 714
    frame #43: 0x00000001089afa78 QtGui`QMenu::event(QEvent*) + 1096
    frame #44: 0x0000000108574afc QtGui`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 332
    frame #45: 0x0000000108578659 QtGui`QApplication::notify(QObject*, QEvent*) + 10265
    frame #46: 0x0000000109830126 QtCore`QCoreApplication::notifyInternal(QObject*, QEvent*) + 118
    frame #47: 0x000000010857549f QtGui`QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 463
    frame #48: 0x0000000108521deb QtGui`qt_mac_handleMouseEvent(NSEvent*, QEvent::Type, Qt::MouseButton, QWidget*, bool) + 1291
    frame #49: 0x00007fff949d0145 AppKit`-[NSWindow sendEvent:] + 781
    frame #50: 0x00000001085119f1 QtGui`-[QCocoaPanel sendEvent:] + 113
    frame #51: 0x00007fff949715d4 AppKit`-[NSApplication sendEvent:] + 2021
    frame #52: 0x000000010851e201 QtGui`-[QNSApplication sendEvent:] + 97
    frame #53: 0x00007fff947c19f9 AppKit`-[NSApplication run] + 646
    frame #54: 0x00000001085279bb QtGui`QEventDispatcherMac::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 2059
    frame #55: 0x000000010982bf4f QtCore`QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 687
    frame #56: 0x0000000109830727 QtCore`QCoreApplication::exec() + 199
    frame #57: 0x0000000105d885ce kontact`main(argc=<unavailable>, argv=<unavailable>) + 4382 at main.cpp:219
    frame #58: 0x00007fff8eb355fd libdyld.dylib`start + 1

  thread #2: tid = 0x35433a, 0x00007fff8f10a662 libsystem_kernel.dylib`kevent64 + 10, queue = 'com.apple.libdispatch-manager'
    frame #0: 0x00007fff8f10a662 libsystem_kernel.dylib`kevent64 + 10
    frame #1: 0x00007fff91e2d421 libdispatch.dylib`_dispatch_mgr_invoke + 239
    frame #2: 0x00007fff91e2d136 libdispatch.dylib`_dispatch_mgr_thread + 52

  thread #3: tid = 0x35433b, 0x00007fff8f109e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x00007fff8f109e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff968ebf08 libsystem_pthread.dylib`_pthread_wqthread + 330
    frame #2: 0x00007fff968eefb9 libsystem_pthread.dylib`start_wqthread + 13

  thread #4: tid = 0x35433c, 0x00007fff8f109e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x00007fff8f109e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff968ebf08 libsystem_pthread.dylib`_pthread_wqthread + 330
    frame #2: 0x00007fff968eefb9 libsystem_pthread.dylib`start_wqthread + 13

  thread #5: tid = 0x354343, 0x00007fff8f109e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x00007fff8f109e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff968ebf08 libsystem_pthread.dylib`_pthread_wqthread + 330
    frame #2: 0x00007fff968eefb9 libsystem_pthread.dylib`start_wqthread + 13

  thread #6: tid = 0x354349, 0x00007fff8f1099aa libsystem_kernel.dylib`__select + 10, name = 'com.apple.CFSocket.private'
    frame #0: 0x00007fff8f1099aa libsystem_kernel.dylib`__select + 10
    frame #1: 0x00007fff8fb23a03 CoreFoundation`__CFSocketManager + 867
    frame #2: 0x00007fff968ea899 libsystem_pthread.dylib`_pthread_body + 138
    frame #3: 0x00007fff968ea72a libsystem_pthread.dylib`_pthread_start + 137
    frame #4: 0x00007fff968eefc9 libsystem_pthread.dylib`thread_start + 13

  thread #7: tid = 0x35434a, 0x00007fff8f1099aa libsystem_kernel.dylib`__select + 10, name = 'QThread'
    frame #0: 0x00007fff8f1099aa libsystem_kernel.dylib`__select + 10
    frame #1: 0x00000001098685d3 QtCore`qt_safe_select(int, fd_set*, fd_set*, fd_set*, timeval const*) + 755
    frame #2: 0x000000010986b3bf QtCore`QEventDispatcherUNIXPrivate::doSelect(QFlags<QEventLoop::ProcessEventsFlag>, timeval*) + 1039
    frame #3: 0x000000010986d2a0 QtCore`QEventDispatcherUNIX::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 896
    frame #4: 0x000000010982bf4f QtCore`QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 687
    frame #5: 0x00000001096f1a84 QtCore`QThread::exec() + 308
    frame #6: 0x00000001096f409c QtCore`QThreadPrivate::start(void*) + 492
    frame #7: 0x00007fff968ea899 libsystem_pthread.dylib`_pthread_body + 138
    frame #8: 0x00007fff968ea72a libsystem_pthread.dylib`_pthread_start + 137
    frame #9: 0x00007fff968eefc9 libsystem_pthread.dylib`thread_start + 13

  thread #8: tid = 0x35436f, 0x00007fff8f109716 libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'Thread (pooled)'
    frame #0: 0x00007fff8f109716 libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x00007fff968ecc3b libsystem_pthread.dylib`_pthread_cond_wait + 727
    frame #2: 0x00000001096f5e69 QtCore`QWaitConditionPrivate::wait(unsigned long) + 185
    frame #3: 0x00000001096f5bb6 QtCore`QWaitCondition::wait(QMutex*, unsigned long) + 294
    frame #4: 0x00000001096e1943 QtCore`QThreadPoolThread::run() + 1075
    frame #5: 0x00000001096f409c QtCore`QThreadPrivate::start(void*) + 492
    frame #6: 0x00007fff968ea899 libsystem_pthread.dylib`_pthread_body + 138
    frame #7: 0x00007fff968ea72a libsystem_pthread.dylib`_pthread_start + 137
    frame #8: 0x00007fff968eefc9 libsystem_pthread.dylib`thread_start + 13

  thread #9: tid = 0x354376, 0x00007fff8f105a1a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #0: 0x00007fff8f105a1a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x00007fff8f104d18 libsystem_kernel.dylib`mach_msg + 64
    frame #2: 0x00007fff8fad7f15 CoreFoundation`__CFRunLoopServiceMachPort + 181
    frame #3: 0x00007fff8fad7539 CoreFoundation`__CFRunLoopRun + 1161
    frame #4: 0x00007fff8fad6e75 CoreFoundation`CFRunLoopRunSpecific + 309
    frame #5: 0x00007fff9496e05e AppKit`_NSEventThread + 144
    frame #6: 0x00007fff968ea899 libsystem_pthread.dylib`_pthread_body + 138
    frame #7: 0x00007fff968ea72a libsystem_pthread.dylib`_pthread_start + 137
    frame #8: 0x00007fff968eefc9 libsystem_pthread.dylib`thread_start + 13

  thread #10: tid = 0x3544e2, 0x00007fff8f109e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x00007fff8f109e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff968ebf08 libsystem_pthread.dylib`_pthread_wqthread + 330
    frame #2: 0x00007fff968eefb9 libsystem_pthread.dylib`start_wqthread + 13
(lldb) detach
Process 59010 detached
Comment 3 RJVB 2016-10-14 16:24:09 UTC
I ran kontact through valgrind to get another angle. I think in the end it just confirms what I already thought:

```
--72548-- run: /usr/bin/dsymutil "/opt/local/lib/kde4/kcm_knote.so"
--72548-- run: /usr/bin/dsymutil "/opt/local/lib/libknotesprivate.4.14.21.dylib"
--72548-- run: /usr/bin/dsymutil "/opt/local/lib/libnoteshared.4.14.21.dylib"
--72548-- run: /usr/bin/dsymutil "/opt/local/lib/libkdnssd.4.14.21.dylib"
warning: (x86_64) /tmp/lto.o unable to open object file
warning: no debug symbols in executable (-arch x86_64)
==72548== Invalid read of size 8
==72548==    at 0xCA796B9: Akonadi::AttributeFactory::registerAttribute(Akonadi::Attribute*) (attributefactory.cpp:148)
==72548==    by 0x19ED63DE: global constructors keyed to a (attributefactory.h:61)
==72548==    by 0x7FFF5FC11C6D: ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==72548==    by 0x7FFF5FC11DF9: ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==72548==    by 0x7FFF5FC0EAA1: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==72548==    by 0x7FFF5FC0EA2A: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==72548==    by 0x7FFF5FC0EA2A: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==72548==    by 0x7FFF5FC0E935: ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==72548==    by 0x7FFF5FC04B0D: dyld::runInitializers(ImageLoader*) (in /usr/lib/dyld)
==72548==    by 0x7FFF5FC0B80E: dlopen (in /usr/lib/dyld)
==72548==    by 0x90657ED: dlopen (in /usr/lib/system/libdyld.dylib)
==72548==    by 0x38F8AFC: QLibraryPrivate::load_sys() (in /opt/local/libexec/qt4/Library/Frameworks/QtCore.framework/Versions/4/QtCore)
==72548==  Address 0x1a48cd40 is not stack'd, malloc'd or (recently) free'd
==72548== 
*** KMail got signal 11 (Exiting)
*** Dead letters dumped.
KCrash: Application 'kontact' crashing...
KCrash: Attempting to start /opt/local/lib/kde4/libexec/drkonqi.app/Contents/MacOS/drkonqi directly
```
Comment 4 RJVB 2016-10-14 17:28:31 UTC
Why this happens is unclear to me, but the line

 const bool registered = dummy();

in libnoteshared's attributeregistrar.cpp is executed twice. I think that can only happen when the library is loaded twice.

I may be saying something stupid here, but if the library gets unloaded without removing its registered attributes, are their addresses still valid when the library is loaded next?
Comment 5 RJVB 2016-10-14 20:17:17 UTC
I don't understand how or why dynamically allocated memory can go stale when the shared library which allocated it is unloaded, but apparently something like that happens.

When I replace libnoteshared's attributeregistrar's mechanism with one that create a global class instance when the library is loaded, I can clearly see that instance being destroyed. I'll have a look at the backtrace leading into that dtor, but meanwhile, here's a fix. It extends the AttributeFactory with a method that returns the newly created attribute instance, and (a circuitous) one that allows to unregister attributes.
The resulting libraries are ABI compatible, and Kontact no longer crashes

Patch for kdepimlibs4:
------------------------------------
diff --git akonadi/attributefactory.cpp akonadi/attributefactory.cpp
index 47a8839..51306f0 100644
--- akonadi/attributefactory.cpp
+++ akonadi/attributefactory.cpp
@@ -30,6 +30,7 @@
 #include "entityannotationsattribute.h"
 
 #include <KGlobal>
+#include <KDebug>
 
 #include <QtCore/QHash>
 
@@ -79,7 +80,18 @@ class StaticAttributeFactory : public AttributeFactory
 public:
     StaticAttributeFactory()
         : AttributeFactory()
-        , initialized(false) {}
+        , initialized(false)
+        , notDeleted(0) {
+        skipList << QLatin1String("NoteDisplayAttribute")
+            << QLatin1String("NoteAlarmAttribute")
+            << QLatin1String("KJotsLockAttribute")
+            << QLatin1String("showfoldernotesattribute");
+    }
+    ~StaticAttributeFactory() {
+        if (notDeleted > 0) {
+            kWarning(5250) << Q_FUNC_INFO << "attributes not deleted:" << notDeleted;
+        }
+    }
     void init() {
         if (initialized) {
             return;
@@ -98,6 +110,8 @@ public:
         AttributeFactory::registerAttribute<TagAttribute>();
     }
     bool initialized;
+    size_t notDeleted;
+    QStringList skipList;
 };
 
 K_GLOBAL_STATIC(StaticAttributeFactory, s_attributeInstance)
@@ -113,6 +127,9 @@ class AttributeFactory::Private
 {
 public:
     QHash<QByteArray, Attribute *> attributes;
+    Private() {
+        attributes.clear();
+    }
 };
 
 AttributeFactory *AttributeFactory::self()
@@ -132,18 +149,35 @@ AttributeFactory::~ AttributeFactory()
     delete d;
 }
 
+#include <QDebug>
 void AttributeFactory::registerAttribute(Attribute *attr)
 {
     Q_ASSERT(attr);
     Q_ASSERT(!attr->type().contains(' ') && !attr->type().contains('\'') && !attr->type().contains('"'));
     QHash<QByteArray, Attribute *>::Iterator it = d->attributes.find(attr->type());
     if (it != d->attributes.end()) {
-        delete *it;
+//         if (!s_attributeInstance->skipList.contains(QLatin1String(attr->type()))) {
+            delete *it;
+//         } else {
+//             s_attributeInstance->notDeleted += 1;
+//         }
         d->attributes.erase(it);
     }
     d->attributes.insert(attr->type(), attr);
 }
 
+void AttributeFactory::unRegisterAttribute(Attribute *attr)
+{
+    Q_ASSERT(attr);
+    Q_ASSERT(!attr->type().contains(' ') && !attr->type().contains('\'') && !attr->type().contains('"'));
+    kDebug(5250) << Q_FUNC_INFO << "deleting entry for type" << attr->type() << attr;
+    QHash<QByteArray, Attribute *>::Iterator it = d->attributes.find(attr->type());
+    if (it != d->attributes.end()) {
+        delete *it;
+        d->attributes.erase(it);
+    }
+}
+
 Attribute *AttributeFactory::createAttribute(const QByteArray &type)
 {
     Attribute *attr = self()->d->attributes.value(type);
diff --git akonadi/attributefactory.h akonadi/attributefactory.h
index 647b67e..be3b471 100644
--- akonadi/attributefactory.h
+++ akonadi/attributefactory.h
@@ -60,6 +60,16 @@ public:
     {
         AttributeFactory::self()->registerAttribute(new T);
     }
+    template <typename T> inline static T *getRegisteredAttribute()
+    {
+        T *attr = new T;
+        AttributeFactory::self()->registerAttribute(attr);
+        return attr;
+    }
+    inline static void deRegisterAttribute(Attribute *attr)
+    {
+        AttributeFactory::self()->unRegisterAttribute(attr);
+    }
 
     /**
      * Creates an entity attribute object of the given type.
@@ -76,6 +86,7 @@ protected:
 private:
     static AttributeFactory *self();
     void registerAttribute(Attribute *attribute);
+    void unRegisterAttribute(Attribute *attribute);
 
     class Private;
     Private *const d;
------------------------------------

Patch for kdepim4:
------------------------------------
diff --git noteshared/attributes/attributeregistrar.cpp noteshared/attributes/attributeregistrar.cpp
index cdcc949..56a61c0 100644
--- noteshared/attributes/attributeregistrar.cpp
+++ noteshared/attributes/attributeregistrar.cpp
@@ -22,19 +22,46 @@
 
 #include <akonadi/attributefactory.h>
 
+#include <KGlobal>
+#include <KDebug>
+
 namespace {
 
 // Anonymous namespace; function is invisible outside this file.
+
+class NoteSharedRegistrar {
+public:
+    NoteSharedRegistrar()
+    {
+      kDebug(5500) << Q_FUNC_INFO << this;
+      displayAttr = Akonadi::AttributeFactory::getRegisteredAttribute<NoteShared::NoteDisplayAttribute>();
+      alarmAttr = Akonadi::AttributeFactory::getRegisteredAttribute<NoteShared::NoteAlarmAttribute>();
+      lockAttr = Akonadi::AttributeFactory::getRegisteredAttribute<NoteShared::NoteLockAttribute>();
+      showAttr = Akonadi::AttributeFactory::getRegisteredAttribute<NoteShared::ShowFolderNotesAttribute>();
+    }
+    ~NoteSharedRegistrar()
+    {
+      kDebug(5500) << Q_FUNC_INFO << this;
+      Akonadi::AttributeFactory::deRegisterAttribute(displayAttr);
+      Akonadi::AttributeFactory::deRegisterAttribute(alarmAttr);
+      Akonadi::AttributeFactory::deRegisterAttribute(lockAttr);
+      Akonadi::AttributeFactory::deRegisterAttribute(showAttr);
+    }
+    NoteShared::NoteDisplayAttribute *displayAttr;
+    NoteShared::NoteAlarmAttribute *alarmAttr;
+    NoteShared::NoteLockAttribute *lockAttr;
+    NoteShared::ShowFolderNotesAttribute *showAttr;
+};
+K_GLOBAL_STATIC(NoteSharedRegistrar, s_registrarInstance)
+
 bool dummy()
 {
-  Akonadi::AttributeFactory::registerAttribute<NoteShared::NoteDisplayAttribute>();
-  Akonadi::AttributeFactory::registerAttribute<NoteShared::NoteAlarmAttribute>();
-  Akonadi::AttributeFactory::registerAttribute<NoteShared::NoteLockAttribute>();
-  Akonadi::AttributeFactory::registerAttribute<NoteShared::ShowFolderNotesAttribute>();
-  return true;
+    kDebug(5500) << "NoteSharedRegistrar=" << s_registrarInstance;
+    return s_registrarInstance != NULL;
 }
 
 // Called when this library is loaded.
 const bool registered = dummy();
 
+
 } // namespace
------------------------------------
Comment 6 RJVB 2016-10-14 20:35:16 UTC
#1 (anonymous namespace)::NoteSharedRegistrar::~NoteSharedRegistrar()() at .../kdepim-4.14.git/noteshared/attributes/attributeregistrar.cpp:44
#2 (anonymous namespace)::NoteSharedRegistrar::~NoteSharedRegistrar()() at .../kdepim-4.14.git/noteshared/attributes/attributeregistrar.cpp:43
#3 (anonymous namespace)::$_0::destroy()() at .../kdepim-4.14.git/noteshared/attributes/attributeregistrar.cpp:55
#4 __cxa_finalize() at ??:-1
#5 dyld::garbageCollectImages()() at ??:-1
#6 dlclose() at ??:-1
#7 dlclose() at ??:-1
#8 QLibraryPrivate::unload_sys()() at ??:-1
#9 QLibraryPrivate::unload()() at ??:-1
#10 QPluginLoader::unload()() at ??:-1
#11 KCModuleLoader::loadModule(KCModuleInfo const&, KCModuleLoader::ErrorReporting, QWidget*, QStringList const&)() at ??:-1
#12 KCModuleProxyPrivate::loadModule()() at ??:-1
#13 KCModuleProxy::realModule() const() at ??:-1
#14 KCMultiDialog::addModule(KCModuleInfo const&, KPageWidgetItem*, QStringList const&)() at ??:-1
#15 KSettings::DialogPrivate::createDialogFromServices()() at ??:-1
#16 KSettings::Dialog::showEvent(QShowEvent*)() at ??:-1
#17 QWidget::event(QEvent*)() at ??:-1
#18 QApplicationPrivate::notify_helper(QObject*, QEvent*)() at ??:-1
#19 QApplication::notify(QObject*, QEvent*)() at ??:-1
#20 QCoreApplication::notifyInternal(QObject*, QEvent*)() at ??:-1
Comment 7 RJVB 2016-10-16 08:40:41 UTC
I see there's been a chronological glitch in my comments :-/

I wonder: shouldn't it be more elegant to do the actual unregistering (attributes.erase(x)) in the Attribute dtor? I'll need to check if the Attribute dtor is actually called when libnoteshared is unloaded and that apparently leads to freeing memory allocated ("new'ed") by that library. If it is, a lot of the above patches will be handled automatically.
Comment 8 RJVB 2016-10-16 16:22:48 UTC
This bug has gotten under my skin. Having looked at this a bit more and asking around a bit, the most likely explanation for the crash is this:

- KCModuleLoader::loadModule() loads the library to get a pointer to the create_ function. The library registers its attributes.
- libnoteshared (or the kcm depending on it) doesn't have such a function, and so KCModuleLoader::loadModule() unloads the library again
- somewhat thereafter, the library (and/or the kcm depending on it) is loaded once more, and again registers its attributes
- the attribute factory finds a previous registration, and attempts to delete the registered attributes
- since the library was unloaded and reloaded since those attributes were "new'ed", the dtor lives (potentially) at a different address.
- delete *it invokes the dtor ... which may SEGV if the dtor address has changed.

I see that `KCModuleLoader::loadModule()` has hardly changed and not at all in the aspects outlined above. IOW, this bug is likely to occur in KDE PIM5 too if libnoteshared hasn't obtained a create_ function since.
Comment 9 Denis Kurz 2017-06-23 22:59:44 UTC
This bug has never been confirmed for a KDE PIM version that is based on KDE Frameworks, except possibly a Technology Preview version 5.0.x. Those Framework-based versions differ significantly from the old 4.x series. Therefore, I plan to close it in around two or three months. In the meantime, it is set to WAITINGFORINFO to give reporters the opportunity to check if it is still valid. As soon as someone confirms it for a recent version (at least 5.1, ideally even more recent), I'll gladly reopen it.

Please understand that we lack the manpower to triage bugs reported for versions almost two years beyond their end of life.

(Thanks for your detailed analysis, RJVB, but we cannot afford to keep bugs open just because there's a reason they *might still be relevant in recent versions)
Comment 10 Denis Kurz 2018-02-01 09:54:30 UTC
Just as announced in my last comment, I close this bug. If you encounter it again in a recent version (at least 5.1 aka 15.12; preferably much more recent), please open a new one unless it already exists. Thank you for all your input.