Debug issue FYI



  • I was using the following

    QString st = ui->source->toPlainText();   //source is a QPlainTextEdit
    

    it was the last statement and the debugger showed the value to be blank; however, when I added another line, namely:

    qDebug() << st

    did the debugger show the correct value of the string.


  • Qt Champions 2016

    Hi
    Can it be a out of scope thing?
    Also what platform, Qt version and compiler is this seen on?



  • @mrjj Linux Mint 64bit latest version of Qt 5.9
    It was the last statement in a method and it was resolved when the debug statement was added. So I could have been out of scope, but the cursor was pointing to the closing bracket. It would seem to me that the stack should not have been unwound until the thread of execution had exited the method. Since I wasted some time trying to figure out the problem, I will in the future always add a debug statement at the end to prevent a recurrance.


  • Qt Champions 2016

    @ofmrew
    Ok, sounds a bit odd.
    Im also on Mint at work i will try it.



  • @ofmrew said in Debug issue FYI:

    I was using the following

    QString st = ui->source->toPlainText();   //source is a QPlainTextEdit
    

    it was the last statement and the debugger showed the value to be blank;

    If you assign st as last statement in a function, the compiler may optimize the assignment, because the variable is never read. if you add a qDebug afterwards, it is read.
    So did you check for compiler warnings?



  • @aha_1980 There were no compiler warnings.


  • Qt Champions 2016

    If you put the breakpoint at the last } of the function the debugger will break after the stack's been unwound. It's a peculiarity of sorts I've found. When I do mid-work debug run and I have such a case I put an empty statement like int z = 0 and break at it (before it's executed) to get proper debug information.



  • @kshegunov I tried putting the breakpoint on the opening bracket of the method and the statement itself, same result. It looks like the culprit is no statement between the statement and the closing bracket. Thanks to all for your responses. Is this a bug?


  • Qt Champions 2016

    @ofmrew said in Debug issue FYI:

    Is this a bug?

    I don't know, in my experience it has been like this forever, so I'd assume not, or at worst a minor one. It never really bothered me much, as there's a very simple workaround as I mentioned above.



  • @ofmrew said in Debug issue FYI:

    @kshegunov I tried putting the breakpoint on the opening bracket of the method and the statement itself, same result. It looks like the culprit is no statement between the statement and the closing bracket. Thanks to all for your responses. Is this a bug?

    Most compilers will make certain small "optimizations" on certain pieces of code (e.g. not creating/updating a variable if it's never used), such that the exact instructions do not always correspond one-to-one with what you might expect looking at the source code literally, even if overall optimizations are off. And this is likely to be a compiler generated code rather than debugger issue. When debugging I often have to append a z = z + 1 or str += "" kind-of-statement in the source code at the end of a function if the last statement changed z/str and I want to see the value, varying across compilers/debuggers and languages.

    BTW, when the last statement in a function is auto variable = function(), why should the compiler generate the code to actually allocate/set the variable at all? If you look at the disassembly code, wouldn't surprise me if the variable part is simply not there.


  • Qt Champions 2016

    @JNBarchan said in Debug issue FYI:

    Most compilers will make certain small "optimizations" on certain pieces of code (e.g. not creating/updating a variable if it's never used), such that the exact instructions do not always correspond one-to-one with what you might expect looking at the source code literally, even if overall optimizations are off.

    I beg to differ, you can't just optimize the return value out of the assembly because the compiler can't know if this won't create a side effect because of your destructor not being run! Additionally, I have never seen it and I really doubt it is in fact done. Here's an excerpt of the assembly from g++ (7.2.x) for a very simple program compiled without optimization and with debug symbols. This is the C++ code:

    void function()
    {
        QStringList list = QStringList { "1", "2", "3", "4" };
        QString str = list.last();
    }
    

    This is the assembly for the last line onward.

            11 [1]	    QString str = list.last();
    0x555555555896  <+0x00ac>        48 8d 45 b8           lea    -0x48(%rbp),%rax
    0x55555555589a  <+0x00b0>        48 89 c7              mov    %rax,%rdi
    0x55555555589d  <+0x00b3>        e8 7c 06 00 00        callq  0x555555555f1e <QList<QString>::last()>
    0x5555555558a2  <+0x00b8>        48 89 c2              mov    %rax,%rdx
    0x5555555558a5  <+0x00bb>        48 8d 45 b0           lea    -0x50(%rbp),%rax
    0x5555555558a9  <+0x00bf>        48 89 d6              mov    %rdx,%rsi
    0x5555555558ac  <+0x00c2>        48 89 c7              mov    %rax,%rdi
    0x5555555558af  <+0x00c5>        e8 36 02 00 00        callq  0x555555555aea <QString::QString(QString const&)>
    0x5555555558b4  <+0x00ca>        48 8d 45 b0           lea    -0x50(%rbp),%rax
    0x5555555558b8  <+0x00ce>        48 89 c7              mov    %rax,%rdi
    0x5555555558bb  <+0x00d1>        e8 82 02 00 00        callq  0x555555555b42 <QString::~QString()>
            10 [2]	    QStringList list = QStringList { "1", "2", "3", "4" };
    0x5555555558c0  <+0x00d6>        48 8d 45 b8           lea    -0x48(%rbp),%rax
    0x5555555558c4  <+0x00da>        48 89 c7              mov    %rax,%rdi
    0x5555555558c7  <+0x00dd>        e8 80 03 00 00        callq  0x555555555c4c <QStringList::~QStringList()>
            12 [1]	}
    0x5555555558cc  <+0x00e2>        eb 47                 jmp    0x555555555915 <function()+299>
    

    As you can see the compiler doesn't strip or optimize anything here. It will create the string from the QStringList::last's return value and then it will immediately start to unwind the stack (+0x00ca onward). Something more, if one puts a breakpoint exactly at the closing brace } the debugger will break at +0x00e2 exactly after the stack's been unwound. So at least for g++ + gdb (but I imagine for other compilers and debuggers too) it's not the compiler stripping anything, it's just where the break is placed in the assembly.



  • @kshegunov
    I do bow to your greater knowledge in this area. I did not mean that the destructor was not to be run, I meant I was not sure that the space on he stack for the variable str would necessarily be allocated. Does the disassembly show the return value being stored into str?

    Not that it matters, but I am mighty confused at that disassembly for the source code you show at the top. They are correctly in sync, aren't they? EDIT: OIC, the disassembler shows the corresponding source line for the QStringList destructor --- wow, OK!



  • @kshegunov I your response you indicated it was where the break was placed. It does not seem to matter in this case: there is a single statement and the break can be place at the beginning, at the end or on the statement, the results are the same, nothing shows in the string. Maybe the problem is not with the placement of the breakpoint, but with the fact that it is a single statement--grasping for straws!


  • Qt Champions 2016

    @JNBarchan said in Debug issue FYI:

    Does the disassembly show the return value being stored into str?

    Yes, the value is stored (through a call to the copy constructor) to -0x50(%rbp) which is the QString object. And after that the destructor is called for that object at +0x00d1 (the actual object's address is loaded just above at +0x00ca).

    They are correctly in sync, aren't they?

    Yes, absolutely. That one was pulled from the "Operate by instruction" view in Qt Creator.

    @ofmrew said in Debug issue FYI:

    Maybe the problem is not with the placement of the breakpoint, but with the fact that it is a single statement--grasping for straws!

    In fact it is, look at the two screenshots bellow and you'll see how the breakpoints are placed in code. The first one is placed just before the QStringList::last call, while the second one (the one at the closing brace) is after the stack's unwound.



  • When you "step over" the str = assignment statement, it executes the code for that line plus the unwind which follows it. Are you saying the breakpoint on the } is supposed to be before the unwind, is that the point?


  • Qt Champions 2016

    @JNBarchan said in Debug issue FYI:

    Are you saying the breakpoint on the } is supposed to before the unwind, is that the point?

    I'm saying that, since the breakpoint that is at } is after the stack unwinding you won't get to see what was in the QString object in the debugger's auto/watch pane when the debugger actually stops at the breakpoint. That's why introducing a dummy statement after QString str = list.last() can be used to break before the stack's been unwound.



  • @kshegunov
    LOL, yes, that's just why I said I often put in a final statement like str += "" (or any other statement) when debugging.
    I thought the debate was over whether the debugger is OK to choose to put the bp there or whether it should put it before the stack unwind.


  • Qt Champions 2016

    @JNBarchan said in Debug issue FYI:

    I thought the debate was over whether the debugger is OK to choose to put the bp there or whether it should put it before the stack unwind.

    This I don't know for sure, as indicated before. It may be considered a bug, it may be a feature. In any case my "main" point is that this isn't due to the compiler optimizing stuff, but just a peculiarity of the debugger/Qt Creator's debug helpers.



  • @kshegunov
    OK, I agree. It was an interesting conversation anyway :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.