aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp21
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h3
-rw-r--r--tests/auto/qml/qqmlecmascript/data/generatorCrashNewProperty.qml20
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp16
4 files changed, 47 insertions, 13 deletions
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
index 4eee6f4338..5077bf1d2b 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -97,24 +97,21 @@ ReturnedValue GeneratorFunction::virtualCall(const FunctionObject *f, const Valu
Function *function = gf->function();
ExecutionEngine *engine = gf->engine();
- // We need to set up a separate stack for the generator, as it's being re-entered
- uint stackSize = argc // space for the original arguments
- + CppStackFrame::requiredJSStackFrameSize(function); // space for the JS stack frame
-
- size_t requiredMemory = sizeof(GeneratorObject::Data) - sizeof(Value) + sizeof(Value) * stackSize;
-
Scope scope(gf);
- Scoped<GeneratorObject> g(scope, scope.engine->memoryManager->allocManaged<GeneratorObject>(requiredMemory, scope.engine->classes[EngineBase::Class_GeneratorObject]));
+ Scoped<GeneratorObject> g(scope, engine->memoryManager->allocManaged<GeneratorObject>(sizeof(GeneratorObject::Data), engine->classes[EngineBase::Class_GeneratorObject]));
g->setPrototypeOf(ScopedObject(scope, gf->get(scope.engine->id_prototype())));
+ // We need to set up a separate JSFrame for the generator, as it's being re-entered
Heap::GeneratorObject *gp = g->d();
- gp->stack.size = stackSize;
- gp->stack.alloc = stackSize;
+ gp->values.set(engine, engine->newArrayObject(argc));
+ gp->jsFrame.set(engine, engine->newArrayObject(CppStackFrame::requiredJSStackFrameSize(function)));
// copy original arguments
- memcpy(gp->stack.values, argv, argc*sizeof(Value));
- gp->cppFrame.init(engine, function, gp->stack.values, argc);
- gp->cppFrame.setupJSFrame(&gp->stack.values[argc], *gf, gf->scope(),
+ for (int i = 0; i < argc; i++)
+ gp->values->arrayData->setArrayData(engine, i, argv[i]);
+
+ gp->cppFrame.init(engine, function, gp->values->arrayData->values.values, argc);
+ gp->cppFrame.setupJSFrame(gp->jsFrame->arrayData->values.values, *gf, gf->scope(),
thisObject ? *thisObject : Value::undefinedValue(),
Value::undefinedValue());
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
index 366319723d..10eea5e46b 100644
--- a/src/qml/jsruntime/qv4generatorobject_p.h
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -90,7 +90,8 @@ struct GeneratorPrototype : FunctionObject {
Member(class, Pointer, GeneratorFunction *, function) \
Member(class, NoMark, GeneratorState, state) \
Member(class, NoMark, CppStackFrame, cppFrame) \
- Member(class, ValueArray, ValueArray, stack)
+ Member(class, Pointer, ArrayObject *, values) \
+ Member(class, Pointer, ArrayObject *, jsFrame)
DECLARE_HEAP_OBJECT(GeneratorObject, Object) {
DECLARE_MARKOBJECTS(GeneratorObject);
diff --git a/tests/auto/qml/qqmlecmascript/data/generatorCrashNewProperty.qml b/tests/auto/qml/qqmlecmascript/data/generatorCrashNewProperty.qml
new file mode 100644
index 0000000000..f775b4c613
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/generatorCrashNewProperty.qml
@@ -0,0 +1,20 @@
+// QTBUG-91491
+import QtQml 2.15
+
+QtObject {
+ property int a: 42
+ property int b: 0
+ property int c: 0
+
+ function f(myfunc) {
+ let gen = myfunc();
+ gen["u"] = 0 // Adding members to the generator used to cause crashes when calling next()
+ c = gen.next().value
+ }
+
+ function refreshA() {
+ f(function*() { b = 12; return a });
+ }
+
+ Component.onCompleted: refreshA();
+}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 73c2267dca..d3874ee47d 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -239,6 +239,7 @@ private slots:
void eval();
void function();
void topLevelGeneratorFunction();
+ void generatorCrashNewProperty();
void qtbug_10696();
void qtbug_11606();
void qtbug_11600();
@@ -6364,6 +6365,21 @@ void tst_qqmlecmascript::topLevelGeneratorFunction()
QCOMPARE(it.property("next").callWithInstance(it).property("value").toInt(), 1);
}
+// QTBUG-91491
+void tst_qqmlecmascript::generatorCrashNewProperty()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("generatorCrashNewProperty.qml"));
+
+ QScopedPointer<QObject> o(component.create());
+
+ QVERIFY2(o != nullptr, qPrintable(component.errorString()));
+
+ QCOMPARE(o->property("a").toInt(), 42);
+ QCOMPARE(o->property("b").toInt(), 12);
+ QCOMPARE(o->property("c").toInt(), 42);
+}
+
// Test the "Qt.include" method
void tst_qqmlecmascript::include()
{