Bug 376595 - Kdevelop crashes on watch member variable
Summary: Kdevelop crashes on watch member variable
Status: CLOSED UPSTREAM
Alias: None
Product: kdevelop
Classification: Applications
Component: CPP Debugger (show other bugs)
Version: 5.1.0
Platform: Appimage Linux
: NOR normal
Target Milestone: ---
Assignee: kdevelop-bugs-null
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-02-17 19:34 UTC by Ian H
Modified: 2017-02-22 19:46 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments
Debug output for debugger (106.78 KB, text/plain)
2017-02-20 19:21 UTC, Ian H
Details
Proposed patch (2.28 KB, patch)
2017-02-20 20:50 UTC, Peifeng Yu
Details
GDB outputs when watchpoint goes out of scope (2.41 KB, text/plain)
2017-02-21 21:27 UTC, Peifeng Yu
Details
Log file for the test case (92.50 KB, text/plain)
2017-02-21 23:15 UTC, Ian H
Details
Better handle and report debugger errors (5.86 KB, patch)
2017-02-22 00:31 UTC, Peifeng Yu
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ian H 2017-02-17 19:34:30 UTC
Kdevelop crashes whenever a breakpoint on a watched variable is tripped (if the variable is a member variable). Local variables work as intended.

Steps to reproduce:
1. Debug program
2. set Break on change for that variable
3. Run until that variable changes
4. watch crash.
Comment 1 Kevin Funk 2017-02-17 20:28:18 UTC
Please retrieve a backtrace of the crash.

See: https://community.kde.org/Guidelines_and_HOWTOs/Debugging/How_to_create_useful_crash_reports
Comment 2 Ian H 2017-02-17 21:37:07 UTC
so i've never been able to get a backtrace while using the appimage. I attempted to build source today, but it seems there are build errors in master at the moment. how do i set kdesrc-build to use branch 5.1 for kdevelop and kdevplatform? 

I attempted to modify the .kdesrc-buildrc and set it to use branch 5.1, but it attempts to use svn instead of git and then fails to update.
Comment 3 Kevin Funk 2017-02-17 21:46:25 UTC
FWIW, master should build fine according to CI. If you want to switch branches I *think* you should be able to use this:

module kdevelop
  branch-group kf5-qt5
...

If that doesn't work you can still simply just `git checkout 5.1; make; make install` in both the kdevplatform + kdevelop dir.
Comment 4 Ian H 2017-02-17 21:59:22 UTC
I get this build error when i attempt to build master. what module is KUrlRequester in that i'm assuming i need to add to the list of things to download and update.

/home/ian/kdesrc/kdevelop/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.cpp:81:34: error: ‘textEdited’ is not a member of ‘KUrlRequester’
     connect(m_ui->compilerPath, &KUrlRequester::textEdited, this, &CompilersWidget::compilerEdited);
Comment 5 Kevin Funk 2017-02-17 22:36:21 UTC
True, this got added just recently. I've restored compat with KF5 5.15 now.

See:
commit 2c775c07436107f90bec8ee16b73f4e5258f362d
Author: Kevin Funk <kfunk@kde.org>
Date:   Fri Feb 17 23:32:22 2017 +0100

    Restore compat with KF5 5.15
    
    The signal KUrlRequester::textEdited got only added in 5.21

Please try to compile again
Comment 6 Ian H 2017-02-17 22:55:29 UTC
here is the backtrace. it also looks like i got a message saying 'breakpoint doesn't contain required location/expression data'. maybe that has something to do with it

Thread 1 "kdevelop" received signal SIGSEGV, Segmentation fault.
0x00007fffb263a07e in KDevMI::MI::MICommand::markAsCompleted() ()
   from /home/ian/kde-5/lib/x86_64-linux-gnu/plugins/kdevplatform/27/kdevgdb.so
(gdb) bt
#0  0x00007fffb263a07e in KDevMI::MI::MICommand::markAsCompleted() ()
   from /home/ian/kde-5/lib/x86_64-linux-gnu/plugins/kdevplatform/27/kdevgdb.so
#1  0x00007fffb263bd9d in KDevMI::MIDebugger::processLine(QByteArray const&) ()
   from /home/ian/kde-5/lib/x86_64-linux-gnu/plugins/kdevplatform/27/kdevgdb.so
#2  0x00007fffb263b506 in KDevMI::MIDebugger::readyReadStandardOutput() ()
   from /home/ian/kde-5/lib/x86_64-linux-gnu/plugins/kdevplatform/27/kdevgdb.so
#3  0x00007fffb263e308 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (KDevMI::MIDebugger::*)()>::call(void (KDevMI::MIDebugger::*)(), KDevMI::MIDebugger*, void**) ()
   from /home/ian/kde-5/lib/x86_64-linux-gnu/plugins/kdevplatform/27/kdevgdb.so
#4  0x00007fffb263e1ca in void QtPrivate::FunctionPointer<void (KDevMI::MIDebugger::*)()>::call<QtPrivate::List<>, void>(void (KDevMI::MIDebugger::*)(), KDevMI::MIDebugger*, void**) ()
   from /home/ian/kde-5/lib/x86_64-linux-gnu/plugins/kdevplatform/27/kdevgdb.so
#5  0x00007fffb263ded1 in QtPrivate::QSlotObject<void (KDevMI::MIDebugger::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) ()
   from /home/ian/kde-5/lib/x86_64-linux-gnu/plugins/kdevplatform/27/kdevgdb.so
#6  0x00007ffff5d35baf in QtPrivate::QSlotObjectBase::call (a=0x7fffffffcfa0, r=0x6c72030, this=<optimized out>)
    at ../../include/QtCore/../../src/corelib/kernel/qobject_impl.h:124
#7  QMetaObject::activate (sender=sender@entry=0x6c72120, signalOffset=<optimized out>, 
    local_signal_index=local_signal_index@entry=5, argv=argv@entry=0x0) at kernel/qobject.cpp:3698
#8  0x00007ffff5d36537 in QMetaObject::activate (sender=sender@entry=0x6c72120, 
    m=m@entry=0x7ffff5f4c400 <QProcess::staticMetaObject>, local_signal_index=local_signal_index@entry=5, 
    argv=argv@entry=0x0) at kernel/qobject.cpp:3578
#9  0x00007ffff5c34b63 in QProcess::readyReadStandardOutput (this=this@entry=0x6c72120) at .moc/moc_qprocess.cpp:266
---Type <return> to continue, or q <return> to quit---
#10 0x00007ffff5c3d0c2 in QProcessPrivate::tryReadFromChannel (this=0x6c72140, channel=0x6c72270)
    at io/qprocess.cpp:966
#11 0x00007ffff5c3d540 in QProcessPrivate::_q_canReadStandardOutput (this=<optimized out>) at io/qprocess.cpp:977
#12 QProcess::qt_static_metacall (_o=<optimized out>, _c=<optimized out>, _id=<optimized out>, _a=0x7fffffffd1a0)
    at .moc/moc_qprocess.cpp:133
#13 0x00007ffff5d35d2a in QMetaObject::activate (sender=sender@entry=0x6c72ec0, signalOffset=<optimized out>, 
    local_signal_index=local_signal_index@entry=0, argv=argv@entry=0x7fffffffd1a0) at kernel/qobject.cpp:3713
#14 0x00007ffff5d36537 in QMetaObject::activate (sender=sender@entry=0x6c72ec0, 
    m=m@entry=0x7ffff5f50780 <QSocketNotifier::staticMetaObject>, local_signal_index=local_signal_index@entry=0, 
    argv=argv@entry=0x7fffffffd1a0) at kernel/qobject.cpp:3578
#15 0x00007ffff5db524e in QSocketNotifier::activated (this=this@entry=0x6c72ec0, _t1=82)
    at .moc/moc_qsocketnotifier.cpp:134
#16 0x00007ffff5d421cb in QSocketNotifier::event (this=0x6c72ec0, e=<optimized out>) at kernel/qsocketnotifier.cpp:260
#17 0x00007ffff65fa05c in QApplicationPrivate::notify_helper (this=this@entry=0x647190, 
    receiver=receiver@entry=0x6c72ec0, e=e@entry=0x7fffffffd410) at kernel/qapplication.cpp:3716
#18 0x00007ffff65ff516 in QApplication::notify (this=0x7fffffffd970, receiver=0x6c72ec0, e=0x7fffffffd410)
    at kernel/qapplication.cpp:3499
#19 0x00007ffff5d0738b in QCoreApplication::notifyInternal (this=0x7fffffffd970, receiver=0x6c72ec0, 
    event=event@entry=0x7fffffffd410) at kernel/qcoreapplication.cpp:965
#20 0x00007ffff5d5dc95 in QCoreApplication::sendEvent (event=0x7fffffffd410, receiver=<optimized out>)
    at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:224
#21 socketNotifierSourceDispatch (source=0x7659a0) at kernel/qeventdispatcher_glib.cpp:101
#22 0x00007fffee394197 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#23 0x00007fffee3943f0 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#24 0x00007fffee39449c in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#25 0x00007ffff5d5d7cf in QEventDispatcherGlib::processEvents (this=0x765850, flags=...)
    at kernel/qeventdispatcher_glib.cpp:418
#26 0x00007ffff5d04b4a in QEventLoop::exec (this=this@entry=0x7fffffffd620, flags=..., flags@entry=...)
    at kernel/qeventloop.cpp:204
#27 0x00007ffff5d0cbec in QCoreApplication::exec () at kernel/qcoreapplication.cpp:1229
#28 0x000000000040e79e in main ()
Comment 7 Ian H 2017-02-17 22:57:44 UTC
if you need anything else from gdb, i still have it up and will get back to you on monday.
Comment 8 Peifeng Yu 2017-02-18 02:09:45 UTC
Hi Ion, from the backtrace it's not clear what's going wrong here. There's no abnormal pointer access in the frame 0 of the backtrace. Could you also provide the console output when crashing?

The debugger plugin related logs are disabled by default, you can enable it by starting kdevelop like this inside console:

QT_LOGGING_RULES="kdevelop.debuggers.gdb.debug=true;kdevelop.debuggers.common.debug=true" kdevelop
Comment 9 Ian H 2017-02-20 13:50:09 UTC
with those debug messages, i get the same backtrace as before, but i get 

QMetaObject::invokeMethod: No such method ExpandingTree::scrollTo(QModelIndex,QAbstractItemView::ScrollHint)
Breakpoint doesn't contain required location/expression data

before it.

i would assume though that you could recreate this. it is 100% for me.
Comment 10 Peifeng Yu 2017-02-20 16:40:15 UTC
Hmm actually I can't reproduce this. I tried with a structure member variable and it works as intended.

From the log output, kdevelop was complaining about gdb not returning required data. So my guessing is something went wrong with either the gdb itself or the way we were setting breakpoints.

How do you exactly set break on change? By manually using the gdb console or by hovering on the variable and click "stop on change" button?

Also, I'm expecting some log output with the prefix "kdevelop.debuggers.common:" and related to the internal interaction between kdevelop and gdb. Could you paste the full log output?
Comment 11 Ian H 2017-02-20 17:15:30 UTC
I get the crash regardless of how i set the breakpoint. i can set it in gdb or through kdevelop and both will crash.

the only logging stuff i got was 
qt.core.logging: Ignoring malformed logging rule: 'kdevelop.debuggers.gdb.debug=true;kdevelop.debuggers.common.debug=true' at the start of the program

and kdevelop.debuggers.common: "No environment group specified, looks like a broken configuration, please check run configuration 'xxxxxx'. Using default environment group." during the startup of my program. 


'Breakpoint doesn't contain required location/expression data' is logged when i create the breakpoint. There is nothing after that before the backtrace.
Comment 12 Peifeng Yu 2017-02-20 18:31:59 UTC
I see. Seems your Qt version doesn't support semicolon separated logging rules. Instead, create a file named logging.conf with the following content:

[Rules]
kdevelop.debuggers.gdb.debug=true
kdevelop.debuggers.common.debug=true

And launch kdevelop with

QT_LOGGING_CONF='/path/to/logging.conf' kdevelop

I think the crash might be specific to some particular gdb version. But without detailed logging, I can't tell anything yet.
Comment 13 Ian H 2017-02-20 19:21:54 UTC
Created attachment 104134 [details]
Debug output for debugger

Here is the output. my gdb version:
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Comment 14 Milian Wolff 2017-02-20 20:28:47 UTC
Please also try valgrind, that is usually much more helpful in such situations:

valgrind --smc-check=all-non-file --track-origins=yes kdevelop
Comment 15 Peifeng Yu 2017-02-20 20:50:00 UTC
Okay. So setting watch point itself seems normal in log. The crash actually happens before the watch point was triggered.

gdb returned two replies for 35-exec-continue command:

35^running and 35^error,msg=\"Command aborted.\"

This doesn't confirm to the spec and confused kdevelop which assumes each reply must have a corresponding command.

I will fix this by ignoring wild replies from gdb. Please try if my patch fixes the crash.

But this is likely also a bug within gdb itself. I would suggest verify if debugging directly in gdb command line works with your program if there's still something wrong. (Probably something like the program doesn't resume execution because the exec-continue command failed)
Comment 16 Peifeng Yu 2017-02-20 20:50:56 UTC
Created attachment 104135 [details]
Proposed patch
Comment 17 Ian H 2017-02-21 14:16:08 UTC
The patch does prevent the crash, although as you suggested, gdb is just sitting there hanging now. Messing with the gdb console outside of kdevelop led me to something interesting. if i use the command 'watch m_bInUpdate', when i attempt to continue, it will just say "current stack frame does not contain a variable named 'this'" and not do anything. If i use the command 'watch this.m_bInUpdate', it works as i would expect. 

Could it be that when kdevelop adds a watch for member variables it just uses 'watch <varname>'? That being said, if this were the case, i would expect that it would be causing issues for everyone.
Comment 18 Peifeng Yu 2017-02-21 21:27:04 UTC
Created attachment 104154 [details]
GDB outputs when watchpoint goes out of scope

Yes, kdevelop uses plain variable name when adding watch points for member variables. This however should work because gdb will delete all invalid watchpoints when the execution left valid scope.

I've created a minimal test program to trigger this problem:

struct testStruct {
    int a; int b;
    void bar() {
        a = a + 1;
    }
};

int main() {
    testStruct ts;
    ts.a = ts.b = 0;
    ts.bar();
    ts.b++;
    return 0;
}

After compile and load it in gdb, this is what I got:

1. break at line 4
2. watch a
3. continue and gdb stopped after a = a + 1 because of watchpoint hit
4. continue again and gdb stopped at some random point after leaving testStruct::bar() with the following output

Error evaluating expression for watchpoint 2
current stack frame does not contain a variable named `this'
Watchpoint 2 deleted.

5. continue and the program exits normally.

If I use watch this.a instead, the outcome is almost the same with the only difference being the warning from gdb:

Watchpoint 3 deleted because the program has left the block in
which its expression is valid.

I've attached the full output from gdb. The point here is that gdb should be able to delete invalid watchpoint gracefully regardless it was set as "this.<varname>" or "<varname>". And it shouldn't produce malformed output in its machine interface which kdevelop uses.

That being said, I'm using a newer version of gdb than yours, so probably the behavior changed. Ian, are you getting the same behavior using my test program?
Comment 19 Ian H 2017-02-21 22:08:13 UTC
ran the test case, it does not give me the same behavior. i'm currently modifying it to see if i can reproduce the issue. As far as i can tell, the only differences between my current version of the test and my normal source is that the method i'm attempting to use this on is a slot... but in qt, pretty much everything is a slot or called by a slot.
Comment 20 Ian H 2017-02-21 23:04:22 UTC
I have created a simple test program that causes the crash. 
//main.cpp
int main(int argc, char* argv[])
{
    QApplication applicationInstance(argc, argv);
    testGDBCrash crasher;
    if (crasher.exec() != QDialog::Accepted)
        return 0;
    return applicationInstance.exec();
}
//testGDBCrash.h
#ifndef TESTGDBCRASH_H
#define TESTGDBCRASH_H
#include <QDialog>
#include <QObject>
class testGDBCrash : public QDialog
{
    Q_OBJECT
public: 
    testGDBCrash(QWidget * parent=0);
    Q_SLOT void TestCrash();
    bool m_bInUpdate; 
};
#endif // TESTGDBCRASH_H
//testGDBCrash.cpp
#include "testGDBCrash.h"
#include <QPushButton>
#include <QHBoxLayout>
testGDBCrash::testGDBCrash(QWidget* parent):QDialog(parent)
{
    resize(200,100);
    QHBoxLayout * layout=new QHBoxLayout(this);
    QPushButton * pb=new QPushButton("crash",this);
    layout->addWidget(pb);
    setLayout(layout);
    show();
    m_bInUpdate=false;
    
    connect(pb,SIGNAL(clicked()),this,SLOT(TestCrash()));
}
void testGDBCrash::TestCrash()
{
    if(m_bInUpdate)
        return;
    m_bInUpdate=false;
    m_bInUpdate=true;
    m_bInUpdate=false;
}

Steps to crash:
1. Run
2. put a breakpoint on line 18 of testGDBCrash.cpp (the if statement)
3. break on change for m_bInUpdate
4. Continue
5. Watch crash.
Comment 21 Ian H 2017-02-21 23:15:31 UTC
Created attachment 104158 [details]
Log file for the test case

Here is the log file for the test case i created.
Comment 22 Peifeng Yu 2017-02-22 00:28:23 UTC
Okay I can reproduce your issue now. I guess the difference is that yours is multi-threaded (several threads for qt internal stuff). And when gdb stopped, it stopped at another thread different from the main thread. Probably gdb can't handle this case well.

However I'm afraid there's no much I can do on the kdevelop side. As it's hard to distinguish a member variable from normal ones, and it's unclear whether this is the only condition that would trigger the bug. Maybe you should report this to gdb.

In the mean time, as a workaround, you can set watchpoints in the Breakpoints tool view manually, using "this.<varname>" as the location. This works as intended.
Comment 23 Peifeng Yu 2017-02-22 00:31:03 UTC
Created attachment 104160 [details]
Better handle and report debugger errors

Anyway, I've updated my patch to better report and end the debug session in this case.
Comment 24 Ian H 2017-02-22 00:41:28 UTC
would it be possible to maybe have some sort of manually set variable that would be a prefix for member variables? a lot of us use a very specific member variable prefix, so if it starts with that prefix, chances are it is a member? 

it is also possible to determine if the variable was declared in the current scope by using 'info locals', right? so any variable not in 'info locals' would be a member?
Comment 25 Peifeng Yu 2017-02-22 01:34:53 UTC
Well adding an UI to set prefix and extra code to identify and match member variable just sounds too much for a workaround for some bug in gdb that will eventually be fixed.

For the "info locals", there are also global and static variables that are not member variable. There are too many corner cases, not to even mention single variable is only the simplest case for watchpoint[1].

[1] https://sourceware.org/gdb/onlinedocs/gdb/Set-Watchpoints.html
Comment 26 Ian H 2017-02-22 12:46:28 UTC
Alright. I posted in the gdb bugtracking https://sourceware.org/bugzilla/show_bug.cgi?id=21192 

hopefully they will fix it eventually.
Comment 27 Peifeng Yu 2017-02-22 19:46:33 UTC
Thank you for reporting!

I've also added a link pointing back to this bug in their bug tracker.