diff options
author | Fabian Kosmale <[email protected]> | 2023-07-24 11:50:47 +0200 |
---|---|---|
committer | Ulf Hermann <[email protected]> | 2023-09-12 07:33:45 +0200 |
commit | 9189ea15fa44fb072fc0a7737050074854d52527 (patch) | |
tree | a2db9d3f8a494c220f5b472f301468b215208e7a | |
parent | d25da3e7b840838c66c92ff627b7ffa1d923012e (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.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4identifiertable.cpp | 24 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4identifiertable_p.h | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4string_p.h | 22 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 10 |
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" |