From 4e5ea43f3096cef2522eb395ae1a96853142b55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Jen=C3=9Fen?= Date: Wed, 4 Jun 2025 16:16:04 +0200 Subject: [PATCH] QmlDesigner: destroy BaseTextEditor before DesignDocument Stale TextEditor::BaseTextEditor instances could still receive paint events after their DesignDocument had already been deleted. This led to a use-after-free in TextEditorWidgetPrivate::updateLineAnnotation() and sporadic heap corruption on shutdown. shutdown problem at https://the-qt-company-00.sentry.io/issues/6409328760 paint problem at https://the-qt-company-00.sentry.io/issues/6648131182 Change-Id: I5cc9762257d92cd1f6d9cf790ef77b3f1c2b0844 Reviewed-by: Tim Jenssen --- .../components/texteditor/texteditorview.cpp | 10 +++++++++- .../qmldesigner/components/texteditor/texteditorview.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp index 35c702af534..b3231baf02d 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp @@ -63,8 +63,9 @@ void TextEditorView::modelAttached(Model *model) AbstractView::modelAttached(model); + DesignDocument *designDocument = QmlDesignerPlugin::instance()->currentDesignDocument(); auto textEditor = Utils::UniqueObjectLatePtr( - QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor()->duplicate()); + designDocument->textEditor()->duplicate()); static constexpr char qmlTextEditorContextId[] = "QmlDesigner::TextEditor"; IContext::attach(textEditor->widget(), Context(qmlTextEditorContextId, Constants::qtQuickToolsMenuContextId), @@ -72,6 +73,12 @@ void TextEditorView::modelAttached(Model *model) m_widget->contextHelp(callback); }); m_widget->setTextEditor(std::move(textEditor)); + + disconnect(m_designDocumentConnection); + m_designDocumentConnection = connect(designDocument, + &DesignDocument::designDocumentClosed, + m_widget, + [this] { m_widget->setTextEditor(nullptr); }); } void TextEditorView::modelAboutToBeDetached(Model *model) @@ -80,6 +87,7 @@ void TextEditorView::modelAboutToBeDetached(Model *model) if (m_widget) m_widget->setTextEditor(nullptr); + disconnect(m_designDocumentConnection); } void TextEditorView::importsChanged(const Imports &/*addedImports*/, const Imports &/*removedImports*/) diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.h b/src/plugins/qmldesigner/components/texteditor/texteditorview.h index b8c624984b1..75355604b2a 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorview.h +++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.h @@ -78,6 +78,7 @@ public: private: QPointer m_widget; + QMetaObject::Connection m_designDocumentConnection; bool m_errorState = false; };