diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2020-01-09 01:00:43 +0100 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-01-09 07:24:26 +0000 |
commit | ba10b0b9ed93be007fcb156710ef6081000e3ae3 (patch) | |
tree | ea17c625900b83d5955cb4a2db1587a5f07e2fb4 /src/qml/jsruntime | |
parent | 653c25d48298fb747cf6f3b012816855c51d4260 (diff) | |
parent | 1798d20ded699837f7b3afe0bb340617af266518 (diff) |
Merge remote-tracking branch 'origin/5.14' into 5.15
Conflicts:
src/particles/qquickitemparticle.cpp
src/qmlmodels/qqmladaptormodel.cpp
tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
Change-Id: Ibd8fbb91da6893a09f4ffe61ad0b95d8149bbc87
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4arraydata.cpp | 8 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4arrayobject.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 99 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 11 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 8 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectiterator.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectproto.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4proxy.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4regexp.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4regexpobject.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4typedarray.cpp | 7 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 2 |
13 files changed, 138 insertions, 14 deletions
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 654d33b8d1..1c587d2367 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -586,7 +586,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) obj->arrayPut(oldSize, os->values.data() + os->offset, chunk); toCopy -= chunk; if (toCopy) - obj->arrayPut(oldSize + chunk, os->values.data(), toCopy); + obj->setArrayLength(oldSize + chunk + toCopy); } return oldSize + n; @@ -659,6 +659,12 @@ bool ArrayElementLessThan::operator()(Value v1, Value v2) const } ScopedString p1s(scope, v1.toString(scope.engine)); ScopedString p2s(scope, v2.toString(scope.engine)); + + if (!p1s) + return false; + if (!p2s) + return true; + return p1s->toQString() < p2s->toQString(); } diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index d8d0d4739f..6c51b4cbcb 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -1048,8 +1048,9 @@ ReturnedValue ArrayPrototype::method_includes(const FunctionObject *b, const Val } } + ScopedValue val(scope); while (k < len) { - ScopedValue val(scope, instance->get(k)); + val = instance->get(k); if (val->sameValueZero(argv[0])) { return Encode(true); } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index cd2327a45e..14eaa5bce8 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -43,6 +43,7 @@ #include <private/qqmljsdiagnosticmessage_p.h> #include <QtCore/QTextStream> +#include <QtCore/private/qvariant_p.h> #include <QDateTime> #include <QDir> #include <QFileInfo> @@ -118,6 +119,7 @@ #endif #include <private/qv4sqlerrors_p.h> #include <qqmlfile.h> +#include <qmetatype.h> #if USE(PTHREADS) # include <pthread.h> @@ -185,6 +187,91 @@ static void restoreJSValue(QDataStream &stream, void *data) } } +struct JSArrayIterator { + QJSValue const* data; + quint32 index; +}; + +namespace { +void createNewIteratorIfNonExisting(void **iterator) { + if (*iterator == nullptr) + *iterator = new JSArrayIterator; +} +} + +static QtMetaTypePrivate::QSequentialIterableImpl jsvalueToSequence (const QJSValue& value) { + using namespace QtMetaTypePrivate; + + QSequentialIterableImpl iterator {}; + if (!value.isArray()) { + // set up some functions so that non-array QSequentialIterables do not crash + // but instead appear as an empty sequence + iterator._size = [](const void *) {return 0;}; + iterator._moveToBegin = [](const void *, void **) {}; + iterator._moveToEnd = [](const void *, void **) {}; + iterator._advance = [](void **, int) {}; + iterator._equalIter = [](void * const *, void * const *){return true; /*all iterators are nullptr*/}; + iterator._destroyIter = [](void **){}; + return iterator; + } + + iterator._iterable = &value; + iterator._iterator = nullptr; + iterator._metaType_id = qMetaTypeId<QVariant>(); + iterator._metaType_flags = QVariantConstructionFlags::ShouldDeleteVariantData; + iterator._iteratorCapabilities = RandomAccessCapability | BiDirectionalCapability | ForwardCapability; + iterator._size = [](const void *p) -> int { + return static_cast<QJSValue const *>(p)->property(QString::fromLatin1("length")).toInt(); + }; + /* Lifetime management notes: + * _at and _get return a pointer to a JSValue allocated via QMetaType::create + * Because we set QVariantConstructionFlags::ShouldDeleteVariantData, QSequentialIterable::at + * and QSequentialIterable::operator*() will free that memory + */ + + iterator._at = [](const void *iterable, int index) -> void const * { + auto const value = static_cast<QJSValue const *>(iterable)->property(quint32(index)).toVariant(); + return QMetaType::create(qMetaTypeId<QVariant>(), &value); + }; + iterator._moveToBegin = [](const void *iterable, void **iterator) { + createNewIteratorIfNonExisting(iterator); + auto jsArrayIterator = static_cast<JSArrayIterator *>(*iterator); + jsArrayIterator->index = 0; + jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable); + }; + iterator._moveToEnd = [](const void *iterable, void **iterator) { + createNewIteratorIfNonExisting(iterator); + auto jsArrayIterator = static_cast<JSArrayIterator *>(*iterator); + auto length = static_cast<QJSValue const *>(iterable)->property(QString::fromLatin1("length")).toInt(); + jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable); + jsArrayIterator->index = quint32(length); + }; + iterator._advance = [](void **iterator, int advanceBy) { + static_cast<JSArrayIterator *>(*iterator)->index += quint32(advanceBy); + }; + iterator._get = []( void * const *iterator, int metaTypeId, uint flags) -> VariantData { + auto const * const arrayIterator = static_cast<const JSArrayIterator *>(*iterator); + QJSValue const * const jsArray = arrayIterator->data; + auto const value = jsArray->property(arrayIterator->index).toVariant(); + Q_ASSERT(flags & QVariantConstructionFlags::ShouldDeleteVariantData); + return {metaTypeId, QMetaType::create(qMetaTypeId<QVariant>(), &value), flags}; + }; + iterator._destroyIter = [](void **iterator) { + delete static_cast<JSArrayIterator *>(*iterator); + }; + iterator._equalIter = [](void * const *p, void * const *other) { + auto this_ = static_cast<const JSArrayIterator *>(*p); + auto that_ = static_cast<const JSArrayIterator *>(*other); + return this_->index == that_->index && this_->data == that_->data; + }; + iterator._copyIter = [](void **iterator, void * const * otherIterator) { + auto *otherIter = (static_cast<JSArrayIterator const *>(*otherIterator)); + static_cast<JSArrayIterator *>(*iterator)->index = otherIter->index; + static_cast<JSArrayIterator *>(*iterator)->data = otherIter->data; + }; + return iterator; +} + ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) : executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) @@ -712,6 +799,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>); if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>()) QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>); + if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QtMetaTypePrivate::QSequentialIterableImpl>()) + QMetaType::registerConverter<QJSValue, QtMetaTypePrivate::QSequentialIterableImpl>(jsvalueToSequence); QMetaType::registerStreamOperators(qMetaTypeId<QJSValue>(), saveJSValue, restoreJSValue); QV4::QObjectWrapper::initializeBindings(this); @@ -1178,8 +1267,11 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) void ExecutionEngine::markObjects(MarkStack *markStack) { for (int i = 0; i < NClasses; ++i) - if (classes[i]) + if (classes[i]) { classes[i]->mark(markStack); + if (markStack->top >= markStack->limit) + markStack->drain(); + } markStack->drain(); identifierTable->markObjects(markStack); @@ -2238,4 +2330,9 @@ int ExecutionEngine::registerExtension() return registrationData()->extensionCount++; } +QNetworkAccessManager *QV4::detail::getNetworkAccessManager(ExecutionEngine *engine) +{ + return engine->qmlEngine()->networkAccessManager(); +} + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index d233347060..e0025feb00 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -91,7 +91,14 @@ class PageAllocation; QT_BEGIN_NAMESPACE -namespace QV4 { struct QObjectMethod; } +class QNetworkAccessManager; + +namespace QV4 { +struct QObjectMethod; +namespace detail { +QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine); +} +} // Used to allow a QObject method take and return raw V4 handles without having to expose // 48 in the public API. @@ -348,6 +355,8 @@ public: FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); } FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } + QNetworkAccessManager* (*networkAccessManager)(ExecutionEngine*) = detail::getNetworkAccessManager; + enum JSStrings { String_Empty, String_undefined, diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 6fb7946023..dfef52583e 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -364,7 +364,13 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons if (!arr) return v4->throwTypeError(); - uint len = arr->getLength(); + const qint64 len64 = arr->getLength(); + if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max())) + return v4->throwRangeError(QStringLiteral("Invalid array length.")); + if (len64 > qint64(v4->jsStackLimit - v4->jsStackTop)) + return v4->throwRangeError(QStringLiteral("Array too large for apply().")); + + const uint len = uint(len64); Scope scope(v4); Value *arguments = scope.alloc<Scope::Uninitialized>(len); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index f3375929a3..9e901d6a34 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -157,7 +157,7 @@ struct Q_QML_EXPORT Object: Managed { const Value *propertyData(uint index) const { return d()->propertyData(index); } Heap::ArrayData *arrayData() const { return d()->arrayData; } - void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a->d()); } + void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a ? a->d() : nullptr); } void getProperty(const InternalClassEntry &entry, Property *p) const; void setProperty(const InternalClassEntry &entry, const Property *p); diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index e529b8e86b..65f6fa8b12 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -182,7 +182,7 @@ PropertyKey ForInIteratorObject::nextProperty() const if (d()->current != d()->object) { o = d()->object; bool shadowed = false; - while (o->d() != c->heapObject()) { + while (o && o->d() != c->heapObject()) { if (o->getOwnProperty(key) != Attr_Invalid) { shadowed = true; break; diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 3d3b3f413f..7d910a1cbc 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -658,6 +658,7 @@ ReturnedValue ObjectPrototype::method_toString(const FunctionObject *b, const Va ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { Scope scope(b); + CHECK_STACK_LIMITS(scope.engine) ScopedObject o(scope, thisObject->toObject(scope.engine)); if (!o) RETURN_UNDEFINED(); diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp index 9325e2e53b..51f96b9003 100644 --- a/src/qml/jsruntime/qv4proxy.cpp +++ b/src/qml/jsruntime/qv4proxy.cpp @@ -515,7 +515,7 @@ ProxyObjectOwnPropertyKeyIterator::ProxyObjectOwnPropertyKeyIterator(ArrayObject PropertyKey ProxyObjectOwnPropertyKeyIterator::next(const Object *m, Property *pd, PropertyAttributes *attrs) { - if (index >= len) + if (index >= len || m == nullptr) return PropertyKey::invalid(); Scope scope(m); diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 4ed1dbd5aa..76daead842 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -73,14 +73,13 @@ DEFINE_MANAGED_VTABLE(RegExp); uint RegExp::match(const QString &string, int start, uint *matchOffsets) { - static const uint offsetJITFail = std::numeric_limits<unsigned>::max() - 1; - if (!isValid()) return JSC::Yarr::offsetNoMatch; WTF::String s(string); #if ENABLE(YARR_JIT) + static const uint offsetJITFail = std::numeric_limits<unsigned>::max() - 1; auto *priv = d(); if (priv->hasValidJITCode()) { uint ret = JSC::Yarr::offsetNoMatch; diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index c1a42c4afa..f1375e4ca4 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -961,8 +961,8 @@ ReturnedValue RegExpPrototype::method_compile(const FunctionObject *b, const Val return scope.engine->throwTypeError(); Scoped<RegExpObject> re(scope, scope.engine->regExpCtor()->callAsConstructor(argv, argc)); - - r->d()->value.set(scope.engine, re->value()); + if (re) // Otherwise the regexp constructor should have thrown an exception + r->d()->value.set(scope.engine, re->value()); return Encode::undefined(); } diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 9c50ac2b95..2ed1971235 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -1409,7 +1409,8 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b, if (scope.engine->hasException || l != len) return scope.engine->throwTypeError(); - if (offset + l > a->length()) + const uint aLength = a->length(); + if (offset > aLength || l > aLength - offset) RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"))); uint idx = 0; @@ -1439,7 +1440,9 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b, return scope.engine->throwTypeError(); uint l = srcTypedArray->length(); - if (offset + l > a->length()) + + const uint aLength = a->length(); + if (offset > aLength || l > aLength - offset) RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"))); char *dest = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize; diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 4e901721cb..ae12033eb4 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -555,6 +555,8 @@ struct ValueArray { } else { while (v < end) { v->mark(markStack); + if (markStack->top >= markStack->limit) + markStack->drain(); ++v; } } |