News:

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

Main Menu

Found location of crash when deleting breakpoint

Started by Pecan, January 28, 2008, 12:36:52 AM

Previous topic - Next topic

Pecan

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;
};

thomas

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."