我有一个简单的C程序:
#include <stdio.h>
int main()
{
int i;
for(i = 0; i < 10; i++)
printf("Hello\n");
return 0;
}
我使用gcc编译它:
gcc -g test.c
然后我运行调试器:
gdb -q ./a.out
我在main设置断点并运行:
(gdb) break main
(gdb) run
然后让它运行直到它到达断点并尝试在rip当前指向的地址处显示汇编指令:
(gdb) x/i $rip
=> 0x400538 <main+8>: mov DWORD PTR [rbp-0x4],0x0
看起来下一条指令将用值0初始化我的局部变量i。由于它还没有执行指令,我预计会有垃圾值。
(gdb) x/4xb $rbp-4
0x7fffffffe0ec: 0x00 0x00 0x00 0x00
它看起来不像垃圾值,看起来一切都已经零了。在执行main中的任何代码之前,断点应该暂停程序。
我在这里缺少什么?在初始化局部变量i之前,该内存位置是否包含随机垃圾值?
答案 0 :(得分:3)
它看起来不像垃圾值,看起来一切都已经零了。
我修改了你的例子,以表明这只是一个巧合。
#include <stdio.h>
int main()
{
int i1;
int i2;
int i3;
int i4;
int i5;
int i6;
int i;
for(i = 0; i < 10; i++)
printf("Hello\n");
return 0;
}
(gdb) start
Temporary breakpoint 1 at 0x4005ac: file main.cpp, line 13.
Starting program: /home/a.out
Temporary breakpoint 1, main () at main.cpp:13
13 for(i = 0; i < 10; i++)
(gdb) info locals
i1 = 0
i3 = 0
i5 = 32767
i = 0
i2 = 4195520
i4 = -7856
i6 = 0
你知道,可能有不同的值。
至于您的示例,此地址的值在到达main()
之前至少更改两次。只需为此地址设置watch
,您就会看到在main()之前调用的函数已更改:
(gdb) watch *(int*)0x7fffffffe06c
Hardware watchpoint 1: *(int*)0x7fffffffe06c
(gdb) r
Starting program: /home/a.out
Hardware watchpoint 1: *(int*)0x7fffffffe06c
Old value = 0
New value = 58
0x0000003a1d890880 in handle_intel () from /lib64/libc.so.6
Hardware watchpoint 1: *(int*)0x7fffffffe06c
Old value = 58
New value = 0
0x0000003a1d0146fd in _dl_runtime_resolve () from /lib64/ld-linux-x86-64.so.2
Hardware watchpoint 1: *(int*)0x7fffffffe06c
Old value = 0
New value = 1
0x00000000004005c3 in main () at main.cpp:7
7 for(i = 0; i < 10; i++)
#0 0x00000000004005c3 in main () at main.cpp:7
答案 1 :(得分:2)
垃圾值可能是任何值,包括值0.该局部变量的内容未定义,直到为其分配值。在此之前你不能指望内容属于某种类型。
然而,在调试构建期间对所有局部变量进行清零是很常见的。如果这是gdb的情况,我不知道。您可以在初始化之前尝试打印变量的内容,然后在没有调试器的情况下进行发布构建,并查看行为是否相同。
更可能的是,编译器决定在实际行i = 0之前初始化变量。编译器可以自由更改程序执行的顺序,如果它可以确定这样做不会影响程序结果。出于性能原因,编译器可能已将零输出移至程序中的较早点。
答案 2 :(得分:1)
你误解了&#34;垃圾&#34; (这甚至不是一个正式的术语)。 C中的未初始化对象具有不确定值。这并不意味着该值是随机的,更不用说它具有任何熵值(在Heartbleed发生之前很久就存在巨大的OpenSSL / Debian惨败这个误解,并且每个人都意识到OpenSSL是多么混乱)。这意味着你不能使用值。如果你这样做,你就没有一个有效的C程序,但没有一个没有意义的程序,并且试图推断它的作用是没有意义的(除非你是一个试图利用它的攻击者)程序中的漏洞)。
答案 3 :(得分:1)
它看起来不像垃圾值
在此上下文中为零 只是&#34;垃圾值&#34;的特殊情况(或更恰当的不确定值),在任何情况下你都不能依赖,这里是一个略微修改的例子,它在我的编译器(gcc 4.4.7
)上产生不同的值:
#include <stdio.h>
int main(void)
{
int i, j, k;
for(i = 0; i < 10; i++)
printf("Hello\n");
return 0;
}
和gdb
会话:
Breakpoint 1, main () at check.c:6
6 for(i = 0; i < 10; i++)
(gdb) x/i $pc
=> 0x4004cc <main+8>: mov DWORD PTR [rbp-0xc],0x0
(gdb) x/4xb $rbp-0xc
0x7fffffffe124: 0xff 0x7f 0x00 0x00
对此的良好比喻可能是随机数生成器,它返回零。零是与112
或377
相同的随机值。