Author Topic: Found location of crash when deleting breakpoint  (Read 2781 times)

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2507
Found location of crash when deleting breakpoint
« on: January 28, 2008, 12:36:52 am »
Recently, I've been running a pgm under the debugger that
causes CB to crash when I delete a breakpoint. But the pgm runs ok when not being debugged. (famous saying)

So I placed asm(int3) traps until I bracketed the problem.
It seems that GdbCmd_RemoveBreakpoint::ParseOutput is assigning
a -1 to a breakpoint that has already been deleted.
Here is a way to reproduce the error.

I do not know the debugger well enough to know how to fix it.

In debuggerstate.cpp at line 191, place a trap and note
the bp address that's being deleted.

DebuggerBreakpoint* DebuggerState::RemoveBreakpoint(int idx, bool deleteit)
{
    // do we have a valid index?
    if (idx < 0 || idx >= (int)m_Breakpoints.GetCount())
        return 0;
    // yes, remove it from the list
    DebuggerBreakpoint* bp = m_Breakpoints[idx];
    m_Breakpoints.RemoveAt(idx);

    // notify driver if it is active
    if (m_pDriver)
        m_pDriver->RemoveBreakpoint(bp);

    if (deleteit)
    {
        asm("int3"); /*trap*/ //<===============
        delete bp; //<= look at bp address
        return 0;
    }
    return bp;
}


In gdb_command.h at line 777, place the following trap.
When the debugger stops at "cmd->ParseOutput(buffer.Left(idx));"
step into the GdbCmd_RemoveBreakpoint() routine and
look at m_BP of the line: "m_BP->index = -1;".
m_BP is the exact address of the bp that got previously deleted.

class GdbCmd_RemoveBreakpoint : public DebuggerCmd
{
   < lines skipped>

//        DebugLog(wxString::Format(_T("Command parsing output (cmd: %s): %s"), cmd->m_Cmd.c_str(), buffer.Left(idx).c_str()));
        RemoveTopCommand(false);
        buffer.Remove(idx);
        // remove the '>>>>>>' part of the prompt (or what's left of it)
        int cnt = 6; // max 6 '>'
        while (buffer.Last() == _T('>') && cnt--)
            buffer.RemoveLast();
        if (buffer.Last() == _T('\n'))
            buffer.RemoveLast();
        wxString cmdString = cmd->m_Cmd;             /*trap*/
        if (cmdString.StartsWith(_T("delete "))) asm("int3"); /*trap*/

        cmd->ParseOutput(buffer.Left(idx));
        delete cmd;
        RunQueue();
    }



This is the culprit: line 508 in gdb_commands.h . m_BP has already been deleted.

            // invalidate bp number
            m_BP->index = -1;


Although there's a test for m_BP, it's never zero. It seems to be a copy of the original bp.

            if (!m_BP)
                return;



        void ParseOutput(const wxString& output)
        {
            if (!m_BP)
                return;

            // invalidate bp number
            m_BP->index = -1;

            if (!output.IsEmpty())
                m_pDriver->Log(output);
//            m_pDriver->DebugLog(wxString::Format(_("Breakpoint removed: file %s, line %d"), m_BP->filename.c_str(), m_BP->line + 1));
        }

        DebuggerBreakpoint* m_BP;
};
« Last Edit: January 28, 2008, 01:04:03 am by Pecan »

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Re: Found location of crash when deleting breakpoint
« Reply #1 on: January 28, 2008, 09:01:43 am »
I'm too lazy to dig through that code right now, since I don't know the code either. :)  (also, I have no crashes)

However, if there is a crash due to a double-delete, then replacing delete bp; with Delete(bp); will solve it. Delete() should preferrably be used anyway, unless a pointer is deleted in a class destructor (where it can still be used, but is pointless).
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."