From cc3cb77f62ddbd4667c7ad51e9c5c8718dd53b1b Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 6 Apr 2021 14:12:03 +0200 Subject: [PATCH] Avoid attempting to parse insanely long texts as zone names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are limits on zone name length and the trial-and-error approach we're more or less forced to take to parsing gets horribly expensive if applied to every prefix of a very long string. So apply a loosened version of the zone-name validity rule that limits the length of the fragments between slashes and limit the number of such fragments. Fixes: QTBUG-92275 Change-Id: I83052b1b6888728c81135db22a9c6298ae439375 Reviewed-by: Robert Löhning Reviewed-by: Thiago Macieira (cherry picked from commit 0c9fc20e7ff7b4ff0f15e0b2c071ea834625dce9) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/time/qdatetimeparser.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp index a36eded2e5c..7bee5a68b14 100644 --- a/src/corelib/time/qdatetimeparser.cpp +++ b/src/corelib/time/qdatetimeparser.cpp @@ -1740,6 +1740,24 @@ QDateTimeParser::findTimeZoneName(QStringView str, const QDateTime &when) const int index = std::distance(str.cbegin(), std::find_if(str.cbegin(), str.cend(), invalidZoneNameCharacter)); + // Limit name fragments (between slashes) to 20 characters. + // (Valid time-zone IDs are allowed up to 14 and Android has quirks up to 17.) + // Limit number of fragments to six; no known zone name has more than four. + int lastSlash = -1; + int count = 0; + Q_ASSERT(index <= str.size()); + while (lastSlash < index) { + int slash = str.indexOf(QLatin1Char('/'), lastSlash + 1); + if (slash < 0) + slash = index; // i.e. the end of the candidate text + else if (++count > 5) + index = slash; // Truncate + if (slash - lastSlash > 20) + index = lastSlash + 20; // Truncate + // If any of those conditions was met, index <= slash, so this exits the loop: + lastSlash = slash; + } + for (; index > systemLength; --index) { // Find longest match str.truncate(index); QTimeZone zone(str.toLatin1());