Bug 425993 - Crash in BreakpointModel::breakpoint() when exiting KDevelop while debugging a program
Summary: Crash in BreakpointModel::breakpoint() when exiting KDevelop while debugging ...
Status: RESOLVED FIXED
Alias: None
Product: kdevelop
Classification: Unclassified
Component: CPP Debugger (show other bugs)
Version: git master
Platform: Compiled Sources Linux
: NOR crash (vote)
Target Milestone: ---
Assignee: Igor Kushnir
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-08-30 15:44 UTC by Igor Kushnir
Modified: 2020-10-16 14:39 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In: 5.6.1


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Igor Kushnir 2020-08-30 15:44:35 UTC
SUMMARY
When a user exits KDevelop while debugging a program, a queued call to MIDebugger::readyReadStandardOutput() may be invoked during or after ~CorePrivate(). If this happens after ~DebugController() (which is the parent of BreakpointModel), a crash is likely, because readyReadStandardOutput() indirectly calls MIBreakpointController::updateFromDebugger(), which assumes that BreakpointModel is not null (as do all other MIBreakpointController's member functions).

SOFTWARE/OS VERSIONS
Manjaro GNU/Linux, Xfce
KDE Frameworks Version: 5.73.0
Qt Version: 5.15.0

ADDITIONAL INFORMATION
I am going to create a Merge Request with a fix soon.

BACKTRACE (Debug)
Application: KDevelop (kdevelop), signal: Segmentation fault

[KCrash Handler]
#4  0x00007fd07528f340 in QScopedPointer<KDevelop::BreakpointModelPrivate, QScopedPointerDeleter<KDevelop::BreakpointModelPrivate> >::operator->() const (this=0x10) at /usr/include/qt/QtCore/qscopedpointer.h:118
#5  0x00007fd07528e72b in qGetPtrHelper<QScopedPointer<KDevelop::BreakpointModelPrivate, QScopedPointerDeleter<KDevelop::BreakpointModelPrivate> > const>(QScopedPointer<KDevelop::BreakpointModelPrivate, QScopedPointerDeleter<KDevelop::BreakpointModelPrivate> > const&) (ptr=...) at /usr/include/qt/QtCore/qglobal.h:1133
#6  0x00007fd07528e602 in KDevelop::BreakpointModel::d_func() const (this=0x0) at ../kdevplatform/debugger/breakpoint/breakpointmodel.h:198
#7  0x00007fd07528d5f9 in KDevelop::BreakpointModel::breakpoint(int) const (this=0x0, row=2) at ../kdevplatform/debugger/breakpoint/breakpointmodel.cpp:622
#8  0x00007fd005a7e5ab in KDevMI::MIBreakpointController::updateFromDebugger(int, KDevMI::MI::Value const&, QFlags<KDevelop::BreakpointModel::ColumnFlag>) (this=0x55a769ef2000, row=2, miBkpt=..., lockedColumns=...) at ../plugins/debuggercommon/mibreakpointcontroller.cpp:653
#9  0x00007fd005a81310 in KDevMI::MIBreakpointController::InsertedHandler::handle(KDevMI::MI::ResultRecord const&) (this=0x55a76a6526b0, r=...) at ../plugins/debuggercommon/mibreakpointcontroller.cpp:140
#10 0x00007fd005a5dfd9 in KDevMI::MI::MICommand::invokeHandler(KDevMI::MI::ResultRecord const&) (this=0x55a76485e000, r=...) at ../plugins/debuggercommon/mi/micommand.cpp:111
#11 0x00007fd005a624e0 in KDevMI::MIDebugger::processLine(QByteArray const&) (this=0x55a769d389a0, line=...) at ../plugins/debuggercommon/midebugger.cpp:224
#12 0x00007fd005a619e7 in KDevMI::MIDebugger::readyReadStandardOutput() (this=0x55a769d389a0) at ../plugins/debuggercommon/midebugger.cpp:147
#13 0x00007fd005a65231 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (KDevMI::MIDebugger::*)()>::call(void (KDevMI::MIDebugger::*)(), KDevMI::MIDebugger*, void**) (f=(void (KDevMI::MIDebugger::*)(KDevMI::MIDebugger * const)) 0x7fd005a6190a <KDevMI::MIDebugger::readyReadStandardOutput()>, o=0x55a769d389a0, arg=0x7fff84c18200) at /usr/include/qt/QtCore/qobjectdefs_impl.h:152
#14 0x00007fd005a64e1c in QtPrivate::FunctionPointer<void (KDevMI::MIDebugger::*)()>::call<QtPrivate::List<>, void>(void (KDevMI::MIDebugger::*)(), KDevMI::MIDebugger*, void**) (f=(void (KDevMI::MIDebugger::*)(KDevMI::MIDebugger * const)) 0x7fd005a6190a <KDevMI::MIDebugger::readyReadStandardOutput()>, o=0x55a769d389a0, arg=0x7fff84c18200) at /usr/include/qt/QtCore/qobjectdefs_impl.h:185
#15 0x00007fd005a6489e in QtPrivate::QSlotObject<void (KDevMI::MIDebugger::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (which=1, this_=0x55a769ccb270, r=0x55a769d389a0, a=0x7fff84c18200, ret=0x0) at /usr/include/qt/QtCore/qobjectdefs_impl.h:418
#16 0x00007fd075acfa26 in QtPrivate::QSlotObjectBase::call(QObject*, void**) (a=0x7fff84c18200, r=0x55a769d389a0, this=0x55a769ccb270) at ../../include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398
#17 doActivate<false>(QObject*, int, void**) (sender=0x55a76a577d70, signal_index=15, argv=argv@entry=0x7fff84c18200) at kernel/qobject.cpp:3886
#18 0x00007fd075ac8bc0 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (sender=<optimized out>, m=m@entry=0x7fd075d2cda0 <QProcess::staticMetaObject>, local_signal_index=local_signal_index@entry=6, argv=argv@entry=0x7fff84c18200) at kernel/qobject.cpp:3946
#19 0x00007fd075a0430e in QProcess::readyReadStandardOutput(QProcess::QPrivateSignal) (this=<optimized out>, _t1=...) at .moc/moc_qprocess.cpp:367
#20 0x00007fd075a09a56 in QProcessPrivate::tryReadFromChannel(QProcessPrivate::Channel*) (this=0x55a769b86ef0, channel=0x55a769b87000) at io/qprocess.cpp:1057
#21 0x00007fd075a09fb5 in QProcessPrivate::_q_canReadStandardError() (this=<optimized out>) at io/qprocess.cpp:1084
#22 QProcess::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) (_o=<optimized out>, _c=<optimized out>, _id=<optimized out>, _a=0x7fff84c183b0) at .moc/moc_qprocess.cpp:210
#23 0x00007fd075acfa60 in doActivate<false>(QObject*, int, void**) (sender=0x55a76a56dd00, signal_index=3, argv=argv@entry=0x7fff84c183b0) at ../../include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:395
#24 0x00007fd075ac8bc0 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (sender=sender@entry=0x55a76a56dd00, m=m@entry=0x7fd075d2f180 <QSocketNotifier::staticMetaObject>, local_signal_index=local_signal_index@entry=0, argv=argv@entry=0x7fff84c183b0) at kernel/qobject.cpp:3946
#25 0x00007fd075ad2f90 in QSocketNotifier::activated(QSocketDescriptor, QSocketNotifier::Type, QSocketNotifier::QPrivateSignal) (this=this@entry=0x55a76a56dd00, _t1=..., _t2=<optimized out>, _t3=...) at .moc/moc_qsocketnotifier.cpp:178
#26 0x00007fd075ad379d in QSocketNotifier::event(QEvent*) (this=0x55a76a56dd00, e=0x7fff84c184c0) at kernel/qsocketnotifier.cpp:302
#27 0x00007fd076923702 in QApplicationPrivate::notify_helper(QObject*, QEvent*) (this=<optimized out>, receiver=0x55a76a56dd00, e=0x7fff84c184c0) at kernel/qapplication.cpp:3671
#28 0x00007fd075a987ba in QCoreApplication::notifyInternal2(QObject*, QEvent*) (receiver=0x55a76a56dd00, event=0x7fff84c184c0) at ../../include/QtCore/5.15.0/QtCore/private/../../../../../src/corelib/thread/qthread_p.h:325
#29 0x00007fd075af1f46 in socketNotifierSourceDispatch(GSource*, GSourceFunc, gpointer) (source=0x55a75f257d90) at kernel/qeventdispatcher_glib.cpp:107
#30 0x00007fd071e5743c in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#31 0x00007fd071ea51d9 in  () at /usr/lib/libglib-2.0.so.0
#32 0x00007fd071e56221 in g_main_context_iteration () at /usr/lib/libglib-2.0.so.0
#33 0x00007fd075af1331 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (this=0x55a75f1aa9f0, flags=...) at kernel/qeventdispatcher_glib.cpp:423
#34 0x00007fd075a9713c in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) (this=this@entry=0x7fff84c186d0, flags=..., flags@entry=...) at ../../include/QtCore/../../src/corelib/global/qflags.h:141
#35 0x00007fd075a9f5c4 in QCoreApplication::exec() () at ../../include/QtCore/../../src/corelib/global/qflags.h:121
#36 0x000055a75e51c81f in main(int, char**) (argc=3, argv=0x7fff84c18b48) at ../app/main.cpp:850
[Inferior 1 (process 129648) detached]
Comment 1 Igor Kushnir 2020-10-16 14:39:10 UTC
Git commit 79c2b0f65c258cb0d931f55aa417bb5cb8714ca1 by Igor Kushnir.
Committed on 15/10/2020 at 15:26.
Pushed by igorkushnir into branch '5.6'.

MIDebugger: check ICore::debugController() for nullptr

When a user exits KDevelop while debugging a program, a queued call to
MIDebugger::readyReadStandardOutput() may be invoked during or after
~CorePrivate(). If this happens after ~DebugController() (which is the
parent of BreakpointModel), a crash is likely, because
readyReadStandardOutput() indirectly calls
MIBreakpointController::updateFromDebugger(), which assumes that
BreakpointModel is not null (as do all other MIBreakpointController's
member functions).

Note that MIDebugger::readyReadStandardOutput() after ~DebugController()
can be invoked both from inside ~MIDebugger() (more precisely, from
inside the QProcess::waitForFinished() call) and before the destructor.

There is no need to process a debugger's standard output and risk a
crash when KDevelop has almost finished shutting down.
FIXED-IN: 5.6.1

M  +10   -0    plugins/debuggercommon/midebugger.cpp

https://invent.kde.org/kdevelop/kdevelop/commit/79c2b0f65c258cb0d931f55aa417bb5cb8714ca1