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

Regression: Crash - Multi-threaded text layout with superscript text de-refs a nullptr in QFontEngine due to a race condition

    XMLWordPrintable

Details

    • 462f6029ed7ab34b76afc009b95134d4e51a8e18

    Description

      Update: I believe this is a regression from 5.5 to 5.6 due to change id Iedc042d8903949140aa8c5257a9d54cde31a51be

      We perform multi-threaded text layout on numerous independent QTextLayouts simultaneously.

      However if multiple text layouts contain superscript text, we are seeing a null-pointer deref in a race condition in the following function:

      qtextengine.cpp
      QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFixed *descent, QFixed *leading) const {}
      

      It appears that in one thread we're seeing the following part of the function called:

      qtextengine.cpp
                      if (valign == QTextCharFormat::AlignSuperScript || valign == QTextCharFormat::AlignSubScript) {
                          if (font.pointSize() != -1)
                              font.setPointSize((font.pointSize() * 2) / 3);
                          else
                              font.setPixelSize((font.pixelSize() * 2) / 3);
                          scaledEngine = font.d->engineForScript(script);
                      }
      

      and inside "engineForScript" I can see the following comment:

      qfont.cpp
          if (engineData && engineData->fontCacheId != QFontCache::instance()->id()) {
              // throw out engineData that came from a different thread
              if (!engineData->ref.deref())
                  delete engineData;
              engineData = 0;
          }
      

      The actual crash is happening in another thread on the following line:

      qtextengine.cpp
      QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFixed *descent, QFixed *leading) const
      {
      <SNIP>
          if (ascent) {
              *ascent = engine->ascent();
              *descent = engine->descent();
              *leading = engine->leading();
          }
      }
      

      The engine pointer is not guarded and by this point is a nullptr. (engine->ascent())

      Attachments

        1. mainwindow.cpp
          3 kB
        2. mainwindow.hpp
          0.6 kB
        3. qtbug53911.zip
          2 kB
        For Gerrit Dashboard: QTBUG-53911
        # Subject Branch Project Status CR V

        Activity

          People

            esabraha Eskil Abrahamsen Blomfeldt
            lmv Luke
            Votes:
            7 Vote for this issue
            Watchers:
            11 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes