From 2be5f429c19cbcc945993112ea484cc579aa0e99 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 6 Mar 2023 19:22:11 +0000 Subject: [PATCH] Don't create wrong wxAppTraits during wxApp construction Creating wxAppTraits before the object of the user-defined class deriving from wxApp is fully constructed may result in creating a wrong traits object if the user class overrides CreateTraits() because the correct, i.e. user-defined, version isn't used if it's called from wx code. This had already happened before and was worked around back in bc334f39ec (Fixes Bug [ 930200 ] Async does not work, 2004-04-27), but recently happened again after the changes of 94e4818caa (Warn on startup when not using comctl32.dll v6 in wxMSW, 2022-11-28). To prevent it from happening in the future, add WXAppConstructed() that must be called after fully constructing wxApp (and forgetting to do it would result in an assert, so doesn't risk to go unnoticed) and which resets m_traits if it has been wrongly created. It would, perhaps, be even better if we avoided creating the wrong traits in the first place, but for now this at least fixes the latest problem and ensures it doesn't reoccur. Closes #23315. --- include/wx/app.h | 16 ++++++++++++++-- src/common/appbase.cpp | 25 +++++++++++++++++++++---- src/dfb/app.cpp | 1 + src/gtk/app.cpp | 2 ++ src/msw/app.cpp | 2 ++ src/osx/carbon/app.cpp | 2 ++ src/qt/app.cpp | 2 ++ src/unix/appunix.cpp | 2 ++ src/x11/app.cpp | 2 ++ 9 files changed, 48 insertions(+), 6 deletions(-) diff --git a/include/wx/app.h b/include/wx/app.h index acb7acea85..5d8b03c5bd 100644 --- a/include/wx/app.h +++ b/include/wx/app.h @@ -476,6 +476,10 @@ public: wxCmdLineArgsArray argv; protected: + // This function must be called at the end of wxApp ctor to indicate that + // wx part of the object is fully constructed. + void WXAppConstructed(); + // delete all objects in wxPendingDelete list // // called from ProcessPendingEvents() @@ -531,6 +535,11 @@ protected: // flag modified by Suspend/ResumeProcessingOfPendingEvents() bool m_bDoPendingEventProcessing = true; +private: + // flag set to true at the end of wxApp ctor, call WXAppConstructed() to + // set it + bool m_fullyConstructed = false; + friend class WXDLLIMPEXP_FWD_BASE wxEvtHandler; // the application object is a singleton anyhow, there is no sense in @@ -541,8 +550,11 @@ protected: #if defined(__UNIX__) && !defined(__WINDOWS__) #include "wx/unix/app.h" #else - // this has to be a class and not a typedef as we forward declare it - class wxAppConsole : public wxAppConsoleBase { }; + class wxAppConsole : public wxAppConsoleBase + { + public: + wxAppConsole() { WXAppConstructed(); } + }; #endif // ---------------------------------------------------------------------------- diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index 85c8a0cd94..d2bffd0bd7 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -138,10 +138,6 @@ wxAppConsoleBase::wxAppConsoleBase() #ifdef __WXDEBUG__ SetTraceMasks(); - // SetTraceMasks call can cause an apptraits to be - // created, but since we are still in the constructor the wrong kind will - // be created for GUI apps. Destroy it so it can be created again later. - wxDELETE(m_traits); #endif wxEvtHandler::AddFilter(this); @@ -162,8 +158,29 @@ wxAppConsoleBase::~wxAppConsoleBase() // initialization/cleanup // ---------------------------------------------------------------------------- +void wxAppConsoleBase::WXAppConstructed() +{ + // Note that we can (and will) be called multiple times for the GUI apps as + // wxAppConsole ctor has to call this function itself too in case it's + // actually a console app, so don't assert that it's currently false. + m_fullyConstructed = true; + + // We're called at the end of wxApp ctor execution, i.e. before the + // user-defined wxApp-derived class was fully constructed, so its possibly + // overridden CreateTraits() couldn't have been called yet, which means + // that if we have already initialized our m_traits, we did it wrongly, and + // need to reset it. + if ( m_traits ) + { + delete m_traits; + m_traits = nullptr; + } +} + bool wxAppConsoleBase::Initialize(int& WXUNUSED(argc), wxChar **WXUNUSED(argv)) { + wxASSERT_MSG( m_fullyConstructed, "Forgot to call WXAppConstructed()?" ); + #if defined(__WINDOWS__) SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); #endif diff --git a/src/dfb/app.cpp b/src/dfb/app.cpp index 41dc5f295f..2ed336ba9c 100644 --- a/src/dfb/app.cpp +++ b/src/dfb/app.cpp @@ -26,6 +26,7 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler); wxApp::wxApp() { + WXAppConstructed(); } wxApp::~wxApp() diff --git a/src/gtk/app.cpp b/src/gtk/app.cpp index ea2d9c4a14..1d19fbce0e 100644 --- a/src/gtk/app.cpp +++ b/src/gtk/app.cpp @@ -308,6 +308,8 @@ wxApp::wxApp() { m_isInAssert = false; m_idleSourceId = 0; + + WXAppConstructed(); } wxApp::~wxApp() diff --git a/src/msw/app.cpp b/src/msw/app.cpp index 3816b9d7da..245af3e53c 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -817,6 +817,8 @@ if you believe not using the manifest should remain supported. ); } } + + WXAppConstructed(); } wxApp::~wxApp() diff --git a/src/osx/carbon/app.cpp b/src/osx/carbon/app.cpp index 4bd645ea05..54a74b4f5d 100644 --- a/src/osx/carbon/app.cpp +++ b/src/osx/carbon/app.cpp @@ -379,6 +379,8 @@ wxApp::wxApp() m_macCurrentEvent = nullptr ; m_macCurrentEventHandlerCallRef = nullptr ; m_macPool = sm_isEmbedded ? nullptr : new wxMacAutoreleasePool(); + + WXAppConstructed(); } wxApp::~wxApp() diff --git a/src/qt/app.cpp b/src/qt/app.cpp index 57552ca807..dcb7b9e7a9 100644 --- a/src/qt/app.cpp +++ b/src/qt/app.cpp @@ -20,6 +20,8 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler); wxApp::wxApp() { m_qtArgc = 0; + + WXAppConstructed(); } diff --git a/src/unix/appunix.cpp b/src/unix/appunix.cpp index a9fb317c6a..982abfe630 100644 --- a/src/unix/appunix.cpp +++ b/src/unix/appunix.cpp @@ -74,6 +74,8 @@ private: wxAppConsole::wxAppConsole() { m_signalWakeUpPipe = nullptr; + + WXAppConstructed(); } wxAppConsole::~wxAppConsole() diff --git a/src/x11/app.cpp b/src/x11/app.cpp index 340361c4ec..4db2cdc53a 100644 --- a/src/x11/app.cpp +++ b/src/x11/app.cpp @@ -217,6 +217,8 @@ wxApp::wxApp() #if !wxUSE_NANOX m_visualInfo = nullptr; #endif + + WXAppConstructed(); } wxApp::~wxApp()