Code::Blocks Forums

Developer forums (C::B DEVELOPMENT STRICTLY!) => Development => Topic started by: christobal on February 12, 2013, 08:53:19 am

Title: Segmentation fault in nativeparser.cpp
Post by: christobal on February 12, 2013, 08:53:19 am
This happens on line 1257, if the Code completion is configured to use one parser per project and the number of loaded projects exceeds the "Maximum allowed parsers" configuration.

This is how I encountered it:
- Configured CC to use one parser per project
- Set the number of max. allowed parsers to 2
- Loaded 2 projects to workspace -> OK
- Loaded 3rd project causes segmentation fault

I use Code::Blocks on Win7 (64-Bit) Rev. 8836; built with wxWidgets 2.8
With Code::Blocks 12.11 the behaviour is the same
Title: Re: Segmentation fault in nativeparser.cpp
Post by: oBFusCATed on February 12, 2013, 09:10:57 am
Do you have a backtrace?
Title: Re: Segmentation fault in nativeparser.cpp
Post by: christobal on February 12, 2013, 09:35:45 am
Do you have a backtrace?

C::B didn't create a crash.log, but I have the call stack from the debugger

Code
#0 65EC347F	NativeParser::RemoveObsoleteParsers(this=0x56c5a60) (D:\codeblocks\source\src\plugins\codecompletion\nativeparser.cpp:1257)
#1 65EBE8A8 NativeParser::CreateParser(this=0x56c5a60, project=0xecb8f60) (D:\codeblocks\source\src\plugins\codecompletion\nativeparser.cpp:590)
#2 65EAB40C CodeCompletion::OnProjectActivated(this=0x56c5a18, event=...) (D:\codeblocks\source\src\plugins\codecompletion\codecompletion.cpp:2384)
#3 65F28428 cbEventFunctor<CodeCompletion, CodeBlocksEvent>::Call(this=0x5cb5028, event=...) (D:/codeblocks/source/src/include/cbfunctor.h:35)
#4 6189A918 Manager::ProcessEvent(this=0xd9a588, event=...) (D:\codeblocks\source\src\sdk\manager.cpp:179)
#5 618B07B6 PluginManager::NotifyPlugins(this=0x2eef4f8, event=...) (D:\codeblocks\source\src\sdk\pluginmanager.cpp:1445)
#6 618D06E9 ProjectManager::SetProject(this=0xdcb368, project=0xecb8f60, refresh=true) (D:\codeblocks\source\src\sdk\projectmanager.cpp:494)
#7 618D3ADF ProjectManager::LoadProject(this=0xdcb368, filename=..., activateIt=true) (D:\codeblocks\source\src\sdk\projectmanager.cpp:792)
#8 0044A064 MainFrame::DoOpenProject(this=0xdbca38, filename=..., addToHistory=true) (D:\codeblocks\source\src\src\main.cpp:1831)
#9 00449B2F MainFrame::OpenGeneric(this=0xdbca38, filename=..., addToHistory=true) (D:\codeblocks\source\src\src\main.cpp:1780)
#10 004524AF MainFrame::OnFileReopenProject(this=0xdbca38, event=...) (D:\codeblocks\source\src\src\main.cpp:2771)
#11 705C7670 wxEvtHandler::ProcessEventIfMatches(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#12 705C77A9 wxEventHashTable::HandleEvent(wxEvent&, wxEvtHandler*) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#13 705C7B74 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#14 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#15 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#16 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#17 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#18 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#19 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#20 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#21 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#22 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#23 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#24 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#25 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#26 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#27 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#28 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#29 705C7B10 wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)

BTW: The same happens if you have loaded a couple of projects and then reduce the number of max. parsers to a number less than currently opened projects.
Title: Re: Segmentation fault in nativeparser.cpp
Post by: ollydbg on February 21, 2013, 03:41:14 pm
Ok, Thanks.
Same crash here.
crash code:
Code
void NativeParser::RemoveObsoleteParsers()
{
    TRACE(_T("NativeParser::RemoveObsoleteParsers()"));

    ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
    const size_t maxParsers = cfg->ReadInt(_T("/max_parsers"), 5);
    wxArrayString removedProjectNames;
    std::pair<cbProject*, ParserBase*> info = GetParserInfoByCurrentEditor();

    while (m_ParserList.size() > maxParsers)
    {
        bool deleted = false;
        for (ParserList::const_iterator it = m_ParserList.begin(); it != m_ParserList.end(); ++it)
        {
            if (it->second == info.second)
                continue;

            if (DeleteParser(it->first))
            {
                wxString prj = (it->first ? it->first->GetTitle() : _T("*NONE*"));
                removedProjectNames.Add(prj);
                deleted = true;
                break;
            }
        }

line: wxString prj = (it->first ? it->first->GetTitle() : _T("*NONE*"));
the debug log is:
Quote
> p it

[debug]> p it
[debug]$1 = {first = , second = }
[debug]>>>>>>cb_gdb:

$1 = {first = , second = }
> p it->first

[debug]> p it->first
[debug]$2 = (cbProject *) 0xfeeefeee
[debug]>>>>>>cb_gdb:

$2 = (cbProject *) 0xfeeefeee
> p it->first->GetTitle()

[debug]> p it->first->GetTitle()
[debug]Cannot access memory at address 0xfeeefeee
[debug]>>>>>>cb_gdb:

Cannot access memory at address 0xfeeefeee

No time to analyze the bug. :)
It would better to file a bug report in BerliOS site, so it never be forgot.

BTW: which version of gdb did you use, it looks your gdb have longer backtrace them mine.
Title: Re: Segmentation fault in nativeparser.cpp
Post by: jarod42 on February 21, 2013, 04:42:26 pm
I assume that DeleteParser modify m_ParserList, so the iterator 'it' is no longer valid.

Moving
Code
wxString prj = (it->first ? it->first->GetTitle() : _T("*NONE*"));
just before
Code
if (DeleteParser(it->first))
should fix the issue.
Title: Re: Segmentation fault in nativeparser.cpp
Post by: christobal on February 22, 2013, 08:26:55 am
I assume that DeleteParser modify m_ParserList, so the iterator 'it' is no longer valid.

Moving
Code
wxString prj = (it->first ? it->first->GetTitle() : _T("*NONE*"));
just before
Code
if (DeleteParser(it->first))
should fix the issue.

It does. CC seems to work as well for all opened projects.

@ollydbg: using GDB 7.2
Title: Re: Segmentation fault in nativeparser.cpp
Post by: ollydbg on February 26, 2013, 02:21:07 am
I assume that DeleteParser modify m_ParserList, so the iterator 'it' is no longer valid.

Moving
Code
wxString prj = (it->first ? it->first->GetTitle() : _T("*NONE*"));
just before
Code
if (DeleteParser(it->first))
should fix the issue.

You are right, I just review the logic of DeleteParser(), look below:
Code
bool NativeParser::DeleteParser(cbProject* project)
{
    wxString prj = (project ? project->GetTitle() : _T("*NONE*"));

    ParserList::iterator it = m_ParserList.begin();
    if (!m_ParserPerWorkspace)
    {
        for (; it != m_ParserList.end(); ++it)
        {
            if (it->first == project)
                break;
        }
    }

    if (it == m_ParserList.end())
    {
        CCLogger::Get()->DebugLog(F(_T("NativeParser::DeleteParser(): Parser does not exist for delete '%s'!"), prj.wx_str()));
        return false;
    }

    bool removeProjectFromParser = false;
    if (m_ParserPerWorkspace)
        removeProjectFromParser = RemoveProjectFromParser(project);

    if (m_ParsedProjects.empty())
    {
        if (it->second == m_Parser)
          SetParser(m_TempParser); // Also updates class browser

        wxString log(F(_("NativeParser::DeleteParser(): Deleting parser for project '%s'!"), prj.wx_str()));
        CCLogger::Get()->Log(log);
        CCLogger::Get()->DebugLog(log);

        delete it->second;
        m_ParserList.erase(it);

        return true;
    }

    if (removeProjectFromParser)
        return true;

    CCLogger::Get()->DebugLog(_T("NativeParser::DeleteParser(): Deleting parser failed!"));
    return false;
}

Here
Code
        m_ParserList.erase(it);
The element is removed.
But return from the function.
Code
it->first
The constant iterator is reused.

I'm going to fix it by your suggestion. Thanks.

It does. CC seems to work as well for all opened projects.
Thanks for the test.
Quote
@ollydbg: using GDB 7.2
Thanks, but I see that longer bt report are some redundant lines like:
Quote
#13 705C7B74   wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#14 705C7B10   wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#15 705C7B10   wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
#16 705C7B10   wxEvtHandler::ProcessEvent(wxEvent&) () (D:\codeblocks\source\src\devel\wxmsw28u_gcc_cb.dll:??)
...
Newer GDB(I'm using GDB CVS head) just stop unwinding in this cases. :)
Title: Re: Segmentation fault in nativeparser.cpp
Post by: ollydbg on February 26, 2013, 02:33:27 am
Fixed in rev 8856. Thanks for you contribution.
Title: Re: Segmentation fault in nativeparser.cpp
Post by: christobal on March 07, 2013, 08:30:35 am
Thanks for fixing.

Unfortunally, I found another one in nativeparser.cpp...

This time it happens if you open a project and *immediately* close it. The problem occures in NativeParser::OnParserStart, which seems to recceive a cbProject pointer to a project that has already been deleted (project->GetTitle refers to 0xfeeefeee).

The Backtrace (C::B Rev 8900) is:

Code
#0 00000000	0xfeeefeee in ??() (??:??)
#1 65ECCBD3 NativeParser::OnParserStart(this=0x32bd5b0, event=...) (D:\projekte\codeblocks\source2\src\plugins\codecompletion\nativeparser.cpp:2458)
#2 705C7670 wxEvtHandler::ProcessEventIfMatches(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () (D:\projekte\codeblocks\source2\src\devel\wxmsw28u_gcc_cb.dll:??)
#3 705C7A96 wxEvtHandler::SearchDynamicEventTable(wxEvent&) () (D:\projekte\codeblocks\source2\src\devel\wxmsw28u_gcc_cb.dll:??)
#4 705C7B4B wxEvtHandler::ProcessEvent(wxEvent&) () (D:\projekte\codeblocks\source2\src\devel\wxmsw28u_gcc_cb.dll:??)
#5 65EF4C49 Parser::ProcessParserEvent(this=0x11503218, state=ParserCommon::ptCreateParser, id=1391, info=...) (D:\projekte\codeblocks\source2\src\plugins\codecompletion\parser\parser.cpp:1178)
#6 65EF3449 Parser::OnBatchTimer(this=0x11503218, event=...) (D:\projekte\codeblocks\source2\src\plugins\codecompletion\parser\parser.cpp:1078)
#7 705C7670 wxEvtHandler::ProcessEventIfMatches(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () (D:\projekte\codeblocks\source2\src\devel\wxmsw28u_gcc_cb.dll:??)
#8 705C7A96 wxEvtHandler::SearchDynamicEventTable(wxEvent&) () (D:\projekte\codeblocks\source2\src\devel\wxmsw28u_gcc_cb.dll:??)
#9 705C7B4B wxEvtHandler::ProcessEvent(wxEvent&) () (D:\projekte\codeblocks\source2\src\devel\wxmsw28u_gcc_cb.dll:??)
#10 706D70ED wxTimerBase::Notify() () (D:\projekte\codeblocks\source2\src\devel\wxmsw28u_gcc_cb.dll:??)
#11 70607BDC wxTimerWndProc() (D:\projekte\codeblocks\source2\src\devel\wxmsw28u_gcc_cb.dll:??)
#12 75CC6238 USER32!IsDialogMessageW() (C:\Windows\syswow64\user32.dll:??)
#13 00000000 0x000309a8 in ??() (??:??)
#14 75CC68EA USER32!AllowForegroundActivation() (C:\Windows\syswow64\user32.dll:??)
#15 70607B64 wxProcessTimer(wxTimer&) () (D:\projekte\codeblocks\source2\src\devel\wxmsw28u_gcc_cb.dll:??)
#16 75CC7D31 USER32!GetMessageExtraInfo() (C:\Windows\syswow64\user32.dll:??)
#17 00000000 0x00000000 in ??() (??:??)



Title: Re: Segmentation fault in nativeparser.cpp
Post by: ollydbg on March 07, 2013, 08:54:47 am
Thanks for fixing.

Unfortunally, I found another one in nativeparser.cpp...

This time it happens if you open a project and *immediately* close it. The problem occures in NativeParser::OnParserStart, which seems to recceive a cbProject pointer to a project that has already been deleted (project->GetTitle refers to 0xfeeefeee).

The Backtrace (C::B Rev 8900) is:

Hi, many thanks for the bug report. I'm currently under heavy work load this week, so I will look into it next week.
The simple logic is: In the NativeParser, there is a Map to hold the database.
Code
cbProject*  -> Parser*
Each Parser is associated with one cbProject. (In another mode, if we use one parser for the whole workspaces, then there is only one parser for all the cbProjects in the workspaces)



Title: Re: Segmentation fault in nativeparser.cpp
Post by: ollydbg on March 09, 2013, 04:38:57 pm
I get similar crash, but not the same bt as yours.

Q:
Code
cbProject* ProjectManager::LoadProject(const wxString& filename, bool activateIt)
{
    cbProject* result = 0;
    if (!wxFileExists(filename) || !BeginLoadingProject())
    {
        return 0;
    }

    // "Try" block (loop which only gets executed once)
    // These blocks are extremely useful in constructs that need
    // premature exits. Instead of having multiple return points,
    // multiple return values and/or gotos,
    // you just break out of the loop (which only gets executed once) to exit.
    do
    {
        cbProject* project = IsOpen(filename);
        if (project)
        {
            // already open
            result = project;
            break;
        }

        if (FileTypeOf(filename) == ftCodeBlocksProject)
        {
            project = new cbProject(filename);

            // We need to do this because creating cbProject allows the app to be
            // closed in the middle of the operation. So the class destructor gets
            // called in the middle of a method call.

            if (!project->IsLoaded())
            {
                delete project;
                break;
            }

            result = project;
        }
        else // !ftCodeBlocksProject
        {
            // the plugin handler should call begin/end on its own...
            EndLoadingProject(0);

            cbMimePlugin* plugin = Manager::Get()->GetPluginManager()->GetMIMEHandlerForFile(filename);
            if (plugin)
                plugin->OpenFile(filename);
        }

        break;
    }  while (false);
    // we 're done

    EndLoadingProject(result);
    if (activateIt)
    {
        if (m_IsLoadingWorkspace)
            // postpone the call to SetProject() until EndLoadingWorkspace() is called
            // (we must call RebuildTree() before SetProject() is called)
            m_pProjectToActivate = result;
        else
            SetProject(result, true);
    }

    return result;
}

I don't understand this comment.
Code
            // We need to do this because creating cbProject allows the app to be
            // closed in the middle of the operation. So the class destructor gets
            // called in the middle of a method call.

            if (!project->IsLoaded())
            {
                delete project;
                break;
            }
The project may be deleted when loading? I don't know how it did.
Title: Re: Segmentation fault in nativeparser.cpp
Post by: ollydbg on March 16, 2013, 10:06:52 am
Today, I try to reproduce this crash.

Firstly, I disable all the plugins except Codecompletion plugin, and I can't reproduce the crash
But after I enable the Compiler plugin, then I can reproduce the crash.

So, can anyone confirm this? Thanks.

In CC's code, it will call some compiler's function to get some include paths of GCC, maybe it is un-safe.

EDIT: Should the Compiler plugin be detached/destroyed after CC plugin?
Title: Re: Segmentation fault in nativeparser.cpp
Post by: Jenna on March 16, 2013, 10:19:05 am
Today, I try to reproduce this crash.

Firstly, I disable all the plugins except Codecompletion plugin, and I can't reproduce the crash
But after I enable the Compiler plugin, then I can reproduce the crash.

So, can anyone confirm this? Thanks.

In CC's code, it will call some compiler's function to get some include paths of GCC, maybe it is un-safe.

EDIT: Should the Compiler plugin should be detached after CC plugin?

There are other crash, that only occur when cc- and compiler-plugin are enabled (if I remember correctly).

If one plugin depends on another it's always unsafe, and we should have some kind of dependency and priority checking for the plugins, to force a load and unload-order.

But in my opinion no plugin should try to use other plugins funnctions before all plugins are loaded (that might not work, if some functions are used for initializing) and after unloading plugins has started.

This will not cover the problem of one plugin depending on another one in normal use.
So the dependency and priority approach might be better.
Title: Re: Segmentation fault in nativeparser.cpp
Post by: ollydbg on March 16, 2013, 10:28:13 am
Quote
There are other crash, that only occur when cc- and compiler-plugin are enabled (if I remember correctly).

If one plugin depends on another it's always unsafe, and we should have some kind of dependency and priority checking for the plugins, to force a load and unload-order.

But in my opinion no plugin should try to use other plugins funnctions before all plugins are loaded (that might not work, if some functions are used for initializing) and after unloading plugins has started.
The crash happens like below steps(I guess):
1, app started
2, both cc and compiler plugin loaded correctly
3, user open a cbp project
4, cc start parsing (after some timer delay) and query compiler search path from compiler plugin(this internally call gcc command line)
5, user click the "close" button of the app

Then, I guess compiler destroyed before cc, so crash happens.

Quote
This will not cover the problem of one plugin depending on another one in normal use.
So the dependency and priority approach might be better.
Yes, I think priority approach is good.
Title: Re: Segmentation fault in nativeparser.cpp
Post by: oBFusCATed on March 16, 2013, 04:43:59 pm
Then, I guess compiler destroyed before cc, so crash happens.
Probably you can add an event which notifies all plugins that the unload process has started, so they can clean themselves and they can untangle some of the dependencies.
Title: Re: Segmentation fault in nativeparser.cpp
Post by: ollydbg on March 17, 2013, 03:35:34 pm
Then, I guess compiler destroyed before cc, so crash happens.
Probably you can add an event which notifies all plugins that the unload process has started, so they can clean themselves and they can untangle some of the dependencies.
I'm not fully understand this idea.
Do you mean, if cc received a "unload start" event, it will not call some function of compiler plugin?
Can you be more specific?
Thanks.
Title: Re: Segmentation fault in nativeparser.cpp
Post by: Grad on March 18, 2013, 02:25:47 pm
The crash happens like below steps(I guess):
1, app started
2, both cc and compiler plugin loaded correctly
3, user open a cbp project
4, cc start parsing (after some timer delay) and query compiler search path from compiler plugin(this internally call gcc command line)
5, user click the "close" button of the app

I had the same with older (slower) XP systems. The CC was using the log which wasn't there any more (at shutdown).
I have solved this with the appShutDown flag in OnRelease and use this same flag as argument in the ClearParsers.
In the deleteParser and RemoveProjectFromParser I use this flag to turn off the logging.

I had no problems since with shutting down.

(But the logging has nothing to do with compiler so that's strange).
Title: Re: Segmentation fault in nativeparser.cpp
Post by: ollydbg on March 19, 2013, 03:40:18 am
The CC was using the log which wasn't there any more (at shutdown).
I have solved this with the appShutDown flag in OnRelease and use this same flag as argument in the ClearParsers.
In the deleteParser and RemoveProjectFromParser I use this flag to turn off the logging.

I had no problems since with shutting down.

(But the logging has nothing to do with compiler so that's strange).
Can you show us the patches? Thanks.

@ALL:
About the logging in CC, why not use a wx standard log functions? It already supports messages from muti-threads.