在变量赋值之前,内存不包含垃圾

时间:2014-08-06 10:45:01

标签: c linux assembly gdb

我有一个简单的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之前,该内存位置是否包含随机垃圾值?

4 个答案:

答案 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

对此的良好比喻可能是随机数生成器,它返回零。零是与112377相同的随机值。