aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <[email protected]>2023-07-24 11:50:47 +0200
committerUlf Hermann <[email protected]>2023-09-12 07:33:45 +0200
commit9189ea15fa44fb072fc0a7737050074854d52527 (patch)
treea2db9d3f8a494c220f5b472f301468b215208e7a
parentd25da3e7b840838c66c92ff627b7ffa1d923012e (diff)
Context properties: Don't trigger an assert for numeric names
The logic in our IdentifierHash assumes that every entry is a StringOrSymbol; however, IdentifierTable::asProperyKey will convert keys that look like numbers to ArrayIndex instead. This is noramlly what we want, and not an issue, except for setContextPropery where the user can pass an arbitrary string that is not necessarily a valid identifier. In an ideal world, we would just disallow such identifiers, but for backward compatibility change the code to handle this case (avoiding a Qt internal assert). We only need to modify the QString overloads, as those are the only ones that interact with unsanitized user input. A later commit will modify setContextPropery to warn if the key is numeric. Fixes: QTBUG-115319 Change-Id: Ifc4e4d2bc99321836e6976c4cbd0c5ff687b430c Reviewed-by: Ulf Hermann <[email protected]> (cherry picked from commit b2b90c7cf5cb5205f2c5b374f7332252205385e8) Reviewed-by: Sami Shalayel <[email protected]>
-rw-r--r--src/qml/jsruntime/qv4identifier.cpp4
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp24
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h5
-rw-r--r--src/qml/jsruntime/qv4string_p.h22
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp10
5 files changed, 47 insertions, 18 deletions
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp
index 6cd694842e..87ca4bca4f 100644
--- a/src/qml/jsruntime/qv4identifier.cpp
+++ b/src/qml/jsruntime/qv4identifier.cpp
@@ -152,7 +152,7 @@ const IdentifierHashEntry *IdentifierHash::lookup(const QString &str) const
if (!d)
return nullptr;
- PropertyKey id = d->identifierTable->asPropertyKey(str);
+ PropertyKey id = d->identifierTable->asPropertyKey(str, IdentifierTable::ForceConversionToId);
return lookup(id);
}
@@ -169,7 +169,7 @@ const IdentifierHashEntry *IdentifierHash::lookup(String *str) const
const PropertyKey IdentifierHash::toIdentifier(const QString &str) const
{
Q_ASSERT(d);
- return d->identifierTable->asPropertyKey(str);
+ return d->identifierTable->asPropertyKey(str, IdentifierTable::ForceConversionToId);
}
const PropertyKey IdentifierHash::toIdentifier(Heap::String *str) const
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index 8db00bd921..54ab77a31e 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -132,16 +132,23 @@ void IdentifierTable::addEntry(Heap::StringOrSymbol *str)
-Heap::String *IdentifierTable::insertString(const QString &s)
+Heap::String *IdentifierTable::insertString(
+ const QString &s, IdentifierTable::KeyConversionBehavior conversionBehavior)
{
uint subtype;
- uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
+
+ uint hash = String::createHashValue(s.constData(), s.size(), &subtype);
if (subtype == Heap::String::StringType_ArrayIndex) {
- Heap::String *str = engine->newString(s);
- str->stringHash = hash;
- str->subtype = subtype;
- return str;
+ if (Q_UNLIKELY(conversionBehavior == ForceConversionToId)) {
+ hash = String::createHashValueDisallowingArrayIndex(s.constData(), s.size(), &subtype);
+ } else {
+ Heap::String *str = engine->newString(s);
+ str->stringHash = hash;
+ str->subtype = subtype;
+ return str;
+ }
}
+
uint idx = hash % alloc;
while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
if (e->stringHash == hash && e->toQString() == s)
@@ -278,9 +285,10 @@ void IdentifierTable::sweep()
size -= freed;
}
-PropertyKey IdentifierTable::asPropertyKey(const QString &s)
+PropertyKey IdentifierTable::asPropertyKey(
+ const QString &s, IdentifierTable::KeyConversionBehavior conversionBehavior)
{
- return insertString(s)->identifier;
+ return insertString(s, conversionBehavior)->identifier;
}
PropertyKey IdentifierTable::asPropertyKey(const char *s, int len)
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index c5b502075c..039ea45612 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -75,11 +75,12 @@ struct Q_QML_PRIVATE_EXPORT IdentifierTable
void addEntry(Heap::StringOrSymbol *str);
public:
+ enum KeyConversionBehavior { Default, ForceConversionToId };
IdentifierTable(ExecutionEngine *engine, int numBits = 8);
~IdentifierTable();
- Heap::String *insertString(const QString &s);
+ Heap::String *insertString(const QString &s, KeyConversionBehavior conversionBehavior);
Heap::Symbol *insertSymbol(const QString &s);
PropertyKey asPropertyKey(const Heap::String *str) {
@@ -91,7 +92,7 @@ public:
return asPropertyKey(str->d());
}
- PropertyKey asPropertyKey(const QString &s);
+ PropertyKey asPropertyKey(const QString &s, KeyConversionBehavior conversionBehavior = Default);
PropertyKey asPropertyKey(const char *s, int len);
PropertyKey asPropertyKeyImpl(const Heap::String *str);
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index ad0e7f28cc..32f78f2bff 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -222,6 +222,12 @@ struct Q_QML_PRIVATE_EXPORT String : public StringOrSymbol {
return calculateHashValue(ch, end, subtype);
}
+ static uint createHashValueDisallowingArrayIndex(const QChar *ch, int length, uint *subtype)
+ {
+ const QChar *end = ch + length;
+ return calculateHashValue<String::DisallowArrayIndex>(ch, end, subtype);
+ }
+
static uint createHashValue(const char *ch, int length, uint *subtype)
{
const char *end = ch + length;
@@ -235,15 +241,19 @@ protected:
static qint64 virtualGetLength(const Managed *m);
public:
- template <typename T>
+ enum IndicesBehavior {Default, DisallowArrayIndex};
+ template <IndicesBehavior Behavior = Default, typename T>
static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
{
// array indices get their number as hash value
- uint h = stringToArrayIndex(ch, end);
- if (h != UINT_MAX) {
- if (subtype)
- *subtype = Heap::StringOrSymbol::StringType_ArrayIndex;
- return h;
+ uint h = UINT_MAX;
+ if (Behavior != DisallowArrayIndex) {
+ h = stringToArrayIndex(ch, end);
+ if (h != UINT_MAX) {
+ if (subtype)
+ *subtype = Heap::StringOrSymbol::StringType_ArrayIndex;
+ return h;
+ }
}
while (ch < end) {
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index 6754f22049..2866988a1a 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -73,6 +73,8 @@ private slots:
void contextObjectHierarchy();
void destroyContextProperty();
+ void numericContextProperty();
+
private:
QQmlEngine engine;
};
@@ -918,6 +920,14 @@ void tst_qqmlcontext::destroyContextProperty()
// TODO: Or are we?
}
+void tst_qqmlcontext::numericContextProperty()
+{
+ QQmlEngine engine;
+ auto context = engine.rootContext();
+ context->setContextProperty(QLatin1String("11"), 42);
+ QCOMPARE(context->contextProperty(QLatin1String("11")).toInt(), 42);
+}
+
QTEST_MAIN(tst_qqmlcontext)
#include "tst_qqmlcontext.moc"