From ee817c7bd881e188b4a5b92b6ace171da8481659 Mon Sep 17 00:00:00 2001 From: Tine Zivic Date: Mon, 20 Apr 2026 02:22:04 +0200 Subject: [PATCH 1/2] FIX: Guard m_side_window against null/stale pointer in ObjectGridTable Crash reproducible on Linux Flatpak (GNOME Platform 48) when clicking 'View all object settings'. Reported in issues #9423, #10015, #10178. Root cause: ObjectGridTable::OnSelectCell(), OnCellValueChanged(), and OnCellLeftClick() all call m_panel->m_side_window->Freeze() without verifying that m_side_window is still valid. On Flatpak with GNOME Platform 48, the newer wxWidgets ABI triggers an invalid read at address 0x1cc (Freeze() dereferencing a stale vtable pointer), causing a SIGSEGV. Valgrind output from issue #9423: Invalid read of size 4 in wxWindowBase::Freeze() called from ObjectGridTable::OnSelectCell() Changes: 1. OnSelectCell(): early return if m_side_window is null 2. OnCellLeftClick(): wrap Freeze/ValueChanged/Thaw in null check 3. OnCellValueChanged(): wrap Freeze/ValueChanged/Thaw in null check 4. ~ObjectTablePanel(): set m_side_window = nullptr after Clear(true) so that any pending wxGrid events fired during teardown hit the guard rather than a freed pointer Note: this addresses the symptom (crash) safely. The root cause is an ABI mismatch between the wxWidgets version bundled in the AppImage and the one provided by org.gnome.Platform/48 in the Flatpak runtime. Co-authored-by: GitHub Copilot AI-generated: This fix was developed with the assistance of GitHub Copilot (Claude Sonnet 4.6). The logic and diagnosis were reviewed and validated by the contributor. --- src/slic3r/GUI/GUI_ObjectTable.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectTable.cpp b/src/slic3r/GUI/GUI_ObjectTable.cpp index 24d3b1806c..983f49d6dd 100644 --- a/src/slic3r/GUI/GUI_ObjectTable.cpp +++ b/src/slic3r/GUI/GUI_ObjectTable.cpp @@ -2554,9 +2554,11 @@ bool ObjectGridTable::OnCellLeftClick(int row, int col, ConfigOptionType &type) //update the right side setting list bool is_object = (grid_row->row_type == row_object); ModelObject* object = m_panel->m_model->objects[grid_row->object_id]; - m_panel->m_side_window->Freeze(); - m_panel->m_object_settings->ValueChanged(row, is_object, object, grid_row->config, grid_col_2->category, grid_col_2->key); - m_panel->m_side_window->Thaw(); + if (m_panel->m_side_window) { + m_panel->m_side_window->Freeze(); + m_panel->m_object_settings->ValueChanged(row, is_object, object, grid_row->config, grid_col_2->category, grid_col_2->key); + m_panel->m_side_window->Thaw(); + } //m_panel->m_plater->update(); } else { @@ -2575,6 +2577,8 @@ bool ObjectGridTable::OnCellLeftClick(int row, int col, ConfigOptionType &type) void ObjectGridTable::OnSelectCell(int row, int col) { m_selected_cells.clear(); + if (!m_panel->m_side_window) + return; m_panel->m_side_window->Freeze(); if (row == 0 || col == col_filaments) { m_panel->m_object_settings->UpdateAndShow(row, false, false, false, nullptr, nullptr, std::string()); @@ -2651,11 +2655,11 @@ void ObjectGridTable::OnCellValueChanged(int row, int col) bool is_object = (grid_row->row_type == row_object); ModelObject* object = m_panel->m_model->objects[grid_row->object_id]; - m_panel->m_side_window->Freeze(); - - m_panel->m_object_settings->ValueChanged(row, is_object, object, grid_row->config, grid_col->category, grid_col->key); - - m_panel->m_side_window->Thaw(); + if (m_panel->m_side_window) { + m_panel->m_side_window->Freeze(); + m_panel->m_object_settings->ValueChanged(row, is_object, object, grid_row->config, grid_col->category, grid_col->key); + m_panel->m_side_window->Thaw(); + } //update volume cell /*if (is_object) { int next_row = row + 1; @@ -3173,6 +3177,7 @@ ObjectTablePanel::~ObjectTablePanel() }*/ if (m_top_sizer) m_top_sizer->Clear(true); + m_side_window = nullptr; // prevent use-after-free in pending events delete m_object_settings; m_filaments_name.clear(); From 821ec5f0484fd7b9fab3221450f149a3e7556a5e Mon Sep 17 00:00:00 2001 From: Tine Zivic Date: Sun, 26 Apr 2026 07:50:53 +0200 Subject: [PATCH 2/2] FIX: null m_side_window before Clear(true) in destructor to close race window Previously m_side_window was nulled after m_top_sizer->Clear(true), which deletes the widget. Pending wxGrid events (e.g. EVT_GRID_SELECT_CELL) could fire between the delete and the null assignment, bypassing the null-guards in OnSelectCell/OnCellLeftClick/OnCellValueChanged and causing use-after-free. Move the null assignment before Clear(true) so any pending event hits the guard before the widget is destroyed. --- src/slic3r/GUI/GUI_ObjectTable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectTable.cpp b/src/slic3r/GUI/GUI_ObjectTable.cpp index 983f49d6dd..18a0dd7eca 100644 --- a/src/slic3r/GUI/GUI_ObjectTable.cpp +++ b/src/slic3r/GUI/GUI_ObjectTable.cpp @@ -3175,9 +3175,9 @@ ObjectTablePanel::~ObjectTablePanel() delete m_object_grid_table; m_object_grid_table = nullptr; }*/ + m_side_window = nullptr; // null before Clear(true) — pending events hit the guard safely if (m_top_sizer) m_top_sizer->Clear(true); - m_side_window = nullptr; // prevent use-after-free in pending events delete m_object_settings; m_filaments_name.clear();