Fix deadlock when setting environment variables.
Qt uses QHash as the container for faking environment variables on Windows Runtime and CE. Environment variable manipulation functions are protected by mutex. Accessing the QT_HASH_SEED environment variable inside QHash can lead to situation where qputenv() call leads to qgetenv() call and that leads to a deadlock. Change the container from QHash to QVector to avoid deadlock. Task-number: QTBUG-49529 Change-Id: I550ead4ab12e7abebc044f52339063a44fcf0170 Reviewed-by: Marc Mutz <marc.mutz@kdab.com> Reviewed-by: Maurice Kalinowski <maurice.kalinowski@theqtcompany.com>
This commit is contained in:
parent
b12e876efc
commit
7fdfaad43f
@ -46,51 +46,72 @@
|
||||
//
|
||||
|
||||
#include "qbytearray.h"
|
||||
#include "qhash.h"
|
||||
#include "qvector.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// Environment ------------------------------------------------------
|
||||
Q_CORE_EXPORT QHash<QByteArray, QByteArray> &qt_app_environment()
|
||||
{
|
||||
static QHash<QByteArray, QByteArray> internalEnvironment;
|
||||
return internalEnvironment;
|
||||
}
|
||||
struct Variable {
|
||||
Variable() { }
|
||||
|
||||
Variable(const QByteArray &name, const QByteArray &value)
|
||||
: name(name), value(value) { }
|
||||
|
||||
QByteArray name;
|
||||
QByteArray value;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(Variable, Q_MOVABLE_TYPE);
|
||||
|
||||
struct NameEquals {
|
||||
typedef bool result_type;
|
||||
const char *name;
|
||||
explicit NameEquals(const char *name) Q_DECL_NOTHROW : name(name) {}
|
||||
result_type operator()(const Variable &other) const Q_DECL_NOTHROW
|
||||
{ return qstrcmp(other.name, name) == 0; }
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(QVector<Variable>, qt_app_environment)
|
||||
|
||||
errno_t qt_fake_getenv_s(size_t *sizeNeeded, char *buffer, size_t bufferSize, const char *varName)
|
||||
{
|
||||
if (!sizeNeeded)
|
||||
return EINVAL;
|
||||
|
||||
QHash<QByteArray, QByteArray>::const_iterator iterator = qt_app_environment().constFind(varName);
|
||||
if (iterator == qt_app_environment().constEnd()) {
|
||||
QVector<Variable>::const_iterator end = qt_app_environment->constEnd();
|
||||
QVector<Variable>::const_iterator iterator = std::find_if(qt_app_environment->constBegin(),
|
||||
end,
|
||||
NameEquals(varName));
|
||||
if (iterator == end) {
|
||||
if (buffer)
|
||||
buffer[0] = '\0';
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
const int size = iterator->size() + 1;
|
||||
const int size = iterator->value.size() + 1;
|
||||
if (bufferSize < size_t(size)) {
|
||||
*sizeNeeded = size;
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
qstrcpy(buffer, iterator->constData());
|
||||
qstrcpy(buffer, iterator->value.constData());
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno_t qt_fake__putenv_s(const char *varName, const char *value)
|
||||
{
|
||||
QHash<QByteArray, QByteArray>::iterator iterator = qt_app_environment().find(varName);
|
||||
QHash<QByteArray, QByteArray>::iterator end = qt_app_environment().end();
|
||||
QVector<Variable>::iterator end = qt_app_environment->end();
|
||||
QVector<Variable>::iterator iterator = std::find_if(qt_app_environment->begin(),
|
||||
end,
|
||||
NameEquals(varName));
|
||||
if (!value || !*value) {
|
||||
if (iterator != end)
|
||||
qt_app_environment().erase(iterator);
|
||||
qt_app_environment->erase(iterator);
|
||||
} else {
|
||||
if (iterator == end)
|
||||
qt_app_environment()[varName] = QByteArray(value);
|
||||
qt_app_environment->append(Variable(varName, value));
|
||||
else
|
||||
(*iterator) = value;
|
||||
iterator->value = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user