aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-03-23 11:36:59 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-03-28 10:51:10 +0100
commit8d81b24ffe3ddeea33a8611bdf666a0a44fd9cda (patch)
tree042bd414481327c651b0f446409d91ff4f7ddaf7 /tests
parentf4a55f7633d5ee2534363fc45129c86a5fae5d6b (diff)
V4 ArrayIterator: Protect retrieved value from GC
When constructing the iterator return object, the garbage collector may run, and drop the element value we want to return. Fixes: QTBUG-101700 Change-Id: I60c9b0b9fbb9e784fa089a8b5bb274d02ef7fc1f Reviewed-by: Maximilian Goldstein <max.goldstein@qt.io> Reviewed-by: Andrei Golubev <andrei.golubev@qt.io> (cherry picked from commit 185760fa44f5b62f1ed3f10a458f4bc38072768f) Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp72
1 files changed, 72 insertions, 0 deletions
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index b75bf820d5..c66e2dccf3 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -268,6 +268,7 @@ private slots:
void dataViewCtor();
void uiLanguage();
+ void forOfAndGc();
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
@@ -5250,6 +5251,77 @@ void tst_QJSEngine::uiLanguage()
}
}
+void tst_QJSEngine::forOfAndGc()
+{
+ // We want to guard against the iterator of a for..of loop leaving the result unprotected from
+ // garbage collection. It should be possible to construct a pure JS test case, but due to the
+ // vaguaries of garbage collection it's hard to reliably trigger the crash. This test is the
+ // best I could come up with.
+
+ QQmlEngine engine;
+ QQmlComponent c(&engine);
+ c.setData(R"(
+ import QtQml 2.15
+ import QtQml.Models 2.15
+
+ QtObject {
+ id: counter
+ property int count: 0
+
+ property DelegateModel model: DelegateModel {
+ id: filesModel
+
+ model: ListModel {
+ Component.onCompleted: {
+ for (let idx = 0; idx < 50; idx++)
+ append({"i" : idx})
+ }
+ }
+
+ groups: [
+ DelegateModelGroup {
+ name: "selected"
+ }
+ ]
+
+ function getSelected() {
+ for (let i = 0; i < items.count; ++i) {
+ var item = items.get(i)
+ for (let el of item.groups) {
+ if (el === "selected")
+ ++counter.count
+ }
+ }
+ }
+
+ property bool bSelect: true
+ function selectAll() {
+ for (let i = 0; i < items.count; ++i) {
+ if (bSelect && !items.get(i).inSelected)
+ items.addGroups(i, 1, ["selected"])
+ else
+ items.removeGroups(i, 1, ["selected"])
+ getSelected()
+ }
+ bSelect = !bSelect
+ }
+ }
+
+ property Timer timer: Timer {
+ running: true
+ interval: 1
+ repeat: true
+ onTriggered: filesModel.selectAll()
+ }
+ }
+ )", QUrl());
+
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+
+ QTRY_VERIFY(o->property("count").toInt() > 32768);
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"