From bf69eb9467b273357b15b8527bb0189d9841792f Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 20 Feb 2017 19:19:50 +0100 Subject: [PATCH] QmlProfiler: Guard against the temporary trace file going away If we cannot open a temporary file to cache a trace or retrieve a previously cached trace, the QML profiler won't work correctly. Show an error in this case. Change-Id: I468d74d9c33033b9ad19501bccbd69a9fe164fed Reviewed-by: Christian Kandeler --- .../qmlprofiler/qmlprofilerdatamodel.cpp | 20 ++++++++++++------ .../qmlprofiler/qmlprofilerdatamodel.h | 3 ++- .../qmlprofiler/qmlprofilermodelmanager.cpp | 21 +++++++++++++------ .../qmlprofilerstatisticsmodel.cpp | 18 +++++++++------- .../qmlprofiler/qmlprofilertracefile.cpp | 18 ++++++++++++---- 5 files changed, 56 insertions(+), 24 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp index dd3d78266d2..b8caf65ab71 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp @@ -101,8 +101,10 @@ QmlProfilerDataModel::QmlProfilerDataModel(QObject *parent) : this, &QmlProfilerDataModel::detailsChanged); connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged, this, &QmlProfilerDataModel::allTypesLoaded); - d->file.open(); - d->eventStream.setDevice(&d->file); + if (!d->file.open()) + emit traceFileError(); + else + d->eventStream.setDevice(&d->file); } QmlProfilerDataModel::~QmlProfilerDataModel() @@ -170,8 +172,11 @@ void QmlProfilerDataModel::clear() { Q_D(QmlProfilerDataModel); d->file.remove(); - d->file.open(); - d->eventStream.setDevice(&d->file); + d->eventStream.unsetDevice(); + if (!d->file.open()) + emit traceFileError(); + else + d->eventStream.setDevice(&d->file); d->eventTypes.clear(); d->detailsRewriter->clearRequests(); } @@ -207,14 +212,16 @@ static bool isStateful(const QmlEventType &type) return message == PixmapCacheEvent || message == MemoryAllocation; } -void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, +bool QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, QmlProfilerModelManager::EventLoader loader) const { Q_D(const QmlProfilerDataModel); QStack stack; QmlEvent event; QFile file(d->file.fileName()); - file.open(QIODevice::ReadOnly); + if (!file.open(QIODevice::ReadOnly)) + return false; + QDataStream stream(&file); bool crossedRangeStart = false; while (!stream.atEnd()) { @@ -271,6 +278,7 @@ void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, loader(event, type); } + return true; } void QmlProfilerDataModel::finalize() diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h b/src/plugins/qmlprofiler/qmlprofilerdatamodel.h index fb60a881158..66ba9f6e887 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h +++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.h @@ -55,12 +55,13 @@ public: bool isEmpty() const; void addEvent(const QmlEvent &event); void addEvents(const QVector &events); - void replayEvents(qint64 startTime, qint64 endTime, + bool replayEvents(qint64 startTime, qint64 endTime, QmlProfilerModelManager::EventLoader loader) const; void finalize(); signals: void allTypesLoaded(); + void traceFileError(); protected slots: void detailsChanged(int typeId, const QString &newString); diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index f59c1c9a75d..887dfe5254a 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -176,6 +176,10 @@ QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) : d->textMarkModel = new QmlProfilerTextMarkModel(this); connect(d->model, &QmlProfilerDataModel::allTypesLoaded, this, &QmlProfilerModelManager::processingDone); + connect(d->model, &QmlProfilerDataModel::traceFileError, + this, [this]() { + emit error(tr("Could not open a temporary file for storing QML traces.")); + }); } QmlProfilerModelManager::~QmlProfilerModelManager() @@ -543,12 +547,17 @@ void QmlProfilerModelManager::restrictToRange(qint64 startTime, qint64 endTime) setVisibleFeatures(0); startAcquiring(); - d->model->replayEvents(startTime, endTime, - std::bind(&QmlProfilerModelManagerPrivate::dispatch, d, - std::placeholders::_1, std::placeholders::_2)); - d->notesModel->setNotes(notes); - d->traceTime->restrictToRange(startTime, endTime); - acquiringDone(); + if (!d->model->replayEvents(startTime, endTime, + std::bind(&QmlProfilerModelManagerPrivate::dispatch, d, + std::placeholders::_1, std::placeholders::_2))) { + emit error(tr("Could not re-read events from temporary trace file. " + "The trace data is lost.")); + clear(); + } else { + d->notesModel->setNotes(notes); + d->traceTime->restrictToRange(startTime, endTime); + acquiringDone(); + } } bool QmlProfilerModelManager::isRestrictedToRange() const diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp index 26ecc29401e..b1917134300 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp @@ -120,13 +120,17 @@ void QmlProfilerStatisticsModel::restrictToFeatures(qint64 features) return; clear(); - d->modelManager->qmlModel()->replayEvents(d->modelManager->traceTime()->startTime(), - d->modelManager->traceTime()->endTime(), - std::bind(&QmlProfilerStatisticsModel::loadEvent, - this, std::placeholders::_1, - std::placeholders::_2)); - finalize(); - notesChanged(-1); // Reload notes + if (!d->modelManager->qmlModel()->replayEvents(d->modelManager->traceTime()->startTime(), + d->modelManager->traceTime()->endTime(), + std::bind(&QmlProfilerStatisticsModel::loadEvent, + this, std::placeholders::_1, + std::placeholders::_2))) { + emit d->modelManager->error(tr("Could not re-read events from temporary trace file.")); + clear(); + } else { + finalize(); + notesChanged(-1); // Reload notes + } } const QHash &QmlProfilerStatisticsModel::getData() const diff --git a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp index 0551d0310ee..f2fc6a8a931 100644 --- a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp @@ -668,8 +668,9 @@ void QmlProfilerFileWriter::saveQtd(QIODevice *device) stream.writeStartElement(_("profilerDataModel")); QStack stack; - m_model->replayEvents(-1, -1, [this, &stack, &stream](const QmlEvent &event, - const QmlEventType &type) { + const bool success = m_model->replayEvents( + -1, -1, [this, &stack, &stream](const QmlEvent &event, + const QmlEventType &type) { if (isCanceled()) return; @@ -741,6 +742,10 @@ void QmlProfilerFileWriter::saveQtd(QIODevice *device) if ((event.timestamp() & 0xfff) == 0) updateProgress(event.timestamp()); }); + if (!success) { + emit error(tr("Could not re-read events from temporary trace file. Saving failed.")); + return; + } stream.writeEndElement(); // profilerDataModel } @@ -807,8 +812,9 @@ void QmlProfilerFileWriter::saveQzt(QFile *file) if (!isCanceled()) { buffer.open(QIODevice::WriteOnly); - m_model->replayEvents(-1, -1, [this, &stream, &buffer, &bufferStream]( - const QmlEvent &event, const QmlEventType &type) { + const bool success = m_model->replayEvents( + -1, -1, [this, &stream, &buffer, &bufferStream](const QmlEvent &event, + const QmlEventType &type) { Q_UNUSED(type); bufferStream << event; // 32MB buffer should be plenty for efficient compression @@ -822,6 +828,10 @@ void QmlProfilerFileWriter::saveQzt(QFile *file) updateProgress(event.timestamp()); } }); + if (!success) { + emit error(tr("Could not re-read events from temporary trace file. Saving failed.")); + return; + } } if (isCanceled()) {