Author Topic: Loop in VarManagement on Linux wx30  (Read 6776 times)

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2809
Loop in VarManagement on Linux wx30
« on: September 06, 2023, 09:40:21 pm »
There's an infinite loop in UserVarManagement.cpp @ line 179 on Linux using wx30.
Code
pecan@LinuxMint:/usr$ /usr/bin/g++ --version
g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Name                   : Code::Blocks
Version                : svn-r13347
SDK Version            : 2.24.0
Scintilla Version      : 3.7.5
Author                 : The Code::Blocks Team
E-mail                 : info@codeblocks.org
Website                : https://www.codeblocks.org
OS                     : Linux 5.4.0-74-generic x86_64
Scaling factor         : 1.000000
Detected scaling factor: 1.000000
Display PPI            : 96x96
Display count          : 1
Display 0              : XY=[0,0]; Size=[1816,1093]; Primary

wxWidgets Library (wxGTK port)
Version 3.0.4 (Unicode: wchar_t, debug level: 1),
Runtime version of toolkit used is 3.24.
Compile-time GTK+ version is 3.24.14.

To recreate on Linux using wx30:
1) Remove the "cb" var definition from global variables.
2) Open a project that contains $(#cb)
3) I get a loop on LinuxMint 20.2, CodeBlocks head 13347 with no contribs loaded.

The backtrace doesn't appear to show what's actually happening. Essentially the d.ShowModal() is not holding/waiting for a reply. Dialogs are getting stack on one another infinitely.
I can't figure out what's happening.
The moment I try to step into the ShowModal() call, the debugger jumps back into the beginning of UserVarManagerReplace, or to MacrosManager while stmt.
I'ts like the stack got stepped on and a return to a previous call happend out of order.

Code
#0 ??	UserVarManagerGUI::OpenEditWindow(std::set<wxString, std::less<wxString>, std::allocator<wxString> > const&) (this=0x555555f19da0, var=std::set with 1 element = {...}) (/home/pecan/proj/cbDevel/trunk/src/src/uservardlgs.cpp:18)
#1 0x7ffff6beb227 UserVariableManager::Replace(wxString const&, std::vector<wxString, std::allocator<wxString> >*) (this=0x555555e22f70, variable=..., errorMessages=0x0) (/home/pecan/proj/cbDevel/trunk/src/sdk/uservarmanager.cpp:179)
#2 0x7ffff6aff18c MacrosManager::ReplaceMacros(wxString&, ProjectBuildTarget const*, bool) (this=0x555556dbda50, buffer=..., target=0x555557d9d6c0, subrequest=false) (/home/pecan/proj/cbDevel/trunk/src/sdk/macrosmanager.cpp:678)
#3 0x55555569c2e2 MacrosManager::ReplaceEnvVars(wxString&) (this=0x555556dbda50, buffer=...) (/home/pecan/proj/cbDevel/trunk/src/include/macrosmanager.h:32)
#4 0x7fffe84e707a CompilerGCC::ExecutableExists(cbProject*) (this=0x5555569b1230, prj=0x555557d9c6b0) (/home/pecan/proj/cbDevel/trunk/src/plugins/compilergcc/compilergcc.cpp:1938)
#5 0x7fffe84f12f5 CompilerGCC::OnUpdateUI(wxUpdateUIEvent&) (this=0x5555569b1230, event=...) (/home/pecan/proj/cbDevel/trunk/src/plugins/compilergcc/compilergcc.cpp:3541)
#6 0x7ffff7297641 wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
#7 0x7ffff7297743 wxEventHashTable::HandleEvent(wxEvent&, wxEvtHandler*) () (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
#8 0x7ffff7297aa0 wxEvtHandler::TryHereOnly(wxEvent&) () (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
#9 0x7ffff7297903 wxEvtHandler::DoTryChain(wxEvent&) () (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
#10 0x7ffff7297bd1 wxEvtHandler::ProcessEvent(wxEvent&) () (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
#11 0x7ffff7814f2a wxWindowBase::TryAfter(wxEvent&) () (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#12 0x7ffff77fbac6 wxToolBarBase::UpdateWindowUI(long) () (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#13 0x7ffff78164b7 wxWindowBase::SendIdleEvents(wxIdleEvent&) () (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#14 0x7ffff78164f0 wxWindowBase::SendIdleEvents(wxIdleEvent&) () (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#15 0x7ffff76a6683 wxFrame::SendIdleEvents(wxIdleEvent&) () (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#16 0x7ffff76e7f8d wxAppBase::ProcessIdle() () (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#17 0x7ffff76126a5 wxApp::DoIdle() () (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#18 0x7ffff76127a7 () at /usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0 (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#19 0x7ffff53b404e g_main_context_dispatch() (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0:??)
#20 0x7ffff53b4400 () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0:??)
#21 0x7ffff53b46f3 g_main_loop_run() (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0:??)
#22 0x7ffff59ed37d gtk_main() (/usr/lib/x86_64-linux-gnu/libgtk-3.so.0:??)
#23 0x7ffff7630575 wxGUIEventLoop::DoRun() () (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#24 0x7ffff714bd41 wxEventLoopBase::Run() () (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
#25 0x7ffff726a8eb wxAppTraits::RunLoopUntilChildExit(wxExecuteData&, wxEventLoopBase&) () (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
#26 0x7ffff765b7e7 wxGUIAppTraits::WaitForChild(wxExecuteData&) () (/usr/lib/x86_64-linux-gnu/libwx_gtk3u_core-3.0.so.0:??)
#27 0x7ffff72758d8 wxExecute(char**, int, wxProcess*, wxExecuteEnv const*) () (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
#28 0x7ffff7277480 wxExecute(wxString const&, int, wxProcess*, wxExecuteEnv const*) () (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
#29 0x7ffff729f884 () at /usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0 (/usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0:??)
« Last Edit: September 06, 2023, 10:01:27 pm by Pecan »

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2809
Re: Loop in VarManagement on Linux wx30
« Reply #1 on: September 07, 2023, 06:54:28 pm »
On further debugging of Linux wx30:

This loop exists because the whole calling sequence is anchored from OnUpdateUI(event) which is anchored from the wxAppBase::DoIdlle() loop.

so when the first dialog goes into a wait, the DoIdle() calls OnUpdateUI(event), calls Compilergcc, calls ReplaceEvnVars, and eventually throws up another var replacement dialog for every idle call. An infinite loop.

We need to determine (somewhere in that sequence) where to check if UserVariableManager has already thrown up the Global Variable Editor dialog and if so, return before invoking the "else" clause (I think).
Code
        else
        {
            wxString msg;
            msg.Printf(_("In the currently active set, Code::Blocks does not know\n"
                         "the global compiler variable \"%s\".\n\n"
                         "Please define it."), varName.wx_str());
            if (errorMessages != nullptr)
                errorMessages->push_back(msg);
            m_ui->DisplayInfoWindow(_("Global Compiler Variables"), msg);

            std::set<wxString> ar = {varName};
            m_ui->OpenEditWindow(ar);
            Reload();
        }
« Last Edit: September 07, 2023, 07:03:49 pm by Pecan »

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2809
Re: Loop in VarManagement on Linux wx30
« Reply #2 on: September 07, 2023, 08:07:40 pm »
The following code succeeds to stop the infinite loop, and properly sets the global var, but I'm not sure about what to return when userVariableMgrIsBusy is true. See code at uservarmanager.cpp line 172

Help please.

Code
        else
        {
            // Guard against an infinite loop here because this code is rooted in the wxAppBase::DoIdle()/OnUpdateUI() event
            // and is called over and over until the "Global Variable Editor dialog" is dismissed.
            if (userVariableMgrIsBusy)
                return value;
            // Instantiation/deallocation of this struct acts as a semaphore code guard.
            // Any return from this point will seet the guard to false.
            struct usrVarMgr_t
            {
                usrVarMgr_t()  { userVariableMgrIsBusy = true; }
                ~usrVarMgr_t() { userVariableMgrIsBusy = false; }
            } UsrVarMgr;

            wxString msg;
            msg.Printf(_("In the currently active set, Code::Blocks does not know\n"
                         "the global compiler variable \"%s\".\n\n"
                         "Please define it."), varName.wx_str());
            if (errorMessages != nullptr)
                errorMessages->push_back(msg);
            m_ui->DisplayInfoWindow(_("Global Compiler Variables"), msg);

            std::set<wxString> ar = {varName};

            m_ui->OpenEditWindow(ar);
            Reload();
        }
    }
    return value;
}
« Last Edit: September 07, 2023, 08:21:28 pm by Pecan »

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2809
Re: Loop in VarManagement on Linux wx30
« Reply #3 on: September 10, 2023, 02:14:21 am »
This loop showed up on Windows wx322 also.
Fixed in Head r13350

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6034
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Loop in VarManagement on Linux wx30
« Reply #4 on: September 11, 2023, 03:39:35 pm »
There is a typo:

Code
// Guarantee that we're not waiting on a Blobal Variable Editor dialog.

in rev 13351.

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.