Details
-
Bug
-
Resolution: Done
-
P1: Critical
-
5.8.0
-
None
-
All enviroments
-
d4cdc4542609e61d04802902d73c693faa8d8969
Description
Sorry I do not have the time to produce a small test case.
Use any call to invoke QMetaMethod::invoke with multiple arguments where one of the parameters is an unregistered data type and the following parameter can be registered. E.g. two arguments, first is an enum with Q_ENUM, second is a QSharedPointer<MyObject> where MyObject is derived from QObject.
Another thing to see this clearly as a bug, look at the value of i in the for loop running from 1 to paramCount. Whereas the moc-files produced by moc expect the arguments numbered from 0 to paramCount-1.
Specifically it is the section handling the Registration of the Arguments:
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
Original text:
In QueuedConnections the arguments are stored as pointers to objects create by QMetaType::create.
The for loop below is copied from the Qt Source 5.8.
If a type is known, " if (types[i] != QMetaType::UnknownType) {"
then args[i] is set to the new object.
Yet there is the case that the type is unknown and need to get registered first.
} else if (param[i]) { // Try to register the type and try again before reporting an error.
But in this branch of the if-clause the value of args[i] is never set. So in the case the typed gets registered correctly, the corresponding args[i] is left at an undefined value while types[i] is set. This will cause a segmentation at the latest in QMetaCallEvent destructor which tries to delete args[i].
The bug is in a for loop of qmetaobject.cpp line 2242ff (in the source version of Qt 5.8). As line numbers might have gotten shiften a copy of the for loop below.
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]) { // Try to register the type and try again before reporting an error. void *argv[] = { &types[i], &i }; QMetaObject::metacall(object, QMetaObject::RegisterMethodArgumentMetaType, idx_relative + idx_offset, argv); if (types[i] == -1) { qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'", typeNames[i]); for (int x = 1; x < i; ++x) { if (types[x] && args[x]) QMetaType::destroy(types[x], args[x]); } free(types); free(args); return false; } } }