Reputation: 109
I have the following example program that I want to debug:
#include <iostream>
#include <assert.h>
using namespace std;
int f(int x) {
assert(false); // something bad happens
return 2 * x;
}
int main() {
int a;
for (int i = 0; i < 5; i++) {
a++; // a is uninitialized
cout << a << endl;
}
cout << f(1) << endl;
}
This code has two problems:
a
within the loop is uninitializedf
causes the program to crashTo detect these problems, I compile with g++ -Wall -Og -g source.cpp
and I get the following warning:
source.cpp: In function ‘int main()’:
source.cpp:17:10: warning: ‘a’ may be used uninitialized in this function [-Wmaybe-uninitialized]
17 | a++; // a is uninitialized
|
As this question shows, the flag -Og
(or any other optimization flag) is necessary for getting this warning.
When I debug the resulting executable with gdb
, it crashes (because of the assert statement) and the backtrace looks something like this:
[...]
#4 0x000055555555528f in f (x=<optimized out>) at source.cpp:7
#5 0x0000555555555322 in main () at source.cpp:21
As you can see, the variable x
has been optimized out. This happened because of the -Og
flag, as discussed in this question.
Obviously, I don't want this for debugging purposes. But when I remove the -Og
flag, the previously mentioned warning won't show up anymore. I now want to find a way to get this warning without having optimized out variables. Is this possible with g++
?
I am using g++
version 10.2.0 and gdb
version 9.2 on Ubuntu 20.10.
Upvotes: 1
Views: 733
Reputation: 213907
Is this possible with g++?
No. Unfortunately, GCC performs the "is value used uninitialized?" analysis in one of its optimization passes, and disabling optimization also disables that pass.
Contrast this with Clang/LLVM, which had an explicit goal of not making warnings dependent on optimization.
clang++ -Wall -Wextra -c t.cc # no optimization
t.cc:17:9: warning: variable 'a' is uninitialized when used here [-Wuninitialized]
a++; // a is uninitialized
^
t.cc:14:10: note: initialize the variable 'a' to silence this warning
int a;
^
= 0
1 warning generated.
As you can see, the variable x has been optimized out.
That is a deficiency in either the g++
(if it didn't emit location info for the parameter), or in gdb
(if it didn't decode the info which g++
emitted).
In theory -Og
should not degrade your debugging experience, though it obviously did here.
Looking at the readelf -wi
for g++
-compiled code, I see:
<1><285d>: Abbrev Number: 114 (DW_TAG_subprogram)
<285e> DW_AT_external : 1
<285e> DW_AT_name : f
<2860> DW_AT_decl_file : 1
<2861> DW_AT_decl_line : 5
<2862> DW_AT_decl_column : 5
<2863> DW_AT_linkage_name: (indirect string, offset: 0x169d): _Z1fi
<2867> DW_AT_type : <0xe4f>
<286b> DW_AT_low_pc : 0x3d
<2873> DW_AT_high_pc : 0x23
<287b> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa)
<287d> DW_AT_GNU_all_call_sites: 1
<287d> DW_AT_sibling : <0x28e1>
<2><2881>: Abbrev Number: 115 (DW_TAG_formal_parameter)
<2882> DW_AT_name : x
<2884> DW_AT_decl_file : 1
<2885> DW_AT_decl_line : 5
<2886> DW_AT_decl_column : 11
<2887> DW_AT_type : <0xe4f>
<288b> DW_AT_location : 0x2dc (location list)
<288f> DW_AT_GNU_locviews: 0x2d8
...
I don't see any definition of 0x2dc
or 0x2d8
, so it seems to me that this is a problem on the g++
side, but I am not entirely sure how to read location lists. It's possible that g++
does in fact emit required info, and GDB doesn't interpret it as it should.
P.S. lldb
shows the same output as GDB:
a.out: t.cc:7: int f(int): Assertion `false' failed.
Process 974666 stopped
* thread #1, name = 'a.out', stop reason = hit program assert
frame #4: 0x0000555555555205 a.out`f(x=<unavailable>) at t.cc:7:5
4
5 int f(int x) {
6
-> 7 assert(false); // something bad happens
8
9 return 2 * x;
10 }
That is an extra indication that the problem is probably on the g++
side.
Upvotes: 1