diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2020-07-23 09:43:52 -0700 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2020-07-28 22:40:11 +0000 |
commit | a17c9b4f5c093c6624990419b2df555c8c9399a1 (patch) | |
tree | 0a95a45202914fa0754d83a8df5d85b2b7892d9b /src/corelib/text | |
parent | 817ca3026349d7c303d9b6b66ba36f2ea1b5bfd5 (diff) |
QByteArray::toDouble: fix buffer overflow reads on fromRawData()
If Qt was not compiled with libdouble-conversion, sscanf() requires
null-termination, which fromRawData() does not require. This could be
fixed by making QByteArray pass a reallocated copy if it is operating on
raw data, but fixing qt_asciiToDouble() means we catch all cases and we
optimize for the common case of not-horribly-long strings.
Fixes: QTBUG-85580
Change-Id: Iea47e0f8fc8b40378df7fffd16246f6163b01442
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit efd3c7bf2427c8237857e56ecd51b8da3ce43a6e)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src/corelib/text')
-rw-r--r-- | src/corelib/text/qlocale_tools.cpp | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp index 0da769d694..6fe08714c7 100644 --- a/src/corelib/text/qlocale_tools.cpp +++ b/src/corelib/text/qlocale_tools.cpp @@ -280,6 +280,11 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, cha double qt_asciiToDouble(const char *num, int numLen, bool &ok, int &processed, StrayCharacterMode strayCharMode) { + auto string_equals = [](const char *needle, const char *haystack, qsizetype haystackLen) { + qsizetype needleLen = strlen(needle); + return needleLen == haystackLen && memcmp(needle, haystack, haystackLen) == 0; + }; + if (*num == '\0') { ok = false; processed = 0; @@ -291,10 +296,10 @@ double qt_asciiToDouble(const char *num, int numLen, bool &ok, int &processed, // We have to catch NaN before because we need NaN as marker for "garbage" in the // libdouble-conversion case and, in contrast to libdouble-conversion or sscanf, we don't allow // "-nan" or "+nan" - if (qstrcmp(num, "nan") == 0) { + if (string_equals("nan", num, numLen)) { processed = 3; return qt_qnan(); - } else if ((num[0] == '-' || num[0] == '+') && qstrcmp(num + 1, "nan") == 0) { + } else if (string_equals("+nan", num, numLen) || string_equals("-nan", num, numLen)) { processed = 0; ok = false; return 0.0; @@ -302,13 +307,13 @@ double qt_asciiToDouble(const char *num, int numLen, bool &ok, int &processed, // Infinity values are implementation defined in the sscanf case. In the libdouble-conversion // case we need infinity as overflow marker. - if (qstrcmp(num, "+inf") == 0) { + if (string_equals("+inf", num, numLen)) { processed = 4; return qt_inf(); - } else if (qstrcmp(num, "inf") == 0) { + } else if (string_equals("inf", num, numLen)) { processed = 3; return qt_inf(); - } else if (qstrcmp(num, "-inf") == 0) { + } else if (string_equals("-inf", num, numLen)) { processed = 4; return -qt_inf(); } @@ -337,9 +342,23 @@ double qt_asciiToDouble(const char *num, int numLen, bool &ok, int &processed, } } #else - if (qDoubleSscanf(num, QT_CLOCALE, "%lf%n", &d, &processed) < 1) + // 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)); + memcpy(buffer, num, numLen); + buffer[numLen] = '\0'; + + if (qDoubleSscanf(buffer, QT_CLOCALE, "%lf%n", &d, &processed) < 1) processed = 0; + if (buffer != reasonableBuffer) + free(buffer); + if ((strayCharMode == TrailingJunkProhibited && processed != numLen) || qIsNaN(d)) { // Implementation defined nan symbol or garbage found. We don't accept it. processed = 0; |