Hey guys, I think I know why some of the plugins (like the TODO list and perhaps even Code Completion) waste too much memory!
Look!
bool cbRead(wxFile& file, wxString& st, wxFontEncoding encoding)
{
st.Empty();
if (!file.IsOpened())
return false;
int len = file.Length();
if(!len)
{
file.Close();
return true;
}
char* buff = new char[len+1];
if (!buff)
{
file.Close();
return false;
}
file.Read((void*)buff, len);
file.Close();
buff[len]='\0';
DetectEncodingAndConvert(buff, st, encoding);
// NOW WHERE'S DELETE BUFF?????????
return true;
}
Notice that DetectEncodingAndConvert takes for parameter a const char*, so it means it doesn't do anything to buff. However, buff isn't released at the end. Hence, the leak.
I'll add a delete operator and see if nothing breaks.
there is another memleak in codecompletion plugin (CCplugin)
BT: I just remembered something I realised sometime back: A possible crash candidate in parser.cpp, lines 690-696 (and on some other places I don't recall, too):
token = new Token();
if (!token->SerializeIn(f))
{
delete token;
token = 0;
break;
}
What if token could not be created (and is NULL therefore)? Shouldn't the if-check better be:
if (token && !token->SerializeIn(f))
or something? (Need to implement an appropriate action anyway then...)
With regards, Morten.
Ps.: Should be go for a corporate bug-hunting for CC only?! ;-)
Here is some "Meat" for "Memory-Leak-Hunters". ;)
I'm attaching the Valgrind log of Code::Blocks. I've run debug build of C::B (Rev 4145) with valgrind with the following options.
valgrind --leak-check=full --show-reachable=yes
BTW, I'm a newbie with valgrind. So I'm posting the log which I received. Please feel free to suggest improvements, if any.
Best Regards,
Biplab
[attachment deleted by admin]
Again bad news: I spotted only one location with a call to FileManager::Load without freeing the reserved memory:
- src/app.cpp:512
But adding this delete did not solve our big memory lead. Perhaps a small one, but not our real one. I have no idea where there is a call to delete missing. *Maybe* somewhere in the CC-plugin but I didn't find it. Anyway, if I did not overlook something the CC-plugin delegates the ownership of this objects to the cbThreadPool. I did not understand this class completely but it has calls to delete but I'm not sure if they are really used. There is at least one in the destructor of the thread pool which should free all memory but this one would not solve our problem as it would only free the memory when Code::Blocks is closed. But we have to free the memory after the CC-plugin finished its parsing.
Edit: Found two minor possible memory leaks. Shouldn't there be deletes in the following two functions?
bool Parser::ParseBufferForFunctions(const wxString& buffer)
{
ParserThreadOptions opts;
opts.wantPreprocessor = m_Options.wantPreprocessor;
opts.useBuffer = true;
opts.bufferSkipBlocks = true;
opts.handleFunctions = true;
ParserThread* thread = new ParserThread(this,
buffer,
false,
opts,
m_pTempTokens);
return thread->Parse();
}
bool Parser::ParseBufferForUsingNamespace(const wxString& buffer, wxArrayString& result)
{
ParserThreadOptions opts;
// opts.wantPreprocessor = m_Options.wantPreprocessor; // ignored
// opts.useBuffer = false; // ignored
// opts.bufferSkipBlocks = false; // ignored
ParserThread* thread = new ParserThread(this,
wxEmptyString,
false,
opts,
m_pTempTokens);
return thread->ParseBufferForUsingNamespace(buffer, result);
}
hacky patch here: http://developer.berlios.de/patch/index.php?func=detailpatch&patch_id=2075&group_id=5358
The patch has an error.
opts.loader=Manager::Get()->GetFileManager()->Load(bufferOrFilename, false);
Should be:
if(!opts.loader)
{
opts.loader=Manager::Get()->GetFileManager()->Load(bufferOrFilename, false);
}
Otherwise you'd be overwriting the loader in case the function gets called somewhere else. Please fix and resend the patch :)
It's most probable.
<stack>
<frame level="0" function="wxFatalSignalHandler" offset="00000026" />
<frame level="1" />
<frame level="2" function="EditorLexerLoader::Load(LoaderBase*)" offset="0000001d" />
<frame level="3" function="EditorColourSet::LoadAvailableSets()" offset="00000362" />
<frame level="4" function="EditorColourSet::EditorColourSet(wxString const&)" offset="00000067" />
<frame level="5" function="EditorManager::EditorManager()" offset="000003e9" />
<frame level="6" function="Manager::GetEditorManager() const" offset="00000056" />
<frame level="7" function="MainFrame::OnStartHereLink(wxCommandEvent&)" offset="00000000" />
<frame level="8" function="MainFrame::OnPluginInstalled(CodeBlocksEvent&)" offset="00000000" />
<frame level="9" function="MainFrame::OnPluginInstalled(CodeBlocksEvent&)" offset="00000000" />
<frame level="10" function="CodeBlocksApp::OnAppActivate(wxActivateEvent&)" offset="00000000" />
<frame level="11" function="CodeBlocksApp::OnBatchBuildDone(CodeBlocksEvent&)" offset="00000000" />
<frame level="12" function="wxAppConsole::CallOnInit()" offset="00000000" />
</stack>
LoaderBase* seems to be the culprit, but having the source line numbers would be better.
Can you do us a favor? On your codeblocks directory, there should be a file called "codeblocks.RPT".
Open it with a text editor and browse to the latest entry. Can you copy and paste the lines here, please? Thanks! :)
line 170 of backgroundthread.h causes the problem (delete job), so presumably job is being deleted twice...
class BackgroundThread ...
ExitCode Entry()
{
AbstractJob* job;
for(;;)
{
semaphore->Wait();
if(die)
break;
job = queue->Pop();
if(job->deleted)
{
delete job;
continue;
}
(*job)();
job->done = true;
if(job->deleted || ownsJobs)
{
****** delete job; // CRASH
}
}
return 0;
};
The recent svn history for that file might help:
http://svn.berlios.de/wsvn/codeblocks/trunk/src/include/backgroundthread.h?op=diff&rev=0&sc=0
I can't reproduce it reliably, seems to happen randomly opening the same project... no idea what it is now. But no crashes with CC disabled, again.
Well, now that the workerthread code is gone, at least it'll be easier for us to identify the culprit. After some deductions, the only possibility left is that it's my fault, and I have understood why :oops:. I wasn't still not sure why, until the crash was reproduced without Thomas' code.
K, here goes...
In my latest change to Code Completion, to fix the class browser not being updated, i moved the code that parses the active projects, from a wxTimerEvent handler, to the OnWorkspaceLoaded event handler. After looking at the app.cpp code a few minutes ago, I noticed that the parsing starts BEFORE it should, making these random crashes appear. Since it's multithreaded, the error only gets triggered either on very fast machines, or on very slow machines.
(The problem is that these 3 changes took place in the same build - from 4165 to 4169: 1) Thomas' workerthread change, 2) dmoore's memleak fix, and 3) My apparently-harm change to the parsing)
Anyway...
bool CodeBlocksApp::OnInit()
{
...
MainFrame* frame = 0; frame = InitFrame();
m_Frame = frame;
...
Manager::Get()->GetMessageManager()->DebugLog(_T("Initializing plugins..."));
CodeBlocksEvent event(cbEVT_APP_STARTUP_DONE);
Manager::Get()->ProcessEvent(event);
Manager::ProcessPendingEvents();
splash.Hide();
}
The problem is that m_Frame isn't set in the middle of InitFrame, and guess what happens in there:
MainFrame* CodeBlocksApp::InitFrame()
{
...
Manager::Get()->GetProjectManager()->LoadWorkspace();
...
}
And in LoadWorkspace...
CodeBlocksEvent event(cbEVT_WORKSPACE_LOADED);
Manager::Get()->GetPluginManager()->NotifyPlugins(event);
So, Thomas, you were both right and wrong: The error was triggered by Code Completion because it's the ONLY plugin yet that uses the new EVT_WORKSPACE_LOADED; but the fault lies within my changes to ProjectManager, because I didn't take into account that the app hadn't been initialized yet in all workspace loads.
And *THIS* is why it happened *ONLY* if you had a workspace open beforehand.
I'll fix ProjectManager so that it only sends the event after the main frame has been initialized. But please don't re-commit your backgroundthread change until we have tested my change... just to be on the safe side :mrgreen:
Edit: I modified the code and am compiling, but I have to go to the job now :( I'll commit in around 10 hours, sorry...
Twice, I got the crash described but I have CC disabled.
It occurred after the splash and just as the CB window appeared.
I have no auto loading of files. So how could this be a CC crash?
I'll run under gdb from now on. See If I can catch it.
SVN4169 XpSp2
Tuesday, June 26, 2007 at 09:32:52.
c:\Usr\Proj\cbBeta\trunk\src\devel\codeblocks.exe caused an Access Violation at location 00000011 Reading from location 00000011.
Registers:
eax=00000011 ebx=01725b00 ecx=00000001 edx=01759d0c esi=015e8194 edi=ffffffff
eip=00000011 esp=0202fec4 ebp=0202fed0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
Call stack:
00000011
606C34C1 c:\Usr\Proj\cbBeta\trunk\src\devel\codeblocks.dll:606C34C1 _ZN16BackgroundThread5EntryEv
100BE97B c:\Usr\Proj\cbBeta\trunk\src\devel\wxmsw28u_gcc_custom.dll:100BE97B _ZN11wxSemaphore7TryWaitEv
100BEA8D c:\Usr\Proj\cbBeta\trunk\src\devel\wxmsw28u_gcc_custom.dll:100BEA8D _ZN11wxSemaphore7TryWaitEv
77C3A3B0 C:\WINDOWS\system32\msvcrt.dll:77C3A3B0 _endthreadex
7C80B50B C:\WINDOWS\system32\kernel32.dll:7C80B50B GetModuleFileNameA
Pecan: Thanks for clearing that up!
Anyway.
I tested my fix, and this is what happens:
[09:08:28.875]: Initializing plugins...
[09:08:28.890]: Add project Code::Blocks in parsing queue
This proves that the parsing doesn't start until the plugins have been correctly initialized. In other words, it works! :)
I'm committing the changes right now... done. Revision 4185.