From 1dd102d741dc9858df2b7e933761ed7cc7a51093 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 17 Jan 2018 10:24:55 +0100 Subject: [PATCH] Fix crash when deleting all wxTreeListCtrl items with wxGTK3 GTK+ 3 (but not the generic version nor even GTK+ 2, apparently) sends "selection changed" event from gtk_tree_model_row_deleted() when deleting the currently selected row, which resulted in sending of wxEVT_TREELIST_SELECTION_CHANGED events with invalid wxTreeListItem, containing a dangling pointer, and a crash in the treelist sample when trying to dump it. Avoid this by clearing the model (and hence generating these events) first and deleting the items only afterwards. Also add a trivial unit test for wxTreeListCtrl::DeleteAllItems(), which doesn't even allow to reproduce this bug, but is still probably better to have than not to. Closes #18045. --- src/generic/treelist.cpp | 8 ++++++-- tests/controls/treelistctrltest.cpp | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/generic/treelist.cpp b/src/generic/treelist.cpp index 6c599100ae..3c6f26d955 100644 --- a/src/generic/treelist.cpp +++ b/src/generic/treelist.cpp @@ -572,12 +572,16 @@ void wxTreeListModel::DeleteItem(Node* item) void wxTreeListModel::DeleteAllItems() { + // Note that this must be called before actually deleting the items as + // clearing GTK+ wxDataViewCtrl results in SELECTION_CHANGED events being + // sent and these events contain pointers to the model items, so they must + // still be valid. + Cleared(); + while ( m_root->GetChild() ) { m_root->DeleteChild(); } - - Cleared(); } const wxString& wxTreeListModel::GetItemText(Node* item, unsigned col) const diff --git a/tests/controls/treelistctrltest.cpp b/tests/controls/treelistctrltest.cpp index d4a3ac96d6..02164ab3a1 100644 --- a/tests/controls/treelistctrltest.cpp +++ b/tests/controls/treelistctrltest.cpp @@ -39,6 +39,7 @@ private: CPPUNIT_TEST( Traversal ); CPPUNIT_TEST( ItemText ); CPPUNIT_TEST( ItemCheck ); + CPPUNIT_TEST( DeleteAll ); CPPUNIT_TEST_SUITE_END(); // Create the control with the given style. @@ -55,6 +56,7 @@ private: void Traversal(); void ItemText(); void ItemCheck(); + void DeleteAll(); // The control itself. @@ -231,4 +233,11 @@ void TreeListCtrlTestCase::ItemCheck() m_treelist->GetCheckedState(m_code) ); } +void TreeListCtrlTestCase::DeleteAll() +{ + m_treelist->DeleteAllItems(); + + CHECK( !m_treelist->GetFirstChild(m_treelist->GetRootItem()).IsOk() ); +} + #endif // wxUSE_TREELISTCTRL