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

Crash on quit, perhaps with a double dealloc of private Qt data

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Not Evaluated
    • Resolution: Duplicate
    • Affects Version/s: 5.14.2
    • Fix Version/s: 5.15.1
    • Labels:
      None
    • Environment:
      macOS 10.15.6
    • Platform/s:
      macOS
    • Commits:
      2eba5cb403b2f2812bca5563183f42a3211c9d07

      Description

      OK, this is a weird one.  Because of QTBUG-86874, I am trying to postpone the dealloc of the main windows in my app, having just close with no dealloc, because that fixes problems with menu item relation in the global menu bar on macOS (see that bug for more background info).  Unfortunately, doing this causes a crash that seems to be a bug in Qt, although perhaps I'm doing something I shouldn't.

      First of all, here's the backtrace for the crash:

      1 QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>>::operator->() const qscopedpointer.h 118 0x10201b594
      2 decltype(fp.operator->()) qGetPtrHelper<QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>> const>(QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>> const&) qglobal.h 1133 0x10201b594
      3 QObject::d_func() const qobject.h 132 0x10201b594
      4 QObject::thread() const qobject.cpp 1512 0x10201b594
      5 QOpenGLVertexArrayObjectPrivate::destroy() qopenglvertexarrayobject.cpp 212 0x101b21481
      6 QOpenGLVertexArrayObject::destroy() qopenglvertexarrayobject.cpp 424 0x101b217cc
      7 QOpenGLVertexArrayObject::~QOpenGLVertexArrayObject() qopenglvertexarrayobject.cpp 392 0x101b217c3
      8 QOpenGLVertexArrayObject::~QOpenGLVertexArrayObject() qopenglvertexarrayobject.cpp 391 0x101b217b9
      9 QOpenGLTextureGlyphCache::~QOpenGLTextureGlyphCache() qopengltextureglyphcache.cpp 93 0x101b1cacd
      10 QOpenGLTextureGlyphCache::~QOpenGLTextureGlyphCache() qopengltextureglyphcache.cpp 88 0x101b1cbce
      11 QOpenGLTextureGlyphCache::~QOpenGLTextureGlyphCache() qopengltextureglyphcache.cpp 88 0x101b1cbc9
      12 QExplicitlySharedDataPointer<QFontEngineGlyphCache>::~QExplicitlySharedDataPointer() qshareddata.h 184 0x101883c92
      13 QExplicitlySharedDataPointer<QFontEngineGlyphCache>::~QExplicitlySharedDataPointer() qshareddata.h 184 0x101883c74
      14 QFontEngine::GlyphCacheEntry::~GlyphCacheEntry() qfontengine.cpp 1570 0x101883c74
      15 QFontEngine::GlyphCacheEntry::~GlyphCacheEntry() qfontengine.cpp 1569 0x101883c74
      16 void std::allocator_traits<std::allocator<std::_list_node<QFontEngine::GlyphCacheEntry, void *>>>::destroy<QFontEngine::GlyphCacheEntry>(std::integral_constant<bool, false>, std::allocator<std::_list_node<QFontEngine::GlyphCacheEntry, void *>>&, QFontEngine::GlyphCacheEntry *) memory 1732 0x101883c74
      17 void std::allocator_traits<std::allocator<std::_list_node<QFontEngine::GlyphCacheEntry, void *>>>::destroy<QFontEngine::GlyphCacheEntry>(std::allocator<std::_list_node<QFontEngine::GlyphCacheEntry, void *>>&, QFontEngine::GlyphCacheEntry *) memory 1595 0x101883c74
      18 std::__list_imp<QFontEngine::GlyphCacheEntry, std::allocator<QFontEngine::GlyphCacheEntry>>::clear() list 733 0x101883c74
      19 std::_list_imp<QFontEngine::GlyphCacheEntry, std::allocator<QFontEngine::GlyphCacheEntry>>::~_list_imp() list 712 0x101883c24
      20 std::list<QFontEngine::GlyphCacheEntry>::~list() list 805 0x101883c24
      21 std::list<QFontEngine::GlyphCacheEntry>::~list() list 805 0x101883c24
      22 QHashNode<void const *, std::list<QFontEngine::GlyphCacheEntry>>::~QHashNode() qhash.h 147 0x101883c24
      23 QHashNode<void const *, std::list<QFontEngine::GlyphCacheEntry>>::~QHashNode() qhash.h 147 0x101883c24
      24 QHash<void const *, std::list<QFontEngine::GlyphCacheEntry>>::deleteNode2(QHashData::Node *) qhash.h 563 0x101883c24
      25 QHashData::free_helper(void ( *)(QHashData::Node *)) qhash.cpp 572 0x101e5db39
      26 QHash<void const *, std::list<QFontEngine::GlyphCacheEntry>>::freeData(QHashData *) qhash.h 603 0x10187a47b
      27 QHash<void const *, std::list<QFontEngine::GlyphCacheEntry>>::~QHash() qhash.h 250 0x10187a46f
      28 QHash<void const *, std::list<QFontEngine::GlyphCacheEntry>>::~QHash() qhash.h 250 0x10187a44f
      29 QFontEngine::~QFontEngine() qfontengine.cpp 277 0x10187a44f
      30 QCoreTextFontEngine::~QCoreTextFontEngine() qfontengine_coretext.mm 215 0x105b7cf8e
      31 QCoreTextFontEngine::~QCoreTextFontEngine() qfontengine_coretext.mm 215 0x105b7cf89
      32 QFontEngineMulti::~QFontEngineMulti() qfontengine.cpp 1782 0x101880039
      33 QFontEngineMulti::~QFontEngineMulti() qfontengine.cpp 1778 0x10188012e
      34 QFontEngineMulti::~QFontEngineMulti() qfontengine.cpp 1778 0x101880129
      35 QFontCache::clear() qfont.cpp 2861 0x1018762eb
      36 QFontCache::~QFontCache() qfont.cpp 2817 0x10187603c
      37 QFontCache::~QFontCache() qfont.cpp 2816 0x1018763ee
      38 QFontCache::~QFontCache() qfont.cpp 2816 0x1018763e9
      39 QThreadStorageData::set(void *) qthreadstorage.cpp 162 0x101e25777
      40 QGuiApplicationPrivate::~QGuiApplicationPrivate() qguiapplication.cpp 1694 0x1017ca490
      41 QApplicationPrivate::~QApplicationPrivate() qapplication.cpp 184 0x10116f81e
      42 QApplicationPrivate::~QApplicationPrivate() qapplication.cpp 184 0x10116f819
      43 QScopedPointerDeleter<QObjectData>::cleanup(QObjectData *) qscopedpointer.h 60 0x10201c06c
      44 QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>>::~QScopedPointer() qscopedpointer.h 107 0x10201c061
      45 QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>>::~QScopedPointer() qscopedpointer.h 105 0x10201c05d
      46 QObject::~QObject() qobject.cpp 1119 0x10201c05d
      47 QApplication::~QApplication() qapplication.cpp 837 0x101171b3d
      48 main main.cpp 246 0x100012256
      49 start (x86_64) /usr/lib/system/libdyld.dylib 0x7fff6b461cc9

      As you can see, we're deep inside deallocations for private data held by QApplication – specifically, some kind of font glyph caching related to OpenGL rendering.  I ran AddressSanitizer on this, and here's the result:

      AddressSanitizer:DEADLYSIGNAL
      =================================================================
      ==13763==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00010bd9d594 bp 0x7ffee6d5b070 sp 0x7ffee6d5b070 T0)
      ==13763==The signal is caused by a READ memory access.
      ==13763==Hint: address points to the zero page.
          #0 0x10bd9d593 in QObject::thread() const qobject.cpp:1511
          #1 0x10b8a0480 in QOpenGLVertexArrayObjectPrivate::destroy() qopenglvertexarrayobject.cpp:212
          #2 0x10b8a07cb in QOpenGLVertexArrayObject::~QOpenGLVertexArrayObject() qopenglvertexarrayobject.cpp:391
      ...  
      AddressSanitizer can not provide additional info.
      SUMMARY: AddressSanitizer: SEGV qobject.cpp:1511 in QObject::thread() const
      ==13763==ABORTING

      So, this is an attempted dereference of address 0x08, which is the "d" pointer inside QScopedPointer, visible in the crash backtrace (not shown in ASAN's backtrace, I would speculate, because it is probably inlined).  Of course QScopedPointer itself is not the problem here; the problem seems to be a double dealloc at some level of the object tree.

      Since it seems to be related to fonts, I commented out every usage of QFont in my app, and that did indeed fix the bug – no more crash on quit.  I then started uncommenting those usages one by one, but the first one I uncommented already triggered the bug again.  The code in question:

      static QFont *tickFont = nullptr;
      if (!tickFont)

      {     tickFont = new QFont();     tickFont->setPointSize(9); }

      painter.setFont(*tickFont);

      If I comment this out, no crash on quit; if I uncomment it, crash on quit.  The tickFont variable is used only in this one spot.  Although this code seems quite innocent, I thought maybe there was something naughty that I wasn't aware of about keeping a permanent QFont instance in a static local, so I tried changing it to this:

      QFont tickFont;
      tickFont.setPointSize(9);
      painter.setFont(tickFont);

      This code, surely, is not problematic; but it still crashes on quit, 100% reproducibly.

      Note that this crash also happens only when I try to defer the dealloc of my main windows, by not calling setAttribute(Qt::WA_DeleteOnClose) on them, as discussed more in QTBUG-86874.  If I set that attribute so they dealloc on close, then there is no crash on quit (but then the global menubar is screwed up, as discussed in the other bug).

      The third important ingredient is where that font code lives: in the paintGL() method of a QOpenGLWidget subclass, where I use the painter, with the font set, to measure and draw text.  That brings in the OpenGL font cache stuff that appears in the backtrace of the crash.  It appears that that cached stuff somehow gets dealloced twice, if the dealloc of the main window is deferred.  Or something like that; that's as far as my detective work got me, anyway.  It's a pretty obscure scenario, but since it's a crash it seemed worth reporting.

        Attachments

          Issue Links

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

            Activity

              People

              Assignee:
              esabraha Eskil Abrahamsen Blomfeldt
              Reporter:
              bhaller Ben Haller
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:

                  Gerrit Reviews

                  There are no open Gerrit changes