From 11409f4c023d7a9596ab5c0ca98256f650be9a90 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 20 Dec 2021 21:52:45 +0100 Subject: QStringBuilder: handle freeSpaceAtBegin() in op+= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amends 9b320edb535a0fbe118933d2e983b73f90c32685. The above commit made the mistake of relying on the 30yr+ old fundamental relation size() - capacity() == freeSpaceAtEnd() which, however, Qt 6's prepend()-optimization (freeSpaceAtBegin()) broke. Because of that, while size() - capacity() may be large enough to hold the new data, if freeSpaceAtBegin() > 0, then freeSpaceAtEnd() may not. Fix by inspecting freeSpaceAtEnd() instead of capacity(). The following reserve() call is unaffected, since it internally already adds freeSpaceAtBegin() to the requested size, which is why the unconditional reserve() in 9b320edb535a0fbe118933d2e983b73f90c32685^ worked while 9b320edb535a0fbe118933d2e983b73f90c32685's capacity() check did not. Fixes: QTBUG-99330 Pick-to: 6.2 6.3 Change-Id: I520f36216011423f97a24484263acd40d8b1fa43 Reviewed-by: Qt CI Bot Reviewed-by: Topi Reiniƶ Reviewed-by: Sona Kurazyan --- .../qstringbuilder1/stringbuilder.cpp | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp index 4d7e452e6f..de5277ab44 100644 --- a/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp @@ -73,6 +73,36 @@ template <> QByteArray toQByteArray(char * const &p) { return p; } template QByteArray toQByteArray(const char (&a)[N]) { return a; } template <> QByteArray toQByteArray(const char &c) { return QByteArray(&c, 1); } +template +void checkItWorksWithFreeSpaceAtBegin(const String &chunk, const Separator &separator) +{ + // GIVEN: a String with freeSpaceAtBegin() and less than chunk.size() freeSpaceAtEnd() + String str; + + int prepends = 0; + const int max_prepends = 10; + while (str.data_ptr().freeSpaceAtBegin() < chunk.size() && prepends++ < max_prepends) + str.prepend(chunk); + QVERIFY(prepends < max_prepends); + + int appends = 0; + const int max_appends = 100; + while (str.data_ptr().freeSpaceAtEnd() >= chunk.size() && appends++ < max_appends) + str.append(chunk); + QVERIFY(appends < max_appends); + + QVERIFY(str.capacity() - str.size() >= chunk.size()); + QVERIFY(str.data_ptr().freeSpaceAtEnd() < chunk.size()); + + // WHEN: adding a QStringBuilder expression which exceeds freeSpaceAtEnd() + str += separator P chunk; + + // THEN: it doesn't crash (QTBUG-99330) + const String expected = chunk.repeated(prepends + appends) + separator + chunk; + QCOMPARE(str, expected); +} + + void runScenario() { // this code is latin1. TODO: replace it with the utf8 block below, once @@ -329,6 +359,16 @@ void runScenario() QCOMPARE(str2, str2_e); } + checkItWorksWithFreeSpaceAtBegin(QString::fromUtf8(UTF8_LITERAL), + #ifdef QT_NO_CAST_FROM_ASCII + QLatin1String("1234") + #else + "1234" + #endif + ); + if (QTest::currentTestFailed()) + return; + //operator QByteArray += { QByteArray ba = UTF8_LITERAL; @@ -350,4 +390,7 @@ void runScenario() QCOMPARE(byteArray, "multipart/mixed; boundary=\"oooooooooooooooooooooooooooooo\""); } + checkItWorksWithFreeSpaceAtBegin(QByteArray(UTF8_LITERAL), "1234"); + if (QTest::currentTestFailed()) + return; } -- cgit v1.2.3