From f22dba503cce9324daec57fd511131bd531eb583 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Tue, 3 Feb 2026 14:46:24 -0800 Subject: [PATCH] Defer template list refresh after duplication to prevent use-after-free Duplicating a template copies files that trigger OnFileSystemEvent, which starts a 500ms refresh timer. The subsequent DisplayInfoMessage runs a modal event loop during which the timer fires, calling RefreshTemplateList which destroys all TEMPLATE_WIDGETs including the one whose onDuplicateTemplate is still on the call stack. When the modal dialog closes, any further member access is undefined behavior. Defer both the info message and the refresh via CallAfter so they execute after the event handler has returned and the call stack is clean. Fixes https://gitlab.com/kicad/code/kicad/-/issues/22931 --- kicad/dialogs/dialog_template_selector.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/kicad/dialogs/dialog_template_selector.cpp b/kicad/dialogs/dialog_template_selector.cpp index d90c81e344..03417ca491 100644 --- a/kicad/dialogs/dialog_template_selector.cpp +++ b/kicad/dialogs/dialog_template_selector.cpp @@ -480,10 +480,20 @@ void TEMPLATE_WIDGET::onDuplicateTemplate( wxCommandEvent& event ) } } - DisplayInfoMessage( m_dialog, wxString::Format( _( "Template duplicated successfully to '%s'." ), - newTemplatePath ) ); + // The file copy triggers OnFileSystemEvent which starts a refresh timer. If we show a + // modal info dialog here, the timer fires during the modal event loop and destroys this + // TEMPLATE_WIDGET while we're still on its call stack. Defer both the message and the + // refresh to run after the current event handler returns. + DIALOG_TEMPLATE_SELECTOR* dlg = m_dialog; - m_dialog->RefreshTemplateList(); + dlg->CallAfter( + [dlg, newTemplatePath]() + { + DisplayInfoMessage( dlg, wxString::Format( _( "Template duplicated successfully" + " to '%s'." ), + newTemplatePath ) ); + dlg->RefreshTemplateList(); + } ); }