diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 6475ec6e06..4d55b15cfa 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -41,8 +41,11 @@ void Object::setInternalClass(Heap::InternalClass *ic) // Pick the members of the old IC that are still valid in the new IC. // Order them by index in memberData (or inline data). Scoped newMembers(scope, MemberData::allocate(scope.engine, ic->size)); - for (uint i = 0; i < ic->size; ++i) - newMembers->set(scope.engine, i, get(ic->nameMap.at(i))); + for (uint i = 0; i < ic->size; ++i) { + // Note that some members might have been deleted. The key may be invalid. + const PropertyKey key = ic->nameMap.at(i); + newMembers->set(scope.engine, i, key.isValid() ? get(key) : Encode::undefined()); + } p->internalClass.set(scope.engine, ic); const uint nInline = p->vtable()->nInlineProperties; diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index b6cb4ae0f3..c1c755d843 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -310,6 +310,9 @@ private slots: void symbolToVariant(); void garbageCollectedObjectMethodBase(); + + void deleteDefineCycle(); + public: Q_INVOKABLE QJSValue throwingCppMethod1(); Q_INVOKABLE void throwingCppMethod2(); @@ -6302,6 +6305,25 @@ void tst_QJSEngine::garbageCollectedObjectMethodBase() } } +void tst_QJSEngine::deleteDefineCycle() +{ + QJSEngine engine; + QStringList stackTrace; + + QJSValue result = engine.evaluate(QString::fromLatin1(R"( + let global = ({}) + + for (let j = 0; j < 1000; j++) { + for (let i = 0; i < 2; i++) { + const name = "test" + i + delete global[name] + Object.defineProperty(global, name, { get() { return 0 }, configurable: true }) + } + } + )"), {}, 1, &stackTrace); + QVERIFY(stackTrace.isEmpty()); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc"