summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/io/qipaddress.cpp28
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp16
-rw-r--r--src/corelib/text/qlocale.cpp28
-rw-r--r--src/corelib/text/qlocale_tools.cpp20
-rw-r--r--src/corelib/text/qlocale_tools_p.h5
-rw-r--r--src/corelib/text/qlocale_win.cpp8
-rw-r--r--src/corelib/text/qstring.cpp6
-rw-r--r--src/corelib/time/qtimezoneprivate_tz.cpp12
-rw-r--r--src/corelib/tools/qhash.cpp2
-rw-r--r--src/corelib/tools/qversionnumber.cpp8
-rw-r--r--tests/auto/corelib/text/qlocale/tst_qlocale.cpp14
11 files changed, 80 insertions, 67 deletions
diff --git a/src/corelib/io/qipaddress.cpp b/src/corelib/io/qipaddress.cpp
index feed38bef6..444a38a319 100644
--- a/src/corelib/io/qipaddress.cpp
+++ b/src/corelib/io/qipaddress.cpp
@@ -60,12 +60,12 @@ static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptL
ptr[1] != '.' && ptr[1] != '\0')
return false;
- auto [ll, endptr] = qstrntoull(ptr, stop - ptr, 0);
+ auto [ll, used] = qstrntoull(ptr, stop - ptr, 0);
quint32 x = ll;
- if (!endptr || endptr == ptr || ll != x)
+ if (used <= 0 || ll != x)
return false;
- if (*endptr == '.' || dotCount == 3) {
+ if (ptr[used] == '.' || dotCount == 3) {
if (x & ~0xff)
return false;
address <<= 8;
@@ -80,13 +80,13 @@ static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptL
}
address |= x;
- if (dotCount == 3 || *endptr == '\0')
- return *endptr == '\0';
- if (*endptr != '.')
+ if (dotCount == 3 || ptr[used] == '\0')
+ return ptr[used] == '\0';
+ if (ptr[used] != '.')
return false;
++dotCount;
- ptr = endptr + 1;
+ ptr += used + 1;
}
return false;
}
@@ -174,16 +174,16 @@ const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end
continue;
}
- auto [ll, endptr] = qstrntoull(ptr, stop - ptr, 16);
+ auto [ll, used] = qstrntoull(ptr, stop - ptr, 16);
quint16 x = ll;
// Reject malformed fields:
// - failed to parse
// - too many hex digits
- if (!endptr || endptr > ptr + 4)
+ if (used <= 0 || used > 4)
return begin + (ptr - buffer.data());
- if (*endptr == '.') {
+ if (ptr[used] == '.') {
// this could be an IPv4 address
// it's only valid in the last element
if (pos != 12)
@@ -203,11 +203,11 @@ const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end
address[pos++] = x >> 8;
address[pos++] = x & 0xff;
- if (*endptr == '\0')
+ if (ptr[used] == '\0')
break;
- if (*endptr != ':')
- return begin + (endptr - buffer.data());
- ptr = endptr + 1;
+ if (ptr[used] != ':')
+ return begin + (used + ptr - buffer.data());
+ ptr += used + 1;
}
return pos == 16 ? nullptr : end;
}
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index be3bf0252d..d815708ab0 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -459,27 +459,31 @@ inline bool QStorageIterator::next()
return false;
mnt.mount_id = r.result;
- r = qstrntoll(r.endptr, stop - r.endptr, 10);
+ ptr += r.used;
+ r = qstrntoll(ptr, stop - ptr, 10);
if (!r.ok())
return false;
int parent_id = r.result;
Q_UNUSED(parent_id);
- r = qstrntoll(r.endptr, stop - r.endptr, 10);
+ ptr += r.used;
+ r = qstrntoll(ptr, stop - ptr, 10);
if (!r.ok())
return false;
- if (*r.endptr != ':')
+ ptr += r.used;
+ if (*ptr != ':')
return false;
int rdevmajor = r.result;
- r = qstrntoll(r.endptr + 1, stop - r.endptr - 1, 10);
+ ++ptr; // Skip over the ':'
+ r = qstrntoll(ptr, stop - ptr, 10);
if (!r.ok())
return false;
mnt.rdev = makedev(rdevmajor, r.result);
- if (*r.endptr != ' ')
+ ptr += r.used;
+ if (*ptr != ' ')
return false;
- ptr = const_cast<char *>(r.endptr);
mnt.subvolume = ++ptr;
ptr = parseMangledPath(ptr);
if (!ptr)
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index 97d84eac4e..23534cbb58 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -4145,20 +4145,20 @@ qulonglong QLocaleData::stringToUnsLongLong(QStringView str, int base, bool *ok,
qlonglong QLocaleData::bytearrayToLongLong(QByteArrayView num, int base, bool *ok)
{
- auto [l, endptr] = qstrntoll(num.data(), num.size(), base);
- if (!endptr) {
+ const qsizetype len = num.size();
+ auto [l, used] = qstrntoll(num.data(), len, base);
+ if (used <= 0) {
if (ok != nullptr)
*ok = false;
return 0;
}
- const char *const stop = num.end();
- if (endptr < stop && *endptr != '\0') {
- while (endptr < stop && ascii_isspace(*endptr))
- ++endptr;
+ if (used < len && num[used] != '\0') {
+ while (used < len && ascii_isspace(num[used]))
+ ++used;
}
- if (endptr < stop && *endptr != '\0') {
+ if (used < len && num[used] != '\0') {
// we stopped at a non-digit character after converting some digits
if (ok != nullptr)
*ok = false;
@@ -4172,20 +4172,20 @@ qlonglong QLocaleData::bytearrayToLongLong(QByteArrayView num, int base, bool *o
qulonglong QLocaleData::bytearrayToUnsLongLong(QByteArrayView num, int base, bool *ok)
{
- auto [l, endptr] = qstrntoull(num.data(), num.size(), base);
- if (!endptr) {
+ const qsizetype len = num.size();
+ auto [l, used] = qstrntoull(num.data(), len, base);
+ if (used <= 0) {
if (ok != nullptr)
*ok = false;
return 0;
}
- const char *const stop = num.end();
- if (endptr < stop && *endptr != '\0') {
- while (endptr < stop && ascii_isspace(*endptr))
- ++endptr;
+ if (used < len && num[used] != '\0') {
+ while (used < len && ascii_isspace(num[used]))
+ ++used;
}
- if (endptr < stop && *endptr != '\0') {
+ if (used < len && num[used] != '\0') {
if (ok != nullptr)
*ok = false;
return 0;
diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp
index 5d439f2b26..ac4c870802 100644
--- a/src/corelib/text/qlocale_tools.cpp
+++ b/src/corelib/text/qlocale_tools.cpp
@@ -194,7 +194,7 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision,
auto r = qstrntoll(target.data() + eSign + 1, length - eSign - 1, 10);
decpt = r.result + 1;
Q_ASSERT(r.ok());
- Q_ASSERT(r.endptr - target.data() <= length);
+ Q_ASSERT(r.used + eSign + 1 <= length);
} else {
// No 'e' found, so it's the 'f' form. Variants of snprintf generate numbers with
// potentially multiple digits before the '.', but without decimal exponent then. So we
@@ -282,9 +282,9 @@ QSimpleParsedNumber<double> qt_asciiToDouble(const char *num, qsizetype numLen,
char c2 = lowered(num[offset + 1]);
char c3 = lowered(num[offset + 2]);
if (c == 'i' && c2 == 'n' && c3 == 'f')
- return { negative ? -qt_inf() : qt_inf(), num + offset + 3 };
+ return { negative ? -qt_inf() : qt_inf(), offset + 3 };
else if (c == 'n' && c2 == 'a' && c3 == 'n' && !hasSign)
- return { qt_qnan(), num + 3 };
+ return { qt_qnan(), 3 };
return {};
}
}
@@ -313,7 +313,7 @@ QSimpleParsedNumber<double> qt_asciiToDouble(const char *num, qsizetype numLen,
return {};
} else {
// Overflow. That's not OK, but we still return infinity.
- return { d, nullptr };
+ return { d, -processed };
}
}
#else
@@ -342,7 +342,7 @@ QSimpleParsedNumber<double> qt_asciiToDouble(const char *num, qsizetype numLen,
return {};
}
}
- return { d, nullptr };
+ return { d, -processed };
}
#endif // !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED)
@@ -360,7 +360,7 @@ QSimpleParsedNumber<double> qt_asciiToDouble(const char *num, qsizetype numLen,
}
}
}
- return { d, num + processed };
+ return { d, processed };
}
/* Detect base if 0 and, if base is hex or bin, skip over 0x/0b prefixes */
@@ -430,7 +430,7 @@ QSimpleParsedNumber<qulonglong> qstrntoull(const char *begin, qsizetype size, in
const auto res = std::from_chars(prefix.next, stop, result, prefix.base);
if (res.ec != std::errc{})
return { };
- return { result, res.ptr == prefix.next ? begin : res.ptr };
+ return { result, res.ptr == prefix.next ? 0 : res.ptr - begin };
}
QSimpleParsedNumber<qlonglong> qstrntoll(const char *begin, qsizetype size, int base)
@@ -458,12 +458,12 @@ QSimpleParsedNumber<qlonglong> qstrntoll(const char *begin, qsizetype size, int
unsigned long long check = 0;
res = std::from_chars(prefix.next, stop, check, prefix.base);
if (res.ec == std::errc{} && check + std::numeric_limits<long long>::min() == 0)
- return { std::numeric_limits<long long>::min(), res.ptr };
+ return { std::numeric_limits<long long>::min(), res.ptr - begin };
return { };
}
if (res.ec != std::errc{})
return { };
- return { negate ? -result : result, res.ptr };
+ return { negate ? -result : result, res.ptr - begin };
}
template <typename Char>
@@ -558,7 +558,7 @@ double qstrntod(const char *s00, qsizetype len, const char **se, bool *ok)
{
auto r = qt_asciiToDouble(s00, len, TrailingJunkAllowed);
if (se)
- *se = r.endptr ? r.endptr : s00;
+ *se = s00 + (r.used < 0 ? -r.used : r.used);
if (ok)
*ok = r.ok();
return r.result;
diff --git a/src/corelib/text/qlocale_tools_p.h b/src/corelib/text/qlocale_tools_p.h
index c01bf617da..61c4061f1a 100644
--- a/src/corelib/text/qlocale_tools_p.h
+++ b/src/corelib/text/qlocale_tools_p.h
@@ -29,8 +29,9 @@ enum StrayCharacterMode {
template <typename T> struct QSimpleParsedNumber
{
T result;
- const char *endptr;
- bool ok() { return endptr; }
+ // When used < 0, -used is how much was used, but it was an error.
+ qsizetype used;
+ bool ok() const { return used > 0; }
};
// API note: this function can't process a number with more than 2.1 billion digits
diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp
index 598de83b0e..1a31d8e90c 100644
--- a/src/corelib/text/qlocale_win.cpp
+++ b/src/corelib/text/qlocale_win.cpp
@@ -1075,8 +1075,8 @@ static QString winIso639LangName(LCID id)
if (!lang_code.isEmpty()) {
const QByteArray latin1 = std::move(lang_code).toLatin1();
- const auto [i, endptr] = qstrntoull(latin1.data(), latin1.size(), 16);
- if (endptr && *endptr == '\0') {
+ const auto [i, used] = qstrntoull(latin1.data(), latin1.size(), 16);
+ if (used > 0 && latin1[used] == '\0') {
switch (i) {
case 0x814:
result = u"nn"_s; // Nynorsk
@@ -1117,8 +1117,8 @@ static QByteArray getWinLocaleName(LCID id)
if (result == "C"
|| (!result.isEmpty() && qt_splitLocaleName(QString::fromLocal8Bit(result)))) {
// See if we have a Windows locale code instead of a locale name:
- auto [id, ok] = qstrntoll(result.data(), result.size(), 0);
- if (!ok || id == 0 || id < INT_MIN || id > INT_MAX) // Assume real locale name
+ auto [id, used] = qstrntoll(result.data(), result.size(), 0);
+ if (used <= 0 || id == 0 || id < INT_MIN || id > INT_MAX) // Assume real locale name
return result;
return winLangCodeToIsoName(int(id));
}
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 3ec9682935..ae0f60b49c 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -6901,9 +6901,9 @@ static int parse_field_width(const char *&c, qsizetype size)
// can't be negative - started with a digit
// contains at least one digit
- auto [result, endp] = qstrntoull(c, size, 10);
- c = endp;
- if (!endp)
+ auto [result, used] = qstrntoull(c, size, 10);
+ c += used;
+ if (used <= 0)
return false;
// preserve Qt 5.5 behavior of consuming all digits, no matter how many
while (c < stop && qIsDigit(*c))
diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp
index d7c529ad10..9056fe79cc 100644
--- a/src/corelib/time/qtimezoneprivate_tz.cpp
+++ b/src/corelib/time/qtimezoneprivate_tz.cpp
@@ -394,26 +394,26 @@ static int parsePosixTime(const char *begin, const char *end)
const int maxHour = 137; // POSIX's extended range.
auto r = qstrntoll(begin, end - begin, 10);
hour = r.result;
- if (!r.ok() || hour < -maxHour || hour > maxHour || r.endptr > begin + 2)
+ if (!r.ok() || hour < -maxHour || hour > maxHour || r.used > 2)
return INT_MIN;
- begin = r.endptr;
+ begin += r.used;
if (begin < end && *begin == ':') {
// minutes
++begin;
r = qstrntoll(begin, end - begin, 10);
min = r.result;
- if (!r.ok() || min < 0 || min > 59 || r.endptr > begin + 2)
+ if (!r.ok() || min < 0 || min > 59 || r.used > 2)
return INT_MIN;
- begin = r.endptr;
+ begin += r.used;
if (begin < end && *begin == ':') {
// seconds
++begin;
r = qstrntoll(begin, end - begin, 10);
sec = r.result;
- if (!r.ok() || sec < 0 || sec > 59 || r.endptr > begin + 2)
+ if (!r.ok() || sec < 0 || sec > 59 || r.used > 2)
return INT_MIN;
- begin = r.endptr;
+ begin += r.used;
}
}
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index a97fc50f3a..59d84f5094 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -113,7 +113,7 @@ private:
const char *seedstr = getenv("QT_HASH_SEED");
if (seedstr) {
auto r = qstrntoll(seedstr, strlen(seedstr), 10);
- if (r.endptr == seedstr + strlen(seedstr)) {
+ if (r.used > 0 && size_t(r.used) == strlen(seedstr)) {
if (r.result) {
// can't use qWarning here (reentrancy)
fprintf(stderr, "QT_HASH_SEED: forced seed value is not 0; ignored.\n");
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index f44d5e4e8c..dcb2a3ad64 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -409,12 +409,12 @@ static QVersionNumber from_string(QLatin1StringView string, qsizetype *suffixInd
do {
// parsing as unsigned so a minus sign is rejected
- auto [value, end] = qstrntoull(start, endOfString - start, 10);
- if (!end || value > qulonglong(std::numeric_limits<int>::max()))
+ auto [value, used] = qstrntoull(start, endOfString - start, 10);
+ if (used <= 0 || value > qulonglong(std::numeric_limits<int>::max()))
break;
seg.append(int(value));
- start = end + 1;
- lastGoodEnd = end;
+ start += used + 1;
+ lastGoodEnd = start - 1;
} while (start < endOfString && *lastGoodEnd == '.');
if (suffixIndex)
diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
index f29b8a96ff..593b98dd60 100644
--- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
+++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
@@ -1246,6 +1246,10 @@ void tst_QLocale::strtod_data()
QTest::newRow("12456789012") << QString("12456789012") << 12456789012.0 << 11 << true;
QTest::newRow("1.2456789012e10") << QString("1.2456789012e10") << 12456789012.0 << 15 << true;
+ // Overflow - fails but reports right length:
+ QTest::newRow("1e2000") << QString("1e2000") << qInf() << 6 << false;
+ QTest::newRow("-1e2000") << QString("-1e2000") << -qInf() << 7 << false;
+
// starts with junk, fails
QTest::newRow("a0") << QString("a0") << 0.0 << 0 << false;
QTest::newRow("a0.") << QString("a0.") << 0.0 << 0 << false;
@@ -1277,6 +1281,10 @@ void tst_QLocale::strtod_data()
QTest::newRow("12456789012f") << QString("12456789012f") << 12456789012.0 << 11 << true;
QTest::newRow("1.2456789012e10g") << QString("1.2456789012e10g") << 12456789012.0 << 15 << true;
+ // Overflow, ends with cruft - fails but reports right length:
+ QTest::newRow("1e2000 cruft") << QString("1e2000 cruft") << qInf() << 6 << false;
+ QTest::newRow("-1e2000 cruft") << QString("-1e2000 cruft") << -qInf() << 7 << false;
+
// "0x" prefix, success but only for the "0" before "x"
QTest::newRow("0x0") << QString("0x0") << 0.0 << 1 << true;
QTest::newRow("0x0.") << QString("0x0.") << 0.0 << 1 << true;
@@ -1309,9 +1317,9 @@ void tst_QLocale::strtod()
QCOMPARE(actualOk, ok);
QCOMPARE(static_cast<int>(end - numData.constData()), processed);
- // make sure neither QByteArray, QString or QLocale also work
- // (but they don't support incomplete parsing)
- if (processed == num_str.size() || processed == 0) {
+ // Make sure QByteArray, QString and QLocale also work.
+ // (They don't support incomplete parsing, and give 0 for overflow.)
+ if (ok && (processed == num_str.size() || processed == 0)) {
actualOk = false;
QCOMPARE(num_str.toDouble(&actualOk), num);
QCOMPARE(actualOk, ok);