diff options
author | Marc Mutz <marc.mutz@qt.io> | 2022-08-06 08:54:17 +0200 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2022-08-08 11:39:38 +0200 |
commit | 51577e8599886ed46845d99fd7bfb8716547199d (patch) | |
tree | f8c1943787a7c9a5bb8a8d6c03786f90709bc9b6 | |
parent | 1fe0b3a7ecec015d620e481fbe9b9dfd48629799 (diff) |
qputenv: defend against non-NUL-terminated QByteArray values
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.
Manual conflict resolutions:
- tracked changes into qglobal.cpp (was: qenvionmentvariables.cpp)
- QCOMPARE_EQ → QCOMPARE
Fixes: QTBUG-105302
Change-Id: I3416535ab09d601e0e87b2767f2c024ba1217e64
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
(cherry picked from commit 15422d191fb03eb9cafe68b24484d59c1270244c)
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
-rw-r--r-- | src/corelib/global/qglobal.cpp | 8 | ||||
-rw-r--r-- | tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp | 6 |
2 files changed, 13 insertions, 1 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 30d3341318..ae59d5c5b6 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -3652,6 +3652,14 @@ bool qEnvironmentVariableIsSet(const char *varName) noexcept */ bool qputenv(const char *varName, const QByteArray &value) { + // protect against non-NUL-terminated QByteArrays: + if (!const_cast<QByteArray&>(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); + } + const auto locker = qt_scoped_lock(environmentMutex); #if defined(Q_CC_MSVC) 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 519c5fa88d..cb5d61aa2f 100644 --- a/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp +++ b/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp @@ -85,7 +85,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(varValueQBA, "supervalue"); + + QVERIFY(qputenv(varName, varValueQBA)); QVERIFY(qEnvironmentVariableIsSet(varName)); QVERIFY(!qEnvironmentVariableIsEmpty(varName)); |