Why does this TopDUContext mod lead to crashes?

René J.V. Bertin rjvbertin at gmail.com
Tue Apr 30 19:27:06 BST 2019


Hi,

So yesterday I made a change to ReferencedToDUContext and TopDUContext which stops the test_duchain-clang test from crashing because of accessing stale TopDUContext instances:
https://bugs.kde.org/attachment.cgi?id=119731&action=edit

The principle is simple: let each TopDUContext instance keep a track of the ReferencedTopDUContext instances that refer to it (via a QSet). When the TopDUContext is deleted it can set the m_topContext variable of those references to a nullptr so that those references can be queried safely elsewhere (and cleaned up).

This works, and for a while I thought that there were no side-effects, but then I started getting random crashes while inserting a valid (AFAICT) ReferencedTopDUContext into an equally valid (AFAICT) TopDUContext, for example deep under a recursive call to ClangHelpers::buildDUChain() (part of a backtrace below). I also tried with a QVector instead of a QSet, that just moved the crash.

That ClangHelpers::buildDUChain() function is surprising because it returns a local ReferencedTopDUContext instance but I have to presume that this is OK because ReferencedTopDUContext has an assignment operator? If that is true I don't see how a QSet operation could fail on a hash node that is neither NULL nor a valid pointer.

Unless maybe references to the same TopDUContext item can be created from multiple threads? IOW, should the m_references QSet have a mutex to protect against concurrent access?

Thanks if someone can and is willing to shed some light on this!
R.


-----
Process 76864 stopped
* thread #190: tid = 0x230771, 0x000000010cc8e8b0 libKDevPlatformLanguage.53.dylib`QHash<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::insert(KDevelop::ReferencedTopDUContext* const&, QHashDummyValue const&) [inlined] QHashNode<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::same_key(this=0x0000000100000001, h0=<unavailable>) const + 15 at qhash.h:177, name = 'Queue(0x7f8a739870f0)[01]', stop reason = EXC_BAD_ACCESS (code=1, address=0x100000009)
    frame #0: 0x000000010cc8e8b0 libKDevPlatformLanguage.53.dylib`QHash<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::insert(KDevelop::ReferencedTopDUContext* const&, QHashDummyValue const&) [inlined] QHashNode<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::same_key(this=0x0000000100000001, h0=<unavailable>) const + 15 at qhash.h:177
   174  
   175      inline QHashNode(const Key &key0, const QHashDummyValue &, uint hash, QHashNode *n)
   176          : next(n), h(hash), key(key0) {}
-> 177      inline bool same_key(uint h0, const Key &key0) const { return h0 == h && key0 == key; }
   178  
   179  private:
   180      Q_DISABLE_COPY(QHashNode)
(lldb) bt
* thread #190: tid = 0x230771, 0x000000010cc8e8b0 libKDevPlatformLanguage.53.dylib`QHash<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::insert(KDevelop::ReferencedTopDUContext* const&, QHashDummyValue const&) [inlined] QHashNode<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::same_key(this=0x0000000100000001, h0=<unavailable>) const + 15 at qhash.h:177, name = 'Queue(0x7f8a739870f0)[01]', stop reason = EXC_BAD_ACCESS (code=1, address=0x100000009)
  * frame #0: 0x000000010cc8e8b0 libKDevPlatformLanguage.53.dylib`QHash<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::insert(KDevelop::ReferencedTopDUContext* const&, QHashDummyValue const&) [inlined] QHashNode<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::same_key(this=0x0000000100000001, h0=<unavailable>) const + 15 at qhash.h:177
    frame #1: 0x000000010cc8e8a1 libKDevPlatformLanguage.53.dylib`QHash<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::insert(KDevelop::ReferencedTopDUContext* const&, QHashDummyValue const&) [inlined] QHash<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::findNode(this=<unavailable>, h=444423924) const + 37 at qhash.h:908
    frame #2: 0x000000010cc8e87c libKDevPlatformLanguage.53.dylib`QHash<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::insert(KDevelop::ReferencedTopDUContext* const&, QHashDummyValue const&) [inlined] QHash<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::findNode(KDevelop::ReferencedTopDUContext* const&, unsigned int*) const + 23 at qhash.h:927
    frame #3: 0x000000010cc8e865 libKDevPlatformLanguage.53.dylib`QHash<KDevelop::ReferencedTopDUContext*, QHashDummyValue>::insert(this=0x00007f8a78cf7ce0, akey=0x000000011a8a23a0, avalue=<unavailable>) + 117 at qhash.h:763
    frame #4: 0x000000010cc862d8 libKDevPlatformLanguage.53.dylib`KDevelop::ReferencedTopDUContext::operator=(KDevelop::ReferencedTopDUContext const&) [inlined] QSet<KDevelop::ReferencedTopDUContext*>::insert(this=<unavailable>, value=0x000000011a8a24a0) + 120 at qset.h:205
    frame #5: 0x000000010cc862c7 libKDevPlatformLanguage.53.dylib`KDevelop::ReferencedTopDUContext::operator=(this=0x000000011a8a24a0, rhs=0x000000011a8a2470) + 103 at topducontext.cpp:92
    frame #6: 0x00000001207e3642 libKDevClangPrivate.31.dylib`ClangHelpers::buildDUChain(file=<unavailable>, imports=0x000000011a8a3d10, session=0x000000011a8a3d28, features=AllDeclarationsContextsAndUses, includedFiles=<unavailable>, index=<unavailable>, abortFunction=<unavailable>)> const&) + 1154 at clanghelpers.cpp:144
    frame #7: 0x00000001207e3442 libKDevClangPrivate.31.dylib`ClangHelpers::buildDUChain(file=0x00007f8a78ef9220, imports=0x000000011a8a3d10, session=0x000000011a8a3d28, features=AllDeclarationsContextsAndUses, includedFiles=<unavailable>, index=<unavailable>, abortFunction=<unavailable>)> const&) + 642 at clanghelpers.cpp:128
    frame #8: 0x00000001207e3442 libKDevClangPrivate.31.dylib`ClangHelpers::buildDUChain(file=0x00007f8a78f02c80, imports=0x000000011a8a3d10, session=0x000000011a8a3d28, features=AllDeclarationsContextsAndUses, includedFiles=<unavailable>, index=<unavailable>, abortFunction=<unavailable>)> const&) + 642 at clanghelpers.cpp:128



More information about the KDevelop-devel mailing list