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.
-
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. -
@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? -
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 likeint 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?
-
@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
orstr += ""
kind-of-statement in the source code at the end of a function if the last statement changedz
/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. -
@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 variablestr
would necessarily be allocated. Does the disassembly show the return value being stored intostr
?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!
-
@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 theQString
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. -
@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 theQString
object in the debugger's auto/watch pane when the debugger actually stops at the breakpoint. That's why introducing a dummy statement afterQString 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 likestr += ""
(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. -
@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.