Fix QMetaMethod::invoke and automatic type registration

This was simply not working for two reasons:
 - The index passed to QMetaObject::metacall was not right (there was an offset
   because of the return type)
 - If the registration succeeded, the arguments were not even initialized.

The tests in tst_moc always called QMetaMethod::parameterType before calling invoke,
which was properly registering the type. So this was not seen in the tests before.

[ChangeLog][QtCore][QMetaMethod] Fixed crash in invoke() with QueuedConnection and
types whose metatype gets automatically registered.

Task-number: QTBUG-60185
Change-Id: I4247628484214fba0a8acc1813ed8f112f59c888
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Olivier Goffart 2017-04-18 12:08:12 +02:00 committed by Olivier Goffart (Woboq GmbH)
parent 23287dfb15
commit d4cdc45426
2 changed files with 36 additions and 5 deletions

View File

@ -2241,12 +2241,10 @@ bool QMetaMethod::invoke(QObject *object,
for (int i = 1; i < paramCount; ++i) {
types[i] = QMetaType::type(typeNames[i]);
if (types[i] != QMetaType::UnknownType) {
args[i] = QMetaType::create(types[i], param[i]);
++nargs;
} else if (param[i]) {
if (types[i] == QMetaType::UnknownType && param[i]) {
// Try to register the type and try again before reporting an error.
void *argv[] = { &types[i], &i };
int index = nargs - 1;
void *argv[] = { &types[i], &index };
QMetaObject::metacall(object, QMetaObject::RegisterMethodArgumentMetaType,
idx_relative + idx_offset, argv);
if (types[i] == -1) {
@ -2261,6 +2259,10 @@ bool QMetaMethod::invoke(QObject *object,
return false;
}
}
if (types[i] != QMetaType::UnknownType) {
args[i] = QMetaType::create(types[i], param[i]);
++nargs;
}
}
QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,

View File

@ -206,6 +206,7 @@ private slots:
void invokeMetaConstructor();
void invokeTypedefTypes();
void invokeException();
void invokeQueuedAutoRegister();
void qtMetaObjectInheritance();
void normalizedSignature_data();
void normalizedSignature();
@ -377,6 +378,7 @@ class QtTestObject: public QObject
public:
QtTestObject();
QtTestObject(const QString &s) : slotResult(s) {}
Q_INVOKABLE QtTestObject(QObject *parent);
public slots:
@ -416,6 +418,15 @@ public slots:
return s2;
}
void slotWithRegistrableArgument(QtTestObject *o1, QPointer<QtTestObject> o2,
QSharedPointer<QtTestObject> o3, QWeakPointer<QtTestObject> o4,
QVector<QtTestObject *> o5, QList<QtTestObject *> o6)
{
slotResult = QLatin1String("slotWithRegistrableArgument:") + o1->slotResult + o2->slotResult
+ o3->slotResult + o4.data()->slotResult + QString::number(o5.size())
+ QString::number(o6.size());
}
signals:
void sig0();
QString sig1(QString s1);
@ -944,6 +955,24 @@ void tst_QMetaObject::invokeException()
#endif
}
void tst_QMetaObject::invokeQueuedAutoRegister()
{
QtTestObject obj;
auto shared = QSharedPointer<QtTestObject>::create(QStringLiteral("myShared-"));
QVERIFY(QMetaObject::invokeMethod(
&obj, "slotWithRegistrableArgument", Qt::QueuedConnection,
Q_ARG(QtTestObject *, shared.data()), Q_ARG(QPointer<QtTestObject>, shared.data()),
Q_ARG(QSharedPointer<QtTestObject>, shared), Q_ARG(QWeakPointer<QtTestObject>, shared),
Q_ARG(QVector<QtTestObject *>, QVector<QtTestObject *>()),
Q_ARG(QList<QtTestObject *>, QList<QtTestObject *>())));
QVERIFY(obj.slotResult.isEmpty());
qApp->processEvents(QEventLoop::AllEvents);
QCOMPARE(obj.slotResult,
QString("slotWithRegistrableArgument:myShared-myShared-myShared-myShared-00"));
}
void tst_QMetaObject::normalizedSignature_data()
{
QTest::addColumn<QString>("signature");