diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2019-06-29 11:01:06 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-07-03 11:52:42 +0000 |
commit | 96a3c80609b976a673585d0745c30a527e3bd913 (patch) | |
tree | 7211e1f7e92dbed42dd51d1290a52157e77a949f /src/plugins/qmlprofiler | |
parent | bf0d84074fe4c836e2815c2a783a4f9f2d9a98ec (diff) |
QmlProfiler: deleteLater() the debug message and engine control clients
Nesting the dtors of the different clients is dangerous as the
connection might call back into a virtual function of a half-destructed
object this way.
Fixes: QTCREATORBUG-22640
Change-Id: I91fccc41fbea40a7f78ef344759abe26d140434d
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/qmlprofiler')
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilertraceclient.cpp | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp index 79183a77b1..a8f82e72fc 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp @@ -55,6 +55,8 @@ inline bool operator!=(const QmlEventType &type1, const QmlEventType &type2) return !(type1 == type2); } +struct ObjectDeleteLater { void operator()(QObject *o) { o->deleteLater(); } }; + class QmlProfilerTraceClientPrivate { public: QmlProfilerTraceClientPrivate(QmlProfilerTraceClient *q, @@ -62,7 +64,7 @@ public: QmlProfilerModelManager *modelManager) : q(q) , modelManager(modelManager) - , engineControl(connection) + , engineControl(new QmlDebug::QmlEngineControlClient(connection)) , maximumTime(0) , recording(false) , requestedFeatures(0) @@ -81,8 +83,14 @@ public: QmlProfilerTraceClient *q; QmlProfilerModelManager *modelManager; - QmlDebug::QmlEngineControlClient engineControl; - QScopedPointer<QmlDebug::QDebugMessageClient> messageClient; + + // Use deleteLater here. The connection will call stateChanged() on all clients that are + // alive when it gets disconnected. One way to notice a disconnection is failing to send the + // plugin advertisement when a client unregisters. If one of the other clients is + // half-destructed at that point, we get invalid memory accesses. Therefore, we cannot nest the + // dtor calls. + std::unique_ptr<QmlDebug::QmlEngineControlClient, ObjectDeleteLater> engineControl; + std::unique_ptr<QmlDebug::QDebugMessageClient, ObjectDeleteLater> messageClient; qint64 maximumTime; bool recording; quint64 requestedFeatures; @@ -235,22 +243,22 @@ QmlProfilerTraceClient::QmlProfilerTraceClient(QmlDebug::QmlDebugConnection *cli , d(new QmlProfilerTraceClientPrivate(this, client, modelManager)) { setRequestedFeatures(features); - connect(&d->engineControl, &QmlDebug::QmlEngineControlClient::engineAboutToBeAdded, + connect(d->engineControl.get(), &QmlDebug::QmlEngineControlClient::engineAboutToBeAdded, this, &QmlProfilerTraceClient::sendRecordingStatus); - connect(&d->engineControl, &QmlDebug::QmlEngineControlClient::engineAboutToBeRemoved, + connect(d->engineControl.get(), &QmlDebug::QmlEngineControlClient::engineAboutToBeRemoved, this, [this](int engineId) { // We may already be done with that engine. Then we don't need to block it. if (d->trackedEngines.contains(engineId)) - d->engineControl.blockEngine(engineId); + d->engineControl->blockEngine(engineId); }); connect(this, &QmlProfilerTraceClient::traceFinished, - &d->engineControl, [this](qint64 timestamp, const QList<int> &engineIds) { + d->engineControl.get(), [this](qint64 timestamp, const QList<int> &engineIds) { Q_UNUSED(timestamp); // The engines might not be blocked because the trace can get finished before engine control // sees them. - for (int blocked : d->engineControl.blockedEngines()) { + for (int blocked : d->engineControl->blockedEngines()) { if (engineIds.contains(blocked)) - d->engineControl.releaseEngine(blocked); + d->engineControl->releaseEngine(blocked); } }); } @@ -317,7 +325,7 @@ void QmlProfilerTraceClient::setRequestedFeatures(quint64 features) d->requestedFeatures = features; if (features & static_cast<quint64>(1) << ProfileDebugMessages) { d->messageClient.reset(new QmlDebug::QDebugMessageClient(connection())); - connect(d->messageClient.data(), &QmlDebug::QDebugMessageClient::message, this, + connect(d->messageClient.get(), &QmlDebug::QDebugMessageClient::message, this, [this](QtMsgType type, const QString &text, const QmlDebug::QDebugContextInfo &context) { |