From fbb59ee1e799bd59f9d09f85180f9521b5ece1f5 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Wed, 30 Sep 2026 09:22:05 +1300 Subject: [PATCH] Fix a crash when closing a project after its terminal strip window is gone The terminal strip window's tree dock connects to its project's destroyed() signal with a lambda capturing `this`, but without `this` as the connection's context, and never disconnects it. When the dock is deleted before the project, closing the project runs the lambda on freed memory. The terminal strip window is a single instance, parented to the editor window it was first opened from. With two editor windows: 1. open the terminal strip manager from window 1 (project A); 2. open it from window 2 (project B): the same window switches to B, still a child of window 1; 3. close window 1: the terminal strip window and its dock are deleted, the connection to B stays; 4. close window 2, or project B: heap-use-after-free in the lambda (terminalstriptreedockwidget.cpp:66), reported by AddressSanitizer 3 times out of 3. Freed by ~TerminalStripEditorWindow from ~QETDiagramEditor. Passing `this` as the context removes the connection with the dock, as FreeTerminalEditor, FreeTerminalModel and TerminalStripEditor already do for the same signal. With the fix: no error, 3 times out of 3. Co-Authored-By: Claude Opus 5.5 (1M context) --- sources/TerminalStrip/ui/terminalstriptreedockwidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sources/TerminalStrip/ui/terminalstriptreedockwidget.cpp b/sources/TerminalStrip/ui/terminalstriptreedockwidget.cpp index b2e2aa1db..fd81bd61e 100644 --- a/sources/TerminalStrip/ui/terminalstriptreedockwidget.cpp +++ b/sources/TerminalStrip/ui/terminalstriptreedockwidget.cpp @@ -62,7 +62,9 @@ void TerminalStripTreeDockWidget::setProject(QETProject *project) } m_project = project; if (m_project) { - m_project_destroy_connection = connect(m_project, &QObject::destroyed, [this](){ + //`this` as context: this dock can be deleted before the project + //(with the editor window that owns it), and the connection must go with it + m_project_destroy_connection = connect(m_project, &QObject::destroyed, this, [this](){ this->m_current_strip.clear(); this->reload(); });