Bug 24459 - GDB prints a wrong value at -O3
Summary: GDB prints a wrong value at -O3
Status: NEW
Alias: None
Product: gdb
Classification: Unclassified
Component: gdb (show other bugs)
Version: unknown
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-04-17 03:49 UTC by Qirun Zhang
Modified: 2025-01-29 16:36 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2019-04-17 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Qirun Zhang 2019-04-17 03:49:00 UTC
The expected output is "i = 0". However, GDB prints "i = 9". 
The code is generated by gcc-8. I have verified that lldb can print the correct value. So I report the bug here.


$ gcc-8 -v
gcc version 8.1.0 (Ubuntu 8.1.0-5ubuntu1~16.04)

$ gdb-trunk -v
GNU gdb (GDB) 8.3.50.20190416-git

$ gcc-8 -O3 -g abc.c outer.c


#Wront value from gdb#
$ gdb-trunk -x cmds -batch a.out
Breakpoint 1 at 0x400449: file abc.c, line 11.

Breakpoint 1, main () at abc.c:11
11	      optimize_me_not();
$1 = 9


#lldb generate the correct value#
$ lldb -s cmds -batch a.out
-> 11  	      optimize_me_not();
   12  	  }
   13  	}
(lldb) p i
(int) $0 = 0
(lldb) kill




Files to reproduce:

$ cat abc.c
volatile long a;
int main() {
  int i, b;
  i = 0;
  for (; i < 9; i++)
    a = i;
  i = 0;
  for (; i < 2; i++) {
    b = 0;
    for (; b < 1; b++)
      optimize_me_not();
  }
}

$ cat cmds
b 11
r
p i
kill
q


$ cat outer.c
void optimize_me_not() {}
Comment 1 Tom Tromey 2019-04-17 13:39:48 UTC
I can reproduce the `i = 9` behavior using the Fedora 29 system gcc.

The DWARF for "i":

 <2><6b>: Abbrev Number: 6 (DW_TAG_variable)
    <6c>   DW_AT_name        : i
    <6e>   DW_AT_decl_file   : 1
    <6f>   DW_AT_decl_line   : 3
    <70>   DW_AT_decl_column : 7
    <71>   DW_AT_type        : <0xc2>
    <75>   DW_AT_location    : 0x16 (location list)
    <79>   DW_AT_GNU_locviews: 0x0


So, let's look at location list 0x16:

    00000016 v000000000000003 v000000000000000 views at 00000000 for:
             0000000000400420 0000000000400431 (DW_OP_lit0; DW_OP_stack_value)
    0000002a v000000000000000 v000000000000000 views at 00000002 for:
             0000000000400431 000000000040043c (DW_OP_lit1; DW_OP_stack_value)
    0000003e v000000000000000 v000000000000000 views at 00000004 for:
             000000000040043c 0000000000400447 (DW_OP_lit2; DW_OP_stack_value)
    00000052 v000000000000000 v000000000000000 views at 00000006 for:
             0000000000400447 0000000000400452 (DW_OP_lit3; DW_OP_stack_value)
    00000066 v000000000000000 v000000000000000 views at 00000008 for:
             0000000000400452 000000000040045d (DW_OP_lit4; DW_OP_stack_value)
    0000007a v000000000000000 v000000000000000 views at 0000000a for:
             000000000040045d 0000000000400468 (DW_OP_lit5; DW_OP_stack_value)
    0000008e v000000000000000 v000000000000000 views at 0000000c for:
             0000000000400468 0000000000400473 (DW_OP_lit6; DW_OP_stack_value)
    000000a2 v000000000000000 v000000000000000 views at 0000000e for:
             0000000000400473 000000000040047e (DW_OP_lit7; DW_OP_stack_value)
    000000b6 v000000000000000 v000000000000000 views at 00000010 for:
             000000000040047e 0000000000400489 (DW_OP_lit8; DW_OP_stack_value)
    000000ca v000000000000000 v000000000000000 views at 00000012 for:
             0000000000400489 0000000000400495 (DW_OP_lit9; DW_OP_stack_value)
    000000de v000000000000000 v000000000000000 views at 00000014 for:
             0000000000400495 000000000040049c (DW_OP_lit2; DW_OP_stack_value)
    000000f2 <End of list>


Now in gdb, let's find the PC in question:

(gdb) b 11
Breakpoint 1 at 0x400489: file abc.c, line 11.
(gdb) r
Starting program: /tmp/qq 

Breakpoint 1, main () at abc.c:11
11	      optimize_me_not();
(gdb) p $pc
$1 = (void (*)()) 0x400489 <main+105>

Looking this up in the location list:

             0000000000400489 0000000000400495 (DW_OP_lit9; DW_OP_stack_value)

In other words, gcc tells gdb that the value is 9.


Now, what is interesting is that lldb sets a different breakpoint location:

(lldb) b 11
Breakpoint 1: where = qq`main + 4 at abc.c:11, address = 0x0000000000400424

Reproducing this in gdb:

(gdb) b *0x400424
Breakpoint 1 at 0x400424: file abc.c, line 6.
(gdb) r
Starting program: /tmp/qq 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.28-27.fc29.x86_64

Breakpoint 1, 0x0000000000400424 in main () at abc.c:6
6	    a = i;
(gdb) p i
$1 = 0


So maybe gdb is misinterpreting the line table somehow; but at the same
time there is a gcc bug here IMO.
Comment 2 Mark Wielaard 2019-04-17 19:07:51 UTC
> So maybe gdb is misinterpreting the line table somehow; but at the same
time there is a gcc bug here IMO.

I think what is happening is that gcc -O3 unrolls the second loop. In which case the value of i doesn't really matter, since it isn't actually used anymore in the code.

Also if you look at the linetable with eu-readelf --debug-dump=decodedline you'll see that line 11 expands to multiple addresses. Two of which have a statement marker, so are equally ok to set a breakpoint on.

I haven't looked at the location views, but maybe those can help determine which view the user expects of the variable?
Comment 3 Mark Wielaard 2019-04-17 19:18:08 UTC
There are actually 4 addresses that expand to line 11:

 CU [b] abc.c
  line:col SBPE* disc isa op address (Statement Block Prologue Epilogue *End)
  /tmp/abc.c (mtime: 0, length: 0)
     2:12  S        0   0  0 +0x0000000000001040 <main>
     3:3   S        0   0  0 +0x0000000000001040 <main>
     4:3   S        0   0  0 +0x0000000000001040 <main>
     5:3   S        0   0  0 +0x0000000000001040 <main>
     6:5   S        0   0  0 +0x0000000000001040 <main>
     2:12           0   0  0 +0x0000000000001040 <main>
->  11:7            0   0  0 +0x0000000000001044 <main+0x4>
     6:7            0   0  0 +0x0000000000001046 <main+0x6>
     6:5   S        0   0  0 +0x0000000000001051 <main+0x11>
     6:7            0   0  0 +0x0000000000001051 <main+0x11>
     6:5   S        0   0  0 +0x000000000000105c <main+0x1c>
     6:7            0   0  0 +0x000000000000105c <main+0x1c>
     6:5   S        0   0  0 +0x0000000000001067 <main+0x27>
     6:7            0   0  0 +0x0000000000001067 <main+0x27>
     6:5   S        0   0  0 +0x0000000000001072 <main+0x32>
     6:7            0   0  0 +0x0000000000001072 <main+0x32>
     6:5   S        0   0  0 +0x000000000000107d <main+0x3d>
     6:7            0   0  0 +0x000000000000107d <main+0x3d>
     6:5   S        0   0  0 +0x0000000000001088 <main+0x48>
     6:7            0   0  0 +0x0000000000001088 <main+0x48>
     6:5   S        0   0  0 +0x0000000000001093 <main+0x53>
     6:7            0   0  0 +0x0000000000001093 <main+0x53>
     6:5   S        0   0  0 +0x000000000000109e <main+0x5e>
     6:7            0   0  0 +0x000000000000109e <main+0x5e>
->  11:7   S        0   0  0 +0x00000000000010a9 <main+0x69>
->  11:7   S        0   0  0 +0x00000000000010ae <main+0x6e>
->  11:7            0   0  0 +0x00000000000010b5 <main+0x75>
    13:1            0   0  0 +0x00000000000010b5 <main+0x75>
    13:1       *    0   0  0 +0x00000000000010bb <main+0x7b>

So the two places where i = 0 were "merged" by the compiler.