From 15422d191fb03eb9cafe68b24484d59c1270244c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 3 Aug 2022 18:52:13 +0200 Subject: [PATCH] qputenv: defend against non-NUL-terminated QByteArray values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old code assumed that a QByteArray's data() is always NUL-terminated. Due to the conflation of owners and non-owners in QByteArray (but also in case we ever get efficient substringing), this is not always the case, e.g. QByteArray::fromRawData() does not ensure NUL-termination. From QString::utf16(), we learn that the condition to check for is QArrayData::isMutable(). After working around the fact that QByteArray::data_ptr() doesn't exist for const QBAs and that empty QBAs always refer to QByteArray::empty_, which is !isMutable(), we can detect this situation and re-allocate without introducing new API. This is the fix for Qt ≤ 6.4. For Qt 6.5, we'll port the function to QByteArrayView. Pick-to: 6.4 6.3 6.2 5.15 Fixes: QTBUG-105302 Change-Id: I3416535ab09d601e0e87b2767f2c024ba1217e64 Reviewed-by: Sona Kurazyan Reviewed-by: Mårten Nordheim --- src/corelib/global/qenvironmentvariables.cpp | 8 ++++++++ tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/corelib/global/qenvironmentvariables.cpp b/src/corelib/global/qenvironmentvariables.cpp index 71544ae56c..d3d963e52e 100644 --- a/src/corelib/global/qenvironmentvariables.cpp +++ b/src/corelib/global/qenvironmentvariables.cpp @@ -262,6 +262,14 @@ bool qEnvironmentVariableIsSet(const char *varName) noexcept */ bool qputenv(const char *varName, const QByteArray &value) { + // protect against non-NUL-terminated QByteArrays: + if (!const_cast(value).data_ptr()->isMutable()) { + QByteArray copy(value); + copy.reserve(copy.size() + 1); // ensures NUL termination (and isMutable() even for size==0 + // (unlike detach()) to avoid infinite recursion) + return qputenv(varName, copy); + } + #if defined(Q_CC_MSVC) const auto locker = qt_scoped_lock(environmentMutex); return _putenv_s(varName, value.constData()) == 0; diff --git a/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp b/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp index 77a7fa4194..f914ee5f23 100644 --- a/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp +++ b/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp @@ -60,7 +60,11 @@ void tst_QGetPutEnv::getSetCheck() QCOMPARE(sresult, QString()); #endif - QVERIFY(qputenv(varName, QByteArray("supervalue"))); + constexpr char varValueFullString[] = "supervalue123"; + const auto varValueQBA = QByteArray::fromRawData(varValueFullString, sizeof varValueFullString - 4); + QCOMPARE_EQ(varValueQBA, "supervalue"); + + QVERIFY(qputenv(varName, varValueQBA)); QVERIFY(qEnvironmentVariableIsSet(varName)); QVERIFY(!qEnvironmentVariableIsEmpty(varName));