Fix crash when doing many text layouts with superscript/subscript

After e109b8a0f3, it is possible
that the cache will be flushed as a result of inserting a new
font rather than just when the timer event triggers. When doing
superscript and subscript text layouts, we would first get
a regular font engine, then a scaled one, and then reference
the regular font engine *after* getting the scaled one. If the
regular font engine was deleted as a result of inserting the scaled
one, we would get a dangling pointer and crash.

The situation was improved by 49926bb9ef.
You would now to switch between 256 different fonts in the layout
in order to trigger it. The test in the commit will trigger the
crash even with this change.

[ChangeLog][Qt Gui][Text] Fixed a crash that could happen if you
were doing many different text layouts with different fonts
and superscript or subscript alignment.

Task-number: QTBUG-53911
Change-Id: Ia33108252e030eff25924ef1b7c10b9d59b5bc8c
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2016-09-28 12:18:11 +02:00
parent 422838685c
commit 462f6029ed
2 changed files with 62 additions and 4 deletions

View File

@ -2058,6 +2058,9 @@ QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFix
font = font.resolve(fnt);
}
engine = font.d->engineForScript(script);
if (engine)
engine->ref.ref();
QTextCharFormat::VerticalAlignment valign = f.verticalAlignment();
if (valign == QTextCharFormat::AlignSuperScript || valign == QTextCharFormat::AlignSubScript) {
if (font.pointSize() != -1)
@ -2065,16 +2068,14 @@ QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFix
else
font.setPixelSize((font.pixelSize() * 2) / 3);
scaledEngine = font.d->engineForScript(script);
if (scaledEngine)
scaledEngine->ref.ref();
}
if (engine)
engine->ref.ref();
if (feCache.prevFontEngine)
releaseCachedFontEngine(feCache.prevFontEngine);
feCache.prevFontEngine = engine;
if (scaledEngine)
scaledEngine->ref.ref();
if (feCache.prevScaledFontEngine)
releaseCachedFontEngine(feCache.prevScaledFontEngine);
feCache.prevScaledFontEngine = scaledEngine;

View File

@ -143,6 +143,7 @@ private slots:
void cursorInNonStopChars();
void nbsp();
void noModificationOfInputString();
void superscriptCrash_qtbug53911();
private:
QFont testFont;
@ -2209,5 +2210,61 @@ void tst_QTextLayout::noModificationOfInputString()
}
}
void tst_QTextLayout::superscriptCrash_qtbug53911()
{
static int fontSizes = 64;
static QString layoutText = "THIS IS SOME EXAMPLE TEXT THIS IS SOME EXAMPLE TEXT";
QList<QTextLayout*> textLayouts;
for (int i = 0; i < fontSizes; ++i) {
for (int j = 0; j < 4; ++j) {
QTextLayout* newTextLayout = new QTextLayout();
newTextLayout->setText(layoutText);
QList<QTextLayout::FormatRange> formatRanges;
QTextLayout::FormatRange formatRange;
formatRange.format.setFont(QFont());
formatRange.format.setFontPointSize(i + 5);
switch (j) {
case 0:
formatRange.format.setFontWeight(QFont::Normal);
formatRange.format.setFontItalic(false);
break;
case 1:
formatRange.format.setFontWeight(QFont::Bold);
formatRange.format.setFontItalic(false);
break;
case 2:
formatRange.format.setFontWeight(QFont::Bold);
formatRange.format.setFontItalic(true);
break;
case 3:
formatRange.format.setFontWeight(QFont::Normal);
formatRange.format.setFontItalic(true);
break;
}
formatRange.format.setVerticalAlignment( QTextCharFormat::AlignSuperScript);
formatRange.start = 0;
formatRange.length = layoutText.size();
formatRanges << formatRange;
newTextLayout->setAdditionalFormats(formatRanges);
textLayouts.push_front(newTextLayout);
}
}
// This loop would crash before fix for QTBUG-53911
foreach (QTextLayout *textLayout, textLayouts) {
textLayout->beginLayout();
while (textLayout->createLine().isValid());
textLayout->endLayout();
}
qDeleteAll(textLayouts);
}
QTEST_MAIN(tst_QTextLayout)
#include "tst_qtextlayout.moc"