2

At this simple C99-Code:

int main(void){
  int a[3][3] = {1};
  int m = 3;
  int x;
  int b[m][m];
  x = sizeof(b);
  b[0][0] = -1;
  return 0;
}

with GDB we set a breakpoint at the return line and run. Now let's look at the following:

(gdb) p a
$1 = {{1, 0, 0}, {0, 0, 0}, {0, 0, 0}}
(gdb) p b
$2 = 0x7fffffffe3a0
(gdb) p sizeof(a)
$3 = 36
(gdb) p sizeof(b)
$4 = 0
(gdb) p x
$5 = 36
(gdb) whatis a
type = int [3][3]
(gdb) whatis b
type = int [][]
(gdb) 

I wonder how this does happen. The C runtime environment assumes that the type of b is int [3][3] (because sizeof(b) is 36), but GDB does not.

viuser
  • 953
  • 6
  • 19
  • 2
    `gdb` is using the debug information stored in your executable file in compile time. C runtime... guess what? is getting some information in runtime. But in this case it *is* a bit weird, as your array is not truly variable-length, as `m` is known in compile-time. – Eugene Sh. Jun 22 '16 at 21:25
  • There is not "runtime environment" in C. Just some startup code which is inactive while `main` runs. – too honest for this site Jun 22 '16 at 22:18
  • @Olaf: depends on the definition of "runtime environment". – viuser Jun 22 '16 at 22:25
  • @wolf-revo-cats: If you have a different one than normal programmers, feel free to state it. And please add a reference where the standard states something about such an environment. – too honest for this site Jun 22 '16 at 22:27
  • @wolf-revo-cats: Apparently, the GDB 7.7 might have a bug, see updated answer. This still might be plenty of other reasons such as different DWARF format. – Grzegorz Szpetkowski Jun 22 '16 at 22:32
  • @Olaf: I don't think that I use it differently. See [here](http://stackoverflow.com/a/3900802/5767184) for a definition. And, yes, the term "runtime environment" does not occur in the C11 standard. But that's also true for stack, heap. – viuser Jun 22 '16 at 22:55
  • @wolf-revo-cats: The reason there is no stack or heap in the standard is exactly the same as there is no runtime in the standard: none is mandatory to implement the language. The standard library is no run-time, simply because is is not required to implement the standard either (yes, there are required headers, but those doe not provide any code). – too honest for this site Jun 22 '16 at 23:34

1 Answers1

5

The most obvious explanation would be that you have entered into main, but apparently have not reached VLA declaration.

To cover this, the C11 (N1570) §6.2.4/7 Storage durations of objects states that (emphasis mine):

For such an object that does have a variable length array type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration.35)

The remedy is to step up into the declaration of VLA (tested with gcc 4.4.7 and gdb 7.2):

Breakpoint 1, main () at so.c:1
1   int main(void){
(gdb) s
2     int a[3][3] = {1};
(gdb) s
3     int m = 3;
(gdb) s
5     int b[m][m];
(gdb) s
6     x = sizeof(b);
(gdb) p b
$5 = {{-1207961984, 0, 1114472}, {6381016, 6319652, -1073745804}, {6416216, 14, 129100401}}
gdb) whatis b
type = int [variable][variable]

It may be also a discrepancy between gdb versions or some sort of bug, though the latter is always the last thing to consider.

EDIT:

I have build gdb 7.7 (CentOS 6.8 32-bit) from source and it displays the address of b instead of array content, so I confirm that issue is with this specific version and consider it has a potential bug or misfeature.

On the other hand, the latest version 7.11 behaves correctly.

GDB 7.7

[grzegorz@centos workspace]$ gdb-7.7/gdb/gdb -q a.out 
Reading symbols from a.out...done.
(gdb) b main
Breakpoint 1 at 0x80483ab: file so.c, line 1.
(gdb) r
Starting program: /home/grzegorz/workspace/a.out 

Breakpoint 1, main () at so.c:1
1   int main(void){
(gdb) s
2     int a[3][3] = {1};
(gdb) s
3     int m = 3;
(gdb) 
5     int b[m][m];
(gdb) 
6     x = sizeof(b);
(gdb) p b
$1 = 0xbffff0c0

GDB 7.11

[grzegorz@centos workspace]$ gdb-7.11/gdb/gdb -q a.out 
Reading symbols from a.out...done.
(gdb) b main
Breakpoint 1 at 0x80483ab: file so.c, line 1.
(gdb) r
Starting program: /home/grzegorz/workspace/a.out 

Breakpoint 1, main () at so.c:1
1   int main(void){
(gdb) s
2     int a[3][3] = {1};
(gdb) 
3     int m = 3;
(gdb) 
5     int b[m][m];
(gdb) 
6     x = sizeof(b);
(gdb) p b
$1 = {{-1207961984, 0, 1114472}, {6381016, 6319652, -1073745676}, {6416216, 14, 129100401}}

Moral story: Either upgrade or downgrade your version of gdb to get correct behaviour

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • The OP states "*with GDB we set a breakpoint at the return line and run*"...Can you show the output of `whatis b` in your run? – Eugene Sh. Jun 22 '16 at 21:45
  • 1
    Right. In general, memory for the VLA can't be allocated until execution reaches the declaration, because it can depend on values that haven't been computed until that point. (A compiler is free to do the allocation early and/or with a compile-time computed size if it's able to. In this case, the VLA can be folded into the stack frame for the function call.) – Keith Thompson Jun 22 '16 at 21:50
  • @Eugene Sh.: Sure. I attached the output and "soften" my answer. – Grzegorz Szpetkowski Jun 22 '16 at 21:52
  • So we see that GDB knows that it is VLA, but can't tell it's dimensions. Do you get the same output *before* the VLA declaration? I guess you just have a different version of the GDB with the OP.. – Eugene Sh. Jun 22 '16 at 21:52
  • What version of GDB do you use? – viuser Jun 22 '16 at 21:56
  • @EugeneSh: It still the same, with both variable indices. – Grzegorz Szpetkowski Jun 22 '16 at 21:58
  • @wolf-revo-cats: It's GNU gdb 7.2. Could you specify yours version in question? It may be a discrepacy between two versions indeed. – Grzegorz Szpetkowski Jun 22 '16 at 21:58
  • I use GDB 7.7, I did everything exactly as you said. But `p b` still just gives me the *address* of `b`. – viuser Jun 22 '16 at 22:05
  • 1
    It could be the way it is compiled aswell – Eugene Sh. Jun 22 '16 at 22:07