From 5a53d2eb88339f0e855c3be3b74900c1a5e78a25 Mon Sep 17 00:00:00 2001 From: Walter Almada <39980099+walterioo@users.noreply.github.com> Date: Mon, 13 Jul 2026 01:54:42 -0500 Subject: [PATCH] Fix use-after-free crash on exit during GLCanvas3D teardown (#14588) Plater's pImpl (unique_ptr p) is destroyed before the wxWindow base destructor runs DestroyChildren(), so child GLCanvas3D windows are torn down after p is gone. GLCanvas3D::~GLCanvas3D() -> reset_volumes() then dereferences the freed p through two paths: - Selection::clear() -> plater()->canvas3D() -> p->get_current_canvas3D() - _set_warning_notification() -> plater()->get_notification_manager() Guard both with the existing wxGetApp().is_closing() flag; both are UI-only side effects that are no-ops during shutdown, so normal-use behavior is unchanged. Co-authored-by: Claude Opus 4.8 (1M context) --- src/slic3r/GUI/GLCanvas3D.cpp | 3 +++ src/slic3r/GUI/Selection.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5b8943d998..55e266ca78 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -10289,6 +10289,9 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning) void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) { + // Skip on shutdown: Plater's pImpl is already freed, so get_notification_manager() would use-after-free. + if (wxGetApp().is_closing()) + return; using NotificationLevel = NotificationManager::NotificationLevel; enum ErrorType{ PLATER_WARNING, diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index b2caaed55d..5d6a545873 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -760,6 +760,9 @@ void Selection::clear() #endif // #et_FIXME fake KillFocus from sidebar + // Skip on shutdown: Plater's pImpl is already freed, so plater()->canvas3D() would use-after-free. + if (wxGetApp().is_closing()) + return; wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false); }