diff options
author | Marc Mutz <marc.mutz@qt.io> | 2022-08-03 19:23:28 +0200 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2022-08-06 14:21:46 +0000 |
commit | 5ff71637968c70f138d8ea6cc24e61c1608f2187 (patch) | |
tree | 4b4f605969497961e70ad311b2ebed3d0b4060e3 | |
parent | 5b62970b9441717670a1756b858c500004dfdfe0 (diff) |
qputenv: port to QByteArrayView
The vast majority of in-tree users pass simple and short C string
literals as the value. By porting to QByteArrayView, we document that
we'll accept non-NUL-terminated data, and do the NUL-termination
internally, using SSO'ed std::string, saving memory allocations in the
common case of short strings.
I didn't bother to check which direction std::string takes for
nullptrs these days (there was a change accepted in that area for
C++20 or 23), so play it safe and protect against them.
Follow-up to
Task-number: QTBUG-105302
Change-Id: I2369acc62f1d5cbc26135396cfe0602d8c75300c
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
12 files changed, 43 insertions, 29 deletions
diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp index 2b864ad41f..aa1a496f0f 100644 --- a/src/corelib/compat/removed_api.cpp +++ b/src/corelib/compat/removed_api.cpp @@ -285,6 +285,13 @@ QT_WARNING_POP #if QT_CORE_REMOVED_SINCE(6, 5) +#include "qenvironmentvariables.h" + +bool qputenv(const char *varName, const QByteArray &value) +{ + return qputenv(varName, qToByteArrayViewIgnoringNull(value)); +} + #include "qmetatype.h" int QMetaType::idHelper() const diff --git a/src/corelib/global/qenvironmentvariables.cpp b/src/corelib/global/qenvironmentvariables.cpp index d3d963e52e..4860913327 100644 --- a/src/corelib/global/qenvironmentvariables.cpp +++ b/src/corelib/global/qenvironmentvariables.cpp @@ -243,6 +243,7 @@ bool qEnvironmentVariableIsSet(const char *varName) noexcept } /*! + \fn bool qputenv(const char *varName, QByteArrayView value) \relates <QEnvironmentVariables> This function sets the \a value of the environment variable named @@ -258,30 +259,30 @@ bool qEnvironmentVariableIsSet(const char *varName) noexcept uses the replacement function in VC, and calls the standard C library's implementation on all other platforms. + \note In Qt versions prior to 6.5, the \a value argument was QByteArray, + not QByteArrayView. + \sa qgetenv(), qEnvironmentVariable() */ -bool qputenv(const char *varName, const QByteArray &value) +bool qputenv(const char *varName, QByteArrayView raw) { - // 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); - } + auto protect = [](const char *str) { return str ? str : ""; }; + + std::string value{protect(raw.data()), size_t(raw.size())}; // NUL-terminates w/SSO #if defined(Q_CC_MSVC) const auto locker = qt_scoped_lock(environmentMutex); - return _putenv_s(varName, value.constData()) == 0; + return _putenv_s(varName, value.data()) == 0; #elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_HAIKU) // POSIX.1-2001 has setenv const auto locker = qt_scoped_lock(environmentMutex); - return setenv(varName, value.constData(), true) == 0; + return setenv(varName, value.data(), true) == 0; #else - QByteArray buffer(varName); + std::string buffer; + buffer += protect(varName); buffer += '='; buffer += value; - char *envVar = qstrdup(buffer.constData()); + char *envVar = qstrdup(buffer.data()); int result = [&] { const auto locker = qt_scoped_lock(environmentMutex); return putenv(envVar); diff --git a/src/corelib/global/qenvironmentvariables.h b/src/corelib/global/qenvironmentvariables.h index cde51c9ba1..78fea255d3 100644 --- a/src/corelib/global/qenvironmentvariables.h +++ b/src/corelib/global/qenvironmentvariables.h @@ -5,6 +5,7 @@ #define QENVIRONMENTVARIABLES_H #include <QtCore/qglobal.h> +#include <QtCore/qtdeprecationmarkers.h> #if 0 #pragma qt_class(QEnvironmentVariables) @@ -14,11 +15,16 @@ QT_BEGIN_NAMESPACE class QByteArray; +class QByteArrayView; + Q_CORE_EXPORT QByteArray qgetenv(const char *varName); // need it as two functions because QString is only forward-declared here Q_CORE_EXPORT QString qEnvironmentVariable(const char *varName); Q_CORE_EXPORT QString qEnvironmentVariable(const char *varName, const QString &defaultValue); +#if QT_CORE_REMOVED_SINCE(6, 5) Q_CORE_EXPORT bool qputenv(const char *varName, const QByteArray &value); +#endif +Q_CORE_EXPORT bool qputenv(const char *varName, QByteArrayView value); Q_CORE_EXPORT bool qunsetenv(const char *varName); Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept; diff --git a/src/gui/opengl/platform/unix/qglxconvenience.cpp b/src/gui/opengl/platform/unix/qglxconvenience.cpp index a756caf343..ce70818042 100644 --- a/src/gui/opengl/platform/unix/qglxconvenience.cpp +++ b/src/gui/opengl/platform/unix/qglxconvenience.cpp @@ -124,7 +124,7 @@ struct QXcbSoftwareOpenGLEnforcer { } if (forceSoftwareOpenGL) - qputenv("LIBGL_ALWAYS_SOFTWARE", QByteArrayLiteral("1")); + qputenv("LIBGL_ALWAYS_SOFTWARE", "1"); } ~QXcbSoftwareOpenGLEnforcer() { diff --git a/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp b/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp index a0a9bb940e..3ba6de20a9 100644 --- a/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp +++ b/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp @@ -181,7 +181,7 @@ private slots: void initTestCase() { qputenv("XDG_CONFIG_DIRS", "/does/not/exist"); - qputenv("QT_MESSAGE_PATTERN", QByteArray("%{category}: %{type},%{message}")); + qputenv("QT_MESSAGE_PATTERN", "%{category}: %{type},%{message}"); oldMessageHandler = qInstallMessageHandler(myCustomMessageHandler); // Create configuration _config = new Configuration(); diff --git a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp index 2c0500eec9..b2bb14180e 100644 --- a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp +++ b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp @@ -64,10 +64,10 @@ private: qputenv("XDG_DATA_DIRS", QFile::encodeName(m_globalAppDir)); } void setDefaultLocations() { - qputenv("XDG_CONFIG_HOME", QByteArray()); - qputenv("XDG_CONFIG_DIRS", QByteArray()); - qputenv("XDG_DATA_HOME", QByteArray()); - qputenv("XDG_DATA_DIRS", QByteArray()); + qputenv("XDG_CONFIG_HOME", nullptr); + qputenv("XDG_CONFIG_DIRS", nullptr); + qputenv("XDG_DATA_HOME", nullptr); + qputenv("XDG_DATA_DIRS", nullptr); } #endif diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index 6bec1969ab..e9d2064503 100644 --- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -153,7 +153,7 @@ private: { reset(zone); } void reset(const QByteArray &zone) { - qputenv("TZ", zone.constData()); + qputenv("TZ", zone); qTzSet(); } ~TimeZoneRollback() @@ -161,7 +161,7 @@ private: if (prior.isNull()) qunsetenv("TZ"); else - qputenv("TZ", prior.constData()); + qputenv("TZ", prior); qTzSet(); } }; diff --git a/tests/auto/gui/kernel/qhighdpi/tst_qhighdpi.cpp b/tests/auto/gui/kernel/qhighdpi/tst_qhighdpi.cpp index f221c9db90..2196724f41 100644 --- a/tests/auto/gui/kernel/qhighdpi/tst_qhighdpi.cpp +++ b/tests/auto/gui/kernel/qhighdpi/tst_qhighdpi.cpp @@ -270,7 +270,7 @@ void tst_QHighDpi::screenDpiChange() void tst_QHighDpi::environment_QT_SCALE_FACTOR() { qreal factor = 3.1415; - qputenv("QT_SCALE_FACTOR", QByteArray::number(factor)); + qputenv("QT_SCALE_FACTOR", std::to_string(factor)); QList<qreal> dpiValues { 96, 144, 192 }; std::unique_ptr<QGuiApplication> app(createStandardOffscreenApp(dpiValues)); diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index 8207f65dcd..bb2437c7f5 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -238,7 +238,7 @@ void tst_Http2::singleRequest() // we have to use TLS sockets (== private key) and thus suppress a // keychain UI asking for permission to use a private key. // Our CI has this, but somebody testing locally - will have a problem. - qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); auto envRollback = qScopeGuard([](){ qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); @@ -630,7 +630,7 @@ void tst_Http2::connectToHost() // we have to use TLS sockets (== private key) and thus suppress a // keychain UI asking for permission to use a private key. // Our CI has this, but somebody testing locally - will have a problem. - qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); auto envRollback = qScopeGuard([](){ qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); @@ -728,7 +728,7 @@ void tst_Http2::maxFrameSize() // we have to use TLS sockets (== private key) and thus suppress a // keychain UI asking for permission to use a private key. // Our CI has this, but somebody testing locally - will have a problem. - qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); auto envRollback = qScopeGuard([](){ qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); @@ -893,7 +893,7 @@ void tst_Http2::moreActivitySignals() // we have to use TLS sockets (== private key) and thus suppress a // keychain UI asking for permission to use a private key. // Our CI has this, but somebody testing locally - will have a problem. - qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); auto envRollback = qScopeGuard([]() { qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); #endif @@ -1004,7 +1004,7 @@ void tst_Http2::contentEncoding() // we have to use TLS sockets (== private key) and thus suppress a // keychain UI asking for permission to use a private key. // Our CI has this, but somebody testing locally - will have a problem. - qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); auto envRollback = qScopeGuard([]() { qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); #endif diff --git a/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp b/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp index 95998cd570..beb0a0805a 100644 --- a/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp +++ b/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp @@ -55,7 +55,7 @@ class tst_QAccessibilityLinux : public QObject public: tst_QAccessibilityLinux() : m_window(0), root(0), rootApplication(0), mainWindow(0) { - qputenv("QT_LINUX_ACCESSIBILITY_ALWAYS_ON", QByteArrayLiteral("1")); + qputenv("QT_LINUX_ACCESSIBILITY_ALWAYS_ON", "1"); dbus = new DBusConnection(); } ~tst_QAccessibilityLinux() diff --git a/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp b/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp index 15af4c899b..adf4cb7181 100644 --- a/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp +++ b/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp @@ -174,7 +174,7 @@ QString tst_QPrinterInfo::getOutputFromCommand(const QStringList &command) { // Forces the ouptut from the command to be in English const QByteArray origSoftwareEnv = qgetenv("SOFTWARE"); - qputenv("SOFTWARE", QByteArray()); + qputenv("SOFTWARE", nullptr); QString output = getOutputFromCommandInternal(command); qputenv("SOFTWARE", origSoftwareEnv); return output; diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp index 3db9953471..127182fd90 100644 --- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -1119,7 +1119,7 @@ void tst_QApplication::libraryPaths_qt_plugin_path_2() << QCoreApplication::applicationDirPath(); QVERIFY(isPathListIncluded(QCoreApplication::libraryPaths(), expected)); - qputenv("QT_PLUGIN_PATH", QByteArray()); + qputenv("QT_PLUGIN_PATH", nullptr); } } #endif |