From 9660c8043067bbfd066d0e29a93297023468990d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 29 Aug 2022 18:39:09 +0200 Subject: [PATCH] Fix crash when using a wxRadioBox without items in wxOSX wxRadioBox::m_radioButtonCycle is never null -- except when it is, when there are no items at all in the radio box. Handle this case without crashing too by checking for the pointer being valid before using it. Also add a unit test checking that this works correctly. See #22751. (cherry picked from commit b0c417db36b7daca3b9b6731588f5b7b3f19ca6a) --- docs/changes.txt | 1 + src/osx/radiobox_osx.cpp | 14 ++++++++++---- tests/controls/radioboxtest.cpp | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 2e3abd9c7e..e0828a691f 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -266,6 +266,7 @@ wxOSX: - Fix wxBitmapBundle compatibility when using template NSImages (#22623). - Fix bezel style of borderless wxToggleButton (#22140). - Improve wxWebView full screen support (Tobias Taschner, #22637). +- Fix crash when creating wxRadioBox without any items (#22751). 3.2.0: (released 2022-07-07) diff --git a/src/osx/radiobox_osx.cpp b/src/osx/radiobox_osx.cpp index 2a7b33c827..626b0f5fec 100644 --- a/src/osx/radiobox_osx.cpp +++ b/src/osx/radiobox_osx.cpp @@ -59,18 +59,21 @@ wxRadioBox::~wxRadioBox() wxRadioButton *next, *current; - current = m_radioButtonCycle->NextInCycle(); + current = m_radioButtonCycle; if (current != NULL) { - while (current != m_radioButtonCycle) + // We need to start deleting the buttons from the second one because + // deleting the first one would change the pointers stored in them. + for (current = current->NextInCycle();;) { next = current->NextInCycle(); delete current; + if (next == m_radioButtonCycle) + break; + current = next; } - - delete current; } } @@ -339,6 +342,9 @@ void wxRadioBox::Command( wxCommandEvent& event ) // void wxRadioBox::SetFocus() { + if (!m_radioButtonCycle) + return; + wxRadioButton *current; current = m_radioButtonCycle; diff --git a/tests/controls/radioboxtest.cpp b/tests/controls/radioboxtest.cpp index 5ecefb64eb..a845408a91 100644 --- a/tests/controls/radioboxtest.cpp +++ b/tests/controls/radioboxtest.cpp @@ -16,6 +16,7 @@ #include "wx/radiobox.h" #endif // WX_PRECOMP +#include "wx/scopedptr.h" #include "wx/tooltip.h" class RadioBoxTestCase : public CppUnit::TestCase @@ -223,4 +224,18 @@ void RadioBoxTestCase::SetString() CPPUNIT_ASSERT_EQUAL("", m_radio->GetString(2)); } +TEST_CASE("RadioBox::NoItems", "[radiobox]") +{ + wxScopedPtr + radio(new wxRadioBox(wxTheApp->GetTopWindow(), wxID_ANY, "Empty", + wxDefaultPosition, wxDefaultSize, + 0, NULL, + 1, wxRA_SPECIFY_COLS)); + + CHECK( radio->GetCount() == 0 ); + CHECK( radio->IsEmpty() ); + + CHECK_NOTHROW( radio->SetFocus() ); +} + #endif // wxUSE_RADIOBOX