内存在variables赋值之前不包含垃圾

我有一个简单的C程序:

#include <stdio.h> int main() { int i; for(i = 0; i < 10; i++) printf("Hello\n"); return 0; } 

我使用gcc编译它:

 gcc -g test.c 

然后我运行debugging器:

 gdb -q ./a.out 

我在main中设置了一个断点并运行:

 (gdb) break main (gdb) run 

然后让它运行,直到遇到断点,并试图在rip当前指向的地址上显示汇编指令:

 (gdb) x/i $rip => 0x400538 <main+8>: mov DWORD PTR [rbp-0x4],0x0 

它看起来像下一个指令将初始化我的本地variables我的值为0.由于它还没有执行的指令,我希望有一个垃圾值在那里。

 (gdb) x/4xb $rbp-4 0x7fffffffe0ec: 0x00 0x00 0x00 0x00 

它看起来不像垃圾值,看起来所有的东西都已经被清零了。 在执行main中的任何代码之前,断点应该暂停程序。

我在这里错过了什么? 在局部variablesi初始化之前,该内存位置是否应该包含随机垃圾值?

它看起来不像垃圾值,看起来所有的东西都已经被清零了。

我修改了你的例子,以表明这只是一个巧合。

 #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()之前至少改变两次。 只要设置这个地址,你会发现它在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 

垃圾值可能是任何东西,包括值0.该局部变量的内容是未定义的,直到它被赋值的地步。 在这种情况发生之前,你不能期望内容是某种类型的。

然而,在调试构建过程中,所有局部变量都进行了零调整是非常常见的。 如果这是gdb的情况,我不知道。 你可以在初始化之前尝试打印变量的内容,然后在没有调试器的情况下建立一个版本,看看这个行为是否相同。

更可能的是,编译器做出了比实际行i = 0更早的初始化变量的决定。 如果编译器可以确定这样做不会影响程序结果,编译器可以自由地改变程序的执行顺序。 由于性能的原因,编译器可能已经将零点移出到程序的较早点。

你误解了什么是“垃圾”(甚至不是一个正式的术语)。 C中未初始化的对象具有不确定的值 。 这并不意味着这个值是随机的,更不用说它具有任何熵的价值了(实际上,在Heartbleed发生之前,这个误解实际上已经发生了OpenSSL / Debian的巨大失败,并且每个人都意识到OpenSSL是多么的混乱)。 这意味着你不能使用这个值 。 如果你这样做,你没有一个有效的C程序,而是一个毫无意义的程序,试图推断它的作用没有意义(除非你是一个试图利用程序中的漏洞的攻击者)。

它看起来不像垃圾值

在这种情况下,“零”只是一个“垃圾值”(或更正确的值)的特殊情况,在任何情况下都不能依赖,这是一个稍微修改的例子,它在我的编译器上产生了不同的值( 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 

好的比喻可能是随机数字发生器,返回零。 零和112377是相同的随机值。