QQmlObjectCreator: Do not crash on read-only bindable
If the binding was not actually set (because the bindable is readonly) then it's dead after the pop_front. We cannot examine it anymore, and we don't have to. Pick-to: 6.5 6.4 6.2 Fixes: QTBUG-109597 Change-Id: I3bf0ca501aa9ad45a64ad181b685ca6d9d325231 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
0461a51c8e
commit
4dfcaa7ee8
|
@ -1442,16 +1442,24 @@ bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
|
|||
void *argv[] = { &bindable };
|
||||
// allow interception
|
||||
target->metaObject()->metacall(target, QMetaObject::BindableProperty, index, argv);
|
||||
bindable.setBinding(qmlBinding);
|
||||
const bool success = bindable.setBinding(qmlBinding);
|
||||
|
||||
// Only pop_front after setting the binding as the bindings are refcounted.
|
||||
sharedState->allQPropertyBindings.pop_front();
|
||||
if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) {
|
||||
auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv);
|
||||
auto jsExpression = qmlBindingPriv->jsExpression();
|
||||
const bool canRemove = !qmlBinding.error().hasError() && !qmlBindingPriv->hasDependencies()
|
||||
&& !jsExpression->hasUnresolvedNames();
|
||||
if (canRemove)
|
||||
bindable.takeBinding();
|
||||
|
||||
// If the binding was actually not set, it's deleted now.
|
||||
if (success) {
|
||||
if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) {
|
||||
auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv);
|
||||
auto jsExpression = qmlBindingPriv->jsExpression();
|
||||
const bool canRemove = !qmlBinding.error().hasError()
|
||||
&& !qmlBindingPriv->hasDependencies()
|
||||
&& !jsExpression->hasUnresolvedNames();
|
||||
if (canRemove)
|
||||
bindable.takeBinding();
|
||||
}
|
||||
}
|
||||
|
||||
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import Qt.test
|
||||
import QtQuick
|
||||
|
||||
ReadOnlyBindable {
|
||||
property int v: 12
|
||||
x: v
|
||||
}
|
|
@ -541,6 +541,7 @@ void registerTypes()
|
|||
|
||||
qmlRegisterType<Receiver>("Qt.test", 1,0, "Receiver");
|
||||
qmlRegisterType<Sender>("Qt.test", 1,0, "Sender");
|
||||
qmlRegisterTypesAndRevisions<ReadOnlyBindable>("Qt.test", 1);
|
||||
}
|
||||
|
||||
#include "testtypes.moc"
|
||||
|
|
|
@ -1981,6 +1981,25 @@ public slots:
|
|||
int slot1(int i, int j, int k) {return i+j+k;}
|
||||
};
|
||||
|
||||
class ReadOnlyBindable : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_PROPERTY(int x READ x WRITE setX BINDABLE bindableX)
|
||||
Q_OBJECT_BINDABLE_PROPERTY(ReadOnlyBindable, int, _xProp)
|
||||
|
||||
public:
|
||||
ReadOnlyBindable(QObject *parent = nullptr)
|
||||
: QObject(parent)
|
||||
{
|
||||
setX(7);
|
||||
}
|
||||
|
||||
int x() const { return _xProp.value(); }
|
||||
void setX(int x) { _xProp.setValue(x); }
|
||||
QBindable<int> bindableX() const { return &_xProp; }
|
||||
};
|
||||
|
||||
void registerTypes();
|
||||
|
||||
#endif // TESTTYPES_H
|
||||
|
|
|
@ -414,6 +414,8 @@ private slots:
|
|||
void internalClassParentGc();
|
||||
void methodTypeMismatch();
|
||||
|
||||
void doNotCrashOnReadOnlyBindable();
|
||||
|
||||
private:
|
||||
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
|
||||
static void verifyContextLifetime(const QQmlRefPointer<QQmlContextData> &ctxt);
|
||||
|
@ -10355,6 +10357,22 @@ void tst_qqmlecmascript::methodTypeMismatch()
|
|||
QCOMPARE(object->actuals(), QVariantList() << QVariant::fromValue((QObject *)nullptr));
|
||||
}
|
||||
|
||||
void tst_qqmlecmascript::doNotCrashOnReadOnlyBindable()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
QQmlComponent c(&engine, testFileUrl("readOnlyBindable.qml"));
|
||||
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||
#ifndef QT_NO_DEBUG
|
||||
QTest::ignoreMessage(
|
||||
QtWarningMsg,
|
||||
"setBinding: Could not set binding via bindable interface. "
|
||||
"The QBindable is read-only.");
|
||||
#endif
|
||||
QScopedPointer<QObject> o(c.create());
|
||||
QVERIFY(o);
|
||||
QCOMPARE(o->property("x").toInt(), 7);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmlecmascript)
|
||||
|
||||
#include "tst_qqmlecmascript.moc"
|
||||
|
|
Loading…
Reference in New Issue