summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qlocale_tools.cpp
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@qt.io>2022-02-23 11:57:00 +0100
committerMarc Mutz <marc.mutz@qt.io>2022-02-25 08:08:21 +0000
commit5a39173c34be6fb033b8988408d0d98546db9f13 (patch)
treee38697494364865c9f731ff451ea299dbecca898 /src/corelib/text/qlocale_tools.cpp
parent64d65a645c3f64c6b317aed571366bc049c1cd25 (diff)
Don't allocate in qt_asciiToDouble()
The sscanf implementation ensured NUL-termination of the input data, by copying it, and appending NUL. Since this function is ignoring trailing garbage and reports the progress back, we could be parsing the first double in a multi-MiB buffer. And we'd been copying and copying the buffer for every double scanned. This is clearly not acceptable. An alternative is to use the max-field-width feature of scanf. By giving the size of the input data as the maximum field width in the format string, we stop sscanf from reading more than the available data. This code should let everyone's alarm bells go off: a format string constructed at run-time is really the last thing one should consider, but I haven't found a way to pass the field width as an argument, so bite the bullet and go through with it. Copying potentially MiBs of data is the worse of the two evils. Pick-to: 6.3 Fixes: QTBUG-101178 Change-Id: Ibaf8142f6b3dab4d5e3631c3cc8cc6699bceb320 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/corelib/text/qlocale_tools.cpp')
-rw-r--r--src/corelib/text/qlocale_tools.cpp25
1 files changed, 8 insertions, 17 deletions
diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp
index c133a028c0..97c91dd3ee 100644
--- a/src/corelib/text/qlocale_tools.cpp
+++ b/src/corelib/text/qlocale_tools.cpp
@@ -286,7 +286,7 @@ double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &proces
return needleLen == haystackLen && memcmp(needle, haystack, haystackLen) == 0;
};
- if (numLen == 0) {
+ if (numLen <= 0) {
ok = false;
processed = 0;
return 0.0;
@@ -350,23 +350,14 @@ double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &proces
}
}
#else
- // need to ensure that our input is null-terminated for sscanf
- // (this is a QVarLengthArray<char, 128> but this code here is too low-level for QVLA)
- char reasonableBuffer[128];
- char *buffer;
- if (numLen < qsizetype(sizeof(reasonableBuffer)) - 1)
- buffer = reasonableBuffer;
- else
- buffer = static_cast<char *>(malloc(numLen + 1));
- Q_CHECK_PTR(buffer);
- memcpy(buffer, num, numLen);
- buffer[numLen] = '\0';
-
- if (qDoubleSscanf(buffer, QT_CLOCALE, "%lf%n", &d, &processed) < 1)
- processed = 0;
+ // ::digits10 is 19, but ::max() is 18'446'744'073'709'551'615ULL - go, figure...
+ constexpr auto maxDigitsForULongLong = 1 + std::numeric_limits<unsigned long long>::digits10;
+ // need to ensure that we don't read more than numLen of input:
+ char fmt[1 + maxDigitsForULongLong + 4 + 1];
+ sprintf(fmt, "%s%llu%s", "%", static_cast<unsigned long long>(numLen), "lf%n");
- if (buffer != reasonableBuffer)
- free(buffer);
+ if (qDoubleSscanf(num, QT_CLOCALE, fmt, &d, &processed) < 1)
+ processed = 0;
if ((strayCharMode == TrailingJunkProhibited && processed != numLen) || qIsNaN(d)) {
// Implementation defined nan symbol or garbage found. We don't accept it.