From af267657ea11e292012ac02634e8bd2dcf8328c7 Mon Sep 17 00:00:00 2001
From: wang_yue111 <648774160@qq.com>
Date: Wed, 21 Apr 2021 11:35:47 +0800
Subject: [PATCH] Fix crash when text contains too many directional chars

In case a text to be layouted contains more than 128 directional characters
it causes the application to crash

The function initScriptAnalysisAndIsolatePairs() collects information of
RTL/LTR chaaracters into vector "isolatePairs". The size of the vector is
capped to 128. Later the function generateDirectionalRuns() iterates
the text again and tries to access items from the previously capped vector
above the upper bound.

Task-number: QTBUG-77819
Change-Id: Ibb7bf12c12b1db22f43ff46236518da3fdeed26a
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
(cherry picked from commit 1232205e32464d90e871f39eb1e14fcf9b78a163)
Reviewed-by: Jukka Jokiniva <jukka.jokiniva@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
---
 src/gui/text/qtextengine.cpp                    | 15 +++++++--------
 .../gui/text/qtextlayout/tst_qtextlayout.cpp    | 17 +++++++++++++++++
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 5e38311f..0c405cbf 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -393,6 +393,7 @@ struct QBidiAlgorithm {
                         analysis[i].bidiDirection = (level & 1) ? QChar::DirR : QChar::DirL;
                     runHasContent = true;
                     lastRunWithContent = -1;
+                    ++isolatePairPosition;
                 }
                 int runBeforeIsolate = runs.size();
                 ushort newLevel = isRtl ? ((stack.top().level + 1) | 1) : ((stack.top().level + 2) & ~1);
@@ -434,20 +435,18 @@ struct QBidiAlgorithm {
                 doEmbed(true, true, false);
                 break;
             case QChar::DirLRI:
-                ++isolatePairPosition;
-                Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i);
                 doEmbed(false, false, true);
                 break;
             case QChar::DirRLI:
-                ++isolatePairPosition;
-                Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i);
                 doEmbed(true, false, true);
                 break;
             case QChar::DirFSI: {
-                ++isolatePairPosition;
-                const auto &pair = isolatePairs.at(isolatePairPosition);
-                Q_ASSERT(pair.start == i);
-                bool isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft();
+		bool isRtl = false;
+		if (isolatePairPosition < isolatePairs.size()) {
+		    const auto &pair = isolatePairs.at(isolatePairPosition);
+		    Q_ASSERT(pair.start == i);
+		    isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft();
+		}
                 doEmbed(isRtl, false, true);
                 break;
             }
diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
index 4e3d1da8..ec8b6116 100644
--- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
+++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
@@ -137,6 +137,7 @@ private slots:
     void nbspWithFormat();
     void noModificationOfInputString();
     void superscriptCrash_qtbug53911();
+    void tooManyDirectionalCharctersCrash_qtbug77819();
 
 private:
     QFont testFont;
@@ -2291,5 +2292,21 @@ void tst_QTextLayout::nbspWithFormat()
     QCOMPARE(layout.lineAt(1).textLength(), s2.length() + 1 + s3.length());
 }
 
+void tst_QTextLayout::tooManyDirectionalCharctersCrash_qtbug77819()
+{
+    QString data;
+    data += QString::fromUtf8("\xe2\x81\xa8"); // U+2068 FSI character
+    data += QString::fromUtf8("\xe2\x81\xa7"); // U+2067 RLI character
+
+    // duplicating the text
+    for (int i = 0; i < 10; i++)
+        data += data;
+
+    // Nothing to test. It must not crash in beginLayout().
+    QTextLayout tl(data);
+    tl.beginLayout();
+    tl.endLayout();
+}
+
 QTEST_MAIN(tst_QTextLayout)
 #include "tst_qtextlayout.moc"
-- 
2.23.0

