From 0c944d361ad6344a45c0d8ece2d5ea372bb58937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Mon, 6 Nov 2023 17:13:39 +0100 Subject: [PATCH] QLocal8Bit::convertToUnicode[win]: split out buffer growing We will need to potentially grow the buffer before appending anything to it, because if we pass in 0 as a size then the MultiByteToWideChar just returns the size we would need. If we didn't intend to do so then we would increment our output buffers even though nothing is written. And when appending single characters (like the replacement character for an invalid sequence) we need to grow the buffer as well. We'll need this all in the next commit. Pick-to: 6.6 6.5 Task-number: QTBUG-105105 Change-Id: I94b9a0f7d18a725da01a47398163e6d0f704eefc Reviewed-by: Ievgenii Meshcheriakov Reviewed-by: Edward Welbourne (cherry picked from commit 1090d5dd4ae5be898d4566314eda43b0283709d9) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/text/qstringconverter.cpp | 35 +++++++++++++++++++++------ 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp index 5abdd262bfe..193eeb88822 100644 --- a/src/corelib/text/qstringconverter.cpp +++ b/src/corelib/text/qstringconverter.cpp @@ -1333,11 +1333,35 @@ QString QLocal8Bit::convertToUnicode_sys(QByteArrayView in, quint32 codePage, Q_ASSERT(mblen > 0); Q_ASSERT(!state || state->remainingChars == 0); + // Return a pointer to storage where we have enough space for `size` + const auto growOut = [&](qsizetype size) -> std::tuple { + if (outlen >= size) + return {out, outlen}; + const bool wasStackBuffer = sp.isEmpty(); + const auto begin = wasStackBuffer ? buf.data() : reinterpret_cast(sp.data()); + const qsizetype offset = qsizetype(std::distance(begin, out)); + qsizetype newSize = 0; + if (Q_UNLIKELY(qAddOverflow(offset, size, &newSize))) { + Q_CHECK_PTR(false); + return {nullptr, 0}; + } + sp.resize(newSize); + auto it = reinterpret_cast(sp.data()); + if (wasStackBuffer) + it = std::copy_n(buf.data(), offset, it); + else + it += offset; + return {it, size}; + }; + constexpr int MaxStep = std::numeric_limits::max(); const char *end = mb + mblen; while (mb != end) { const int nextIn = int(std::min(qsizetype(mblen), qsizetype(MaxStep))); const int nextOut = int(std::min(outlen, qsizetype(MaxStep))); + std::tie(out, outlen) = growOut(1); // Need space for at least one character + if (!out) + return {}; len = MultiByteToWideChar(codePage, MB_ERR_INVALID_CHARS, mb, nextIn, out, nextOut); if (len) { mb += nextIn; @@ -1349,14 +1373,9 @@ QString QLocal8Bit::convertToUnicode_sys(QByteArrayView in, quint32 codePage, if (r == ERROR_INSUFFICIENT_BUFFER) { Q_ASSERT(QtPrivate::q_points_into_range(out, buf.data(), buf.data() + buf.size())); const int wclen = MultiByteToWideChar(codePage, 0, mb, nextIn, 0, 0); - auto begin = buf.data(); - const qsizetype offset = qsizetype(std::distance(begin, out)); - qsizetype newSize = offset + wclen; - sp.resize(newSize); - auto it = reinterpret_cast(sp.data()); - it = std::copy_n(buf.data(), offset, it); - out = it; - outlen = wclen; + std::tie(out, outlen) = growOut(wclen); + if (!out) + return {}; } else if (r == ERROR_NO_UNICODE_TRANSLATION && state && state->remainingChars < q20::ssize(state->state_data)) { ++state->remainingChars;