From 012dd52fa364ebdb8c177a057ffd3de8d34515c7 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 16 Dec 2024 10:11:57 +0100 Subject: [PATCH] QmlProfiler: Fix crash at startup if file creation fails If opening the temporary file for QmlProfilerEventStorage fails in it's destructor, it was crashing, because the error handler tried to emit a signal on an object that wasn't even half constructed yet. Can be tested by forcing the return value of TraceStashFile::open to `false`. Delay the construction of the event storage a bit and do not set the error handler in its constructor, since nobody could connect to the signal that was sent yet anyway. Also add some checks before calling the error handler. Change-Id: I0fc1207aac447090e12f6b2342e156312e0d1d1b Reviewed-by: hjk --- src/libs/tracing/tracestashfile.h | 3 ++- .../qmlprofiler/qmlprofilermodelmanager.cpp | 25 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/libs/tracing/tracestashfile.h b/src/libs/tracing/tracestashfile.h index ebd3b514180..fac274e2c78 100644 --- a/src/libs/tracing/tracestashfile.h +++ b/src/libs/tracing/tracestashfile.h @@ -130,7 +130,8 @@ public: void clear() { - file.remove(); + if (!file.fileName().isEmpty()) + file.remove(); stream.setDevice(nullptr); } diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index fa0c9f77db1..5e3bb060a6b 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -88,12 +88,9 @@ public: int resolveStackTop(); }; -QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) : - Timeline::TimelineTraceManager( - std::make_unique( - std::bind(&Timeline::TimelineTraceManager::error, this, std::placeholders::_1)), - std::make_unique(), parent), - d(new QmlProfilerModelManagerPrivate) +QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) + : Timeline::TimelineTraceManager({}, std::make_unique(), parent) + , d(new QmlProfilerModelManagerPrivate) { setNotesModel(new QmlProfilerNotesModel(this)); d->textMarkModel = new Internal::QmlProfilerTextMarkModel(this); @@ -103,6 +100,10 @@ QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) : this, &QmlProfilerModelManager::setTypeDetails); connect(d->detailsRewriter, &Internal::QmlProfilerDetailsRewriter::eventDetailsChanged, this, &QmlProfilerModelManager::typeDetailsFinished); + auto storage = new QmlProfilerEventStorage(QmlProfilerEventStorage::ErrorHandler()); + storage->setErrorHandler([this](const QString &message) { emit error(message); }); + std::unique_ptr storagePtr(storage); + swapEventStorage(storagePtr); } QmlProfilerModelManager::~QmlProfilerModelManager() @@ -486,7 +487,7 @@ QmlProfilerEventStorage::QmlProfilerEventStorage( const std::function &errorHandler) : m_file("qmlprofiler-data"), m_errorHandler(errorHandler) { - if (!m_file.open()) + if (!m_file.open() && m_errorHandler) errorHandler(Tr::tr("Cannot open temporary trace file to store events.")); } @@ -506,13 +507,13 @@ void QmlProfilerEventStorage::clear() { m_size = 0; m_file.clear(); - if (!m_file.open()) + if (!m_file.open() && m_errorHandler) m_errorHandler(Tr::tr("Failed to reset temporary trace file.")); } void QmlProfilerEventStorage::finalize() { - if (!m_file.flush()) + if (!m_file.flush() && m_errorHandler) m_errorHandler(Tr::tr("Failed to flush temporary trace file.")); } @@ -534,13 +535,15 @@ bool QmlProfilerEventStorage::replay( case Timeline::TraceStashFile::ReplaySuccess: return true; case Timeline::TraceStashFile::ReplayOpenFailed: - m_errorHandler(Tr::tr("Could not re-open temporary trace file.")); + if (m_errorHandler) + m_errorHandler(Tr::tr("Could not re-open temporary trace file.")); break; case Timeline::TraceStashFile::ReplayLoadFailed: // Happens if the loader rejects an event. Not an actual error break; case Timeline::TraceStashFile::ReplayReadPastEnd: - m_errorHandler(Tr::tr("Read past end in temporary trace file.")); + if (m_errorHandler) + m_errorHandler(Tr::tr("Read past end in temporary trace file.")); break; } return false;