From 924b87447f4703fa66b65cb3277febf3f1d862bb Mon Sep 17 00:00:00 2001 From: ispyisail Date: Fri, 2 Oct 2026 16:15:51 +1300 Subject: [PATCH] Fix a use-after-free when closing QElectroTech without saving Closing QElectroTech with an edited project and choosing "Close without saving" read freed memory. Destroying the project clears each folio's undo stack, which signals the Projects panel to refresh that project. The refresh reached GenericPanel::updateItem(), whose only statement was QApplication::processEvents(). That ran the editor window's pending deleteLater(), destroying the panel, and GenericPanel::addProject() then carried on using it (genericpanel.cpp:142). The call was added in 2013 (70b7cd7d1) to keep the window responsive while the panel reloaded, when it also listed the whole element collection. The collection has its own panel now; this one lists projects, folios and title block templates. updateItem() is again what its comment says it is: a hook that does nothing. Found by the GUI fuzzer under AddressSanitizer. Reproduced 3/3 on master 51b122993 (open a project, move everything on a folio, Ctrl+Q, Close without Saving: heap-use-after-free, exit 1); 0/3 with this change (exit 0, no report), with the save prompt confirmed on screen. Co-Authored-By: Claude Opus 5.5 (1M context) --- sources/genericpanel.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sources/genericpanel.cpp b/sources/genericpanel.cpp index dd4874d49..c5261df90 100644 --- a/sources/genericpanel.cpp +++ b/sources/genericpanel.cpp @@ -696,7 +696,13 @@ QTreeWidgetItem *GenericPanel::updateItem(QTreeWidgetItem *qtwi, bool freshly_created) { Q_UNUSED(options); Q_UNUSED(freshly_created); - QApplication::processEvents(); + //No QApplication::processEvents() here. It dates from when this + //panel also listed the whole element collection, to keep the + //window alive while that reloaded; the collection has its own + //panel now. Running the event loop from inside the panel's own + //methods let a pending deleteLater() destroy the panel while + //addProject() was still using it: closing QElectroTech without + //saving an edited project read freed memory. return(qtwi); }