Avoid attempting to parse insanely long texts as zone names

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
Pick-to: 6.1 6.0 5.15
Change-Id: I83052b1b6888728c81135db22a9c6298ae439375
Reviewed-by: Robert Löhning <robert.loehning@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2021-04-06 14:12:03 +02:00
parent 89bdd09670
commit 0c9fc20e7f

View File

@ -1740,6 +1740,24 @@ QDateTimeParser::findTimeZoneName(QStringView str, const QDateTime &when) const
int index = std::distance(str.cbegin(), int index = std::distance(str.cbegin(),
std::find_if(str.cbegin(), str.cend(), invalidZoneNameCharacter)); 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 for (; index > systemLength; --index) { // Find longest match
str.truncate(index); str.truncate(index);
QTimeZone zone(str.toLatin1()); QTimeZone zone(str.toLatin1());