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>bb10
parent
5b62970b94
commit
5ff7163796
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ struct QXcbSoftwareOpenGLEnforcer {
|
|||
}
|
||||
|
||||
if (forceSoftwareOpenGL)
|
||||
qputenv("LIBGL_ALWAYS_SOFTWARE", QByteArrayLiteral("1"));
|
||||
qputenv("LIBGL_ALWAYS_SOFTWARE", "1");
|
||||
}
|
||||
|
||||
~QXcbSoftwareOpenGLEnforcer() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue