aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-03-28 01:00:54 +0100
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-03-28 01:00:54 +0100
commit4407f1f81813216bf64021eab7dcecc88d3056fe (patch)
treeaba2c7ed9a8f8d04898faced151c30b9dfbe0508
parent187b2e0efccb9e803a72fc87a3659d8b76a73ca9 (diff)
parent3507c29e8d9ea42e63fd0c01e27ee9263d939256 (diff)
Merge remote-tracking branch 'origin/5.12' into 5.13
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4engine.cpp16
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp35
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h10
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp21
-rw-r--r--src/quick/items/qquickpathview.cpp4
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp13
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp13
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickpathview/data/pathview5.qml65
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp23
12 files changed, 179 insertions, 32 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 8637db3dfd..b5b421fa39 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -103,7 +103,9 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
ctor->defineDefaultProperty(QStringLiteral("from"), method_from, 1);
ctor->addSymbolSpecies();
- ScopedObject unscopables(scope, engine->newObject(engine->classes[EngineBase::Class_Empty]->changeVTable(QV4::Object::staticVTable())));
+ Scoped<InternalClass> ic(scope, engine->classes[EngineBase::Class_Empty]
+ ->changeVTable(QV4::Object::staticVTable()));
+ ScopedObject unscopables(scope, engine->newObject(ic->d()));
ScopedString name(scope);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString, 0);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 0a41579a25..f506e4015e 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -467,11 +467,17 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(global);
jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(global);
jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>();
- jsObjects[ForInIteratorProto] = memoryManager->allocObject<ForInIteratorPrototype>(newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype()));
- jsObjects[MapIteratorProto] = memoryManager->allocObject<MapIteratorPrototype>(newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype()));
- jsObjects[SetIteratorProto] = memoryManager->allocObject<SetIteratorPrototype>(newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype()));
- jsObjects[ArrayIteratorProto] = memoryManager->allocObject<ArrayIteratorPrototype>(newInternalClass(ArrayIteratorPrototype::staticVTable(), iteratorPrototype()));
- jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(newInternalClass(StringIteratorPrototype::staticVTable(), iteratorPrototype()));
+
+ ic = newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype());
+ jsObjects[ForInIteratorProto] = memoryManager->allocObject<ForInIteratorPrototype>(ic);
+ ic = newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype());
+ jsObjects[MapIteratorProto] = memoryManager->allocObject<MapIteratorPrototype>(ic);
+ ic = newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype());
+ jsObjects[SetIteratorProto] = memoryManager->allocObject<SetIteratorPrototype>(ic);
+ ic = newInternalClass(ArrayIteratorPrototype::staticVTable(), iteratorPrototype());
+ jsObjects[ArrayIteratorProto] = memoryManager->allocObject<ArrayIteratorPrototype>(ic);
+ ic = newInternalClass(StringIteratorPrototype::staticVTable(), iteratorPrototype());
+ jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(ic);
str = newString(QStringLiteral("get [Symbol.species]"));
jsObjects[GetSymbolSpecies] = FunctionObject::createBuiltinFunction(this, str, ArrayPrototype::method_get_species, 0);
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
index 566db6fd4e..14caa6953f 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -139,7 +139,9 @@ void GeneratorPrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedValue v(scope);
- ScopedObject ctorProto(scope, engine->newObject(engine->newInternalClass(Object::staticVTable(), engine->functionPrototype())));
+ Scoped<InternalClass> ic(scope, engine->newInternalClass(
+ Object::staticVTable(), engine->functionPrototype()));
+ ScopedObject ctorProto(scope, engine->newObject(ic->d()));
ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(1));
ctor->defineReadonlyProperty(engine->id_prototype(), ctorProto);
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 8e2657f4a5..a10fda79f2 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -145,7 +145,7 @@ SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(cons
data(nullptr)
{
if (other.alloc()) {
- int s = other.size();
+ const uint s = other.size();
data = MemberData::allocate(engine, other.alloc(), other.data);
setSize(s);
}
@@ -164,8 +164,8 @@ SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(cons
void SharedInternalClassDataPrivate<PropertyKey>::grow()
{
- uint a = alloc() * 2;
- int s = size();
+ const uint a = alloc() * 2;
+ const uint s = size();
data = MemberData::allocate(engine, a, data);
setSize(s);
Q_ASSERT(alloc() >= a);
@@ -209,10 +209,11 @@ SharedInternalClassDataPrivate<PropertyAttributes>::SharedInternalClassDataPriva
const SharedInternalClassDataPrivate<PropertyAttributes> &other, uint pos,
PropertyAttributes value)
: refcount(1),
- m_alloc(pos + 8),
+ m_alloc(qMin(other.m_alloc, pos + 8)),
m_size(pos + 1),
m_engine(other.m_engine)
{
+ Q_ASSERT(m_size <= m_alloc);
m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes));
data = new PropertyAttributes[m_alloc];
if (other.data)
@@ -244,22 +245,29 @@ SharedInternalClassDataPrivate<PropertyAttributes>::~SharedInternalClassDataPriv
}
void SharedInternalClassDataPrivate<PropertyAttributes>::grow() {
+ uint alloc;
if (!m_alloc) {
- m_alloc = 4;
- m_engine->memoryManager->changeUnmanagedHeapSizeUsage(
- 2 * m_alloc * sizeof(PropertyAttributes));
+ alloc = 8;
+ m_engine->memoryManager->changeUnmanagedHeapSizeUsage(alloc * sizeof(PropertyAttributes));
} else {
+ // yes, signed. We don't want to deal with stuff > 2G
+ const uint currentSize = m_alloc * sizeof(PropertyAttributes);
+ if (currentSize < uint(std::numeric_limits<int>::max() / 2))
+ alloc = m_alloc * 2;
+ else
+ alloc = std::numeric_limits<int>::max() / sizeof(PropertyAttributes);
+
m_engine->memoryManager->changeUnmanagedHeapSizeUsage(
- m_alloc * sizeof(PropertyAttributes));
+ (alloc - m_alloc) * sizeof(PropertyAttributes));
}
- auto *n = new PropertyAttributes[m_alloc * 2];
+ auto *n = new PropertyAttributes[alloc];
if (data) {
memcpy(n, data, m_alloc*sizeof(PropertyAttributes));
delete [] data;
}
data = n;
- m_alloc *= 2;
+ m_alloc = alloc;
}
namespace Heap {
@@ -658,11 +666,10 @@ Heap::InternalClass *InternalClass::frozen()
return f;
}
-Heap::InternalClass *InternalClass::propertiesFrozen() const
+Heap::InternalClass *InternalClass::propertiesFrozen()
{
Scope scope(engine);
- Scoped<QV4::InternalClass> frozen(scope, engine->internalClasses(EngineBase::Class_Empty)->changeVTable(vtable));
- frozen = frozen->changePrototype(prototype);
+ Scoped<QV4::InternalClass> frozen(scope, this);
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
if (!nameMap.at(i).isValid())
@@ -671,7 +678,7 @@ Heap::InternalClass *InternalClass::propertiesFrozen() const
attrs.setWritable(false);
attrs.setConfigurable(false);
}
- frozen = frozen->addMember(nameMap.at(i), attrs);
+ frozen = frozen->changeMember(nameMap.at(i), attrs);
}
return frozen->d();
}
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index c689637721..42b61218a5 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -247,8 +247,12 @@ struct SharedInternalClassData {
Q_ASSERT(pos == d->size());
if (pos == d->alloc())
d->grow();
- d->setSize(d->size() + 1);
- d->set(pos, value);
+ if (pos >= d->alloc()) {
+ qBadAlloc();
+ } else {
+ d->setSize(d->size() + 1);
+ d->set(pos, value);
+ }
}
void set(uint pos, T value) {
@@ -428,7 +432,7 @@ struct InternalClass : Base {
Q_REQUIRED_RESULT InternalClass *sealed();
Q_REQUIRED_RESULT InternalClass *frozen();
- Q_REQUIRED_RESULT InternalClass *propertiesFrozen() const;
+ Q_REQUIRED_RESULT InternalClass *propertiesFrozen();
Q_REQUIRED_RESULT InternalClass *asProtoClass();
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index 246f857643..f327c85001 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -69,12 +69,25 @@ Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberD
size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value));
// round up to next power of two to avoid quadratic behaviour for very large objects
alloc = nextPowerOfTwo(alloc);
- Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc);
- if (old)
+
+ // The above code can overflow in a number of interesting ways. All of those are unsigned,
+ // and therefore defined behavior. Still, apply some sane bounds.
+ if (alloc > std::numeric_limits<int>::max())
+ alloc = std::numeric_limits<int>::max();
+
+ Heap::MemberData *m;
+ if (old) {
+ const size_t oldSize = sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value);
+ if (oldSize > alloc)
+ alloc = oldSize;
+ m = e->memoryManager->allocManaged<MemberData>(alloc);
// no write barrier required here
- memcpy(m, old, sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value));
- else
+ memcpy(m, old, oldSize);
+ } else {
+ m = e->memoryManager->allocManaged<MemberData>(alloc);
m->init();
+ }
+
m->values.alloc = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
m->values.size = m->values.alloc;
return m;
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index be8532bf64..e4480b335a 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -2419,10 +2419,6 @@ void QQuickPathViewPrivate::snapToIndex(int index, MovementReason reason)
return;
qreal targetOffset = std::fmod(qreal(modelCount - index), qreal(modelCount));
-
- if (offset == targetOffset)
- return;
-
moveReason = reason;
offsetAdj = 0.0;
tl.reset(moveOffset);
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 3e871108bc..620e31e01a 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -236,6 +236,7 @@ private slots:
void importExportErrors();
void equality();
+ void aggressiveGc();
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
@@ -4632,6 +4633,18 @@ void tst_QJSEngine::equality()
QCOMPARE(ok.toString(), QString("ok"));
}
+void tst_QJSEngine::aggressiveGc()
+{
+ const QByteArray origAggressiveGc = qgetenv("QV4_MM_AGGRESSIVE_GC");
+ qputenv("QV4_MM_AGGRESSIVE_GC", "true");
+ {
+ QJSEngine engine; // ctor crashes if core allocation methods don't properly scope things.
+ QJSValue obj = engine.newObject();
+ QVERIFY(obj.isObject());
+ }
+ qputenv("QV4_MM_AGGRESSIVE_GC", origAggressiveGc);
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index f58ae38264..b9cb6b70d2 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -80,6 +80,7 @@ private slots:
void qrcUrls();
void cppSignalAndEval();
void singletonInstance();
+ void aggressiveGc();
public slots:
QObject *createAQObjectForOwnershipTest ()
@@ -1043,6 +1044,18 @@ void tst_qqmlengine::singletonInstance()
}
}
+void tst_qqmlengine::aggressiveGc()
+{
+ const QByteArray origAggressiveGc = qgetenv("QV4_MM_AGGRESSIVE_GC");
+ qputenv("QV4_MM_AGGRESSIVE_GC", "true");
+ {
+ QQmlEngine engine; // freezing should not run into infinite recursion
+ QJSValue obj = engine.newObject();
+ QVERIFY(obj.isObject());
+ }
+ qputenv("QV4_MM_AGGRESSIVE_GC", origAggressiveGc);
+}
+
QTEST_MAIN(tst_qqmlengine)
#include "tst_qqmlengine.moc"
diff --git a/tests/auto/qml/qquickfolderlistmodel/BLACKLIST b/tests/auto/qml/qquickfolderlistmodel/BLACKLIST
new file mode 100644
index 0000000000..642fdea741
--- /dev/null
+++ b/tests/auto/qml/qquickfolderlistmodel/BLACKLIST
@@ -0,0 +1,3 @@
+[nameFilters]
+msvc-2015
+msvc-2017
diff --git a/tests/auto/quick/qquickpathview/data/pathview5.qml b/tests/auto/quick/qquickpathview/data/pathview5.qml
new file mode 100644
index 0000000000..479c5dc500
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/pathview5.qml
@@ -0,0 +1,65 @@
+import QtQuick 2.0
+
+PathView {
+ property int countclick: 0
+ id: pathview
+ y: 0
+ width: 348
+ height: 480
+
+ interactive: false
+
+ cacheItemCount: 10
+ currentIndex: 2
+ pathItemCount: 4
+ highlightMoveDuration: 1000
+ highlightRangeMode : PathView.StrictlyEnforceRange
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ snapMode : PathView.SnapOneItem
+
+ path: Path {
+ id: leftPath
+ startX: pathview.width / 2 - 800
+ startY: pathview.height / 2 - 800
+
+ PathArc {
+ x: pathview.width / 2 - 800
+ y: pathview.height / 2 + 800
+ radiusX: 800
+ radiusY: 800
+ direction: PathArc.Clockwise
+ }
+ }
+
+ model: ListModel {
+ id: model
+ ListElement { objectName:"aqua"; name: "aqua" ;mycolor:"aqua"}
+ ListElement { objectName:"blue"; name: "blue" ;mycolor:"blue"}
+ ListElement { objectName:"blueviolet"; name: "blueviolet" ;mycolor:"blueviolet"}
+ ListElement { objectName:"brown"; name: "brown" ;mycolor:"brown"}
+ ListElement { objectName:"chartreuse"; name: "chartreuse" ;mycolor:"chartreuse"}
+ }
+
+ delegate: Item {
+ id: revolveritem
+ objectName: model.objectName
+
+ width: pathview.width
+ height: pathview.height
+
+ Rectangle
+ {
+ id:myRectangle
+ color: mycolor
+ width: pathview.width -20
+ height: pathview.height -20
+
+ Text {
+ anchors.centerIn: parent
+ text: "index:"+index
+ color: "white"
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index bf38d2d926..1a5ce39318 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -104,6 +104,7 @@ private slots:
void offset_data();
void offset();
void setCurrentIndex();
+ void setCurrentIndexWrap();
void resetModel();
void propertyChanges();
void pathChanges();
@@ -1138,6 +1139,28 @@ void tst_QQuickPathView::setCurrentIndex()
QCOMPARE(currentIndexSpy.count(), 1);
}
+void tst_QQuickPathView::setCurrentIndexWrap()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("pathview5.qml"));
+ window->show();
+ qApp->processEvents();
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
+ QVERIFY(pathview);
+
+ // set current index to last item
+ pathview->setCurrentIndex(4);
+ // set currentIndex to first item, then quickly set it back (QTBUG-74508)
+ QSignalSpy currentIndexSpy(pathview, SIGNAL(currentIndexChanged()));
+ QSignalSpy movementStartedSpy(pathview, SIGNAL(movementStarted()));
+ pathview->setCurrentIndex(0);
+ pathview->setCurrentIndex(4);
+ QCOMPARE(pathview->currentIndex(), 4);
+ QCOMPARE(currentIndexSpy.count(), 2);
+ QCOMPARE(movementStartedSpy.count(), 0);
+}
+
void tst_QQuickPathView::resetModel()
{
QScopedPointer<QQuickView> window(createView());