News:

Accounts with zero posts and zero activity during the last months will be deleted periodically to fight SPAM!

Main Menu

crash on close cbp project (rev 7773)

Started by ollydbg, February 05, 2012, 02:45:39 AM

Previous topic - Next topic

ollydbg

gdb points to here:

bool cbProject::CloseAllFiles(bool dontsave)
{
   // first try to close modified editors

   if (!dontsave && !QueryCloseAllFiles())
           return false;

   // now free the rest of the project files
   Manager::Get()->GetEditorManager()->HideNotebook();
   FilesList::iterator it = m_Files.begin();
   while (it != m_Files.end())
   {
       ProjectFile* f = *it;
       if (f)
       {
           Manager::Get()->GetEditorManager()->Close(f->file.GetFullPath(),true);
       }
       m_Files.erase(it);
       m_FileArray.Remove(*it); //crash here****************************
       delete f;
       it = m_Files.begin();
   }
   Manager::Get()->GetEditorManager()->ShowNotebook();

   return true;
}


No time to find the reason right now.
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.

ollydbg

#1
I test this again, but it does not crash every time I close the cbp project.

But I found another crash after I close the C::B, gdb point to the desturctor of ClassBrowser.
1, start c::b.
2, close c::b, and it crashes.

// class destructor
ClassBrowser::~ClassBrowser()
{
   int pos = XRCCTRL(*this, "splitterWin", wxSplitterWindow)->GetSashPosition();
   Manager::Get()->GetConfigManager(_T("code_completion"))->Write(_T("/splitter_pos"), pos);

   SetParser(NULL);

   if (m_ClassBrowserBuilderThread)
   {
       m_ClassBrowserSemaphore.Post();
       // m_ClassBrowserBuilderThread->Delete(); --> would delete it twice and leads to a warning
       m_ClassBrowserBuilderThread->Wait();
   }
}
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.

oBFusCATed

#2
http://forums.next.codeblocks.org/index.php/topic,15882.0.html

Quote from: ollydbg on February 05, 2012, 02:45:39 AM
gdb points to here:

       m_Files.erase(it);
       m_FileArray.Remove(*it); //crash here****************************
       delete f;


The iterator is invalid, after the erase method. The correct code is m_FileArray.Remove(f); I guess. Or you can swap the two methods (erase and Remove):)
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Jenna

#3
Quote from: oBFusCATed on February 05, 2012, 10:34:58 AM
The iterator is invalid, after the erase method. The correct code is m_FileArray.Remove(f); I guess. Or you can swap the two methods (erase and Remove):)

Definitely not, because:
ProjectFile* f = *it;

The fix by Pecan and committed by Thomas is also not a fix in my opinion (or wxWidgets has a bug in the Remove-function), but it does no harm.

I'm not sure if an invalid iterator is really the cause for it (I did not dig into the sources of wxWidgets deeper, to see whether the iterator can be invalid in this case).

Just changeing the order of removal should do it, first
       m_FileArray.Remove(*it);
and then
       m_Files.erase(it);

In this case the iterator can not be invalid.

In most cases the Remove-method is called on an empty Array, because the array only gets filled if cbProject::GetFile was called at least once, and this is only done by script-functions at the moment.
According to the wxWidgets documentation we can get an assert in debug-mode, but in release-mode just nothing happens, if the element we try to remove does not exist.
If the cause for the crash should be, that we try to remove a not-existing element, we would need to check whether the array is empty and in this case not run the Remove-method.

Jenna

I hope it's finally fixed with svn r7777 (with this revision-number it must be fixed  ;) ).

Additionally closing large projects should be much faster.
My very large test-project (linux kernel 2.6.35 with more than 30000 files) closes about 4 times faster (1200 ms instead of almost 5000 ms).
Times are measured without codecompletion-plugin, which is a little bit unstable at the moment.

ollydbg

Quote from: jens on February 05, 2012, 01:25:19 PM
I hope it's finally fixed with svn r7777 (with this revision-number it must be fixed  ;) ).

Additionally closing large projects should be much faster.
My very large test-project (linux kernel 2.6.35 with more than 30000 files) closes about 4 times faster (1200 ms instead of almost 5000 ms).
Times are measured without codecompletion-plugin, which is a little bit unstable at the moment.
Hi, jens, I can confirm that open/close the cbp project does not crash again. Thank you!
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.

MortenMacFly

Quote from: jens on February 05, 2012, 01:25:19 PM
Times are measured without codecompletion-plugin, which is a little bit unstable at the moment.
It shouldn't be any longer. If it is, please report. I have concluded the things I wanted to change. The next change will take some more time...
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: [url="https://www.codeblocks.org/docs/main_codeblocks_en.html"]https://www.codeblocks.org/docs/main_codeblocks_en.html[/url]
C::B FAQ: [url="https://wiki.codeblocks.org/index.php?title=FAQ"]https://wiki.codeblocks.org/index.php?title=FAQ[/url]

oBFusCATed

Is there any particular reason to remove the ';' after the locking macros? It looks pretty weird.

I'll give it a try in a minute and I'll report if there are any crashes.
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

ollydbg

Quote from: oBFusCATed on February 05, 2012, 03:47:35 PM
Is there any particular reason to remove the ';' after the locking macros? It looks pretty weird.
One reason I can say is: It will make our cc's parser happy(they like a function call statement) ;).
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.

MortenMacFly

Quote from: oBFusCATed on February 05, 2012, 03:47:35 PM
Is there any particular reason to remove the ';' after the locking macros? It looks pretty weird.
Yes, because if you set the macros to nothing, they will expand to truly nothing. Otherwise they would expand to a semicolon. the latter I believe is "more weird". ;-)
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: [url="https://www.codeblocks.org/docs/main_codeblocks_en.html"]https://www.codeblocks.org/docs/main_codeblocks_en.html[/url]
C::B FAQ: [url="https://wiki.codeblocks.org/index.php?title=FAQ"]https://wiki.codeblocks.org/index.php?title=FAQ[/url]

oBFusCATed

Quote from: MortenMacFly on February 05, 2012, 04:09:49 PM
Yes, because if you set the macros to nothing, they will expand to truly nothing. Otherwise they would expand to a semicolon. the latter I believe is "more weird". ;-)
No, it is not, because you (almost) never look at the preprocessed code :)
Also is there any particular reason to set the macros to nothing in this case?
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

MortenMacFly

Quote from: oBFusCATed on February 05, 2012, 04:13:17 PM
Also is there any particular reason to set the macros to nothing in this case?
Yes, if you have followed the discussion with Thomas, instead of locking / unlocking which is excellent for debugging, the better way would be to use a locker object. In that case, the "Unlock" macro has to / will expand to nothing.
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: [url="https://www.codeblocks.org/docs/main_codeblocks_en.html"]https://www.codeblocks.org/docs/main_codeblocks_en.html[/url]
C::B FAQ: [url="https://wiki.codeblocks.org/index.php?title=FAQ"]https://wiki.codeblocks.org/index.php?title=FAQ[/url]

oBFusCATed

I doubt you'll be able the switch to a locker object with just a macro:)
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

MortenMacFly

Quote from: oBFusCATed on February 05, 2012, 04:21:09 PM
I doubt you'll be able the switch to a locker object with just a macro:)
Why not? The first macro will expand to wxMutexLocker(BLAH) and the second to nothing. That's it.
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: [url="https://www.codeblocks.org/docs/main_codeblocks_en.html"]https://www.codeblocks.org/docs/main_codeblocks_en.html[/url]
C::B FAQ: [url="https://wiki.codeblocks.org/index.php?title=FAQ"]https://wiki.codeblocks.org/index.php?title=FAQ[/url]

oBFusCATed

But then you have no guarantee that the mutex will be unlocked at the correct place/time.


CC_LOCK(s_lock);
... code 1 ...
CC_UNLOCK(s_lock);
... code 2 ...
CC_LOCK(s_lock);
... code 3 ...
CC_UNLOCK(s_lock);

Code 2 is executed under a lock and before code3 you have a double locking problem (probably a dead lock).
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]