0

我遇到了 Memcheck 报告未初始化值的问题,我认为这些是完全合法的。我设法创建了一个展示这种行为的小示例程序。我想知道 Memcheck 是否真的错了,可以做些什么。(除了将错误添加到抑制文件中之外,还有其他解决方案吗?)

为了重现这一点,我制作了下面的程序。它运行go放入0x42堆栈的函数,调用og(这会将下一条指令的地址压leave入堆栈),然后og将其存储esp+4到全局变量a中。

堆栈如下所示:

| address of `leave` instruction |                     pc = a[-1]
| 0x42                           |  a points here, answer = a[0]

如果我构建它并运行 Valgrind,

gcc -g -m32 main.c go.S -o main
valgrind --track-origins=yes ./main

Valgrind 认为变量中的值pcanswer如果你把它放在里面if)是未定义的。我用调试器检查了那里的值实际上是我想要的。

==14160== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==14160== Command: ./main
==14160== 
==14160== Conditional jump or move depends on uninitialised value(s)
==14160==    at 0x804847D: print (main.c:18)
==14160==    by 0x80484B0: ??? (go.S:19)
==14160==    by 0x8048440: main (main.c:8)
==14160==  Uninitialised value was created by a stack allocation
==14160==    at 0x80484AC: ??? (go.S:19)
==14160== 
==14160== Use of uninitialised value of size 4
==14160==    at 0x80484B1: ??? (go.S:20)
==14160==    by 0x8048440: main (main.c:8)
==14160==  Uninitialised value was created by a stack allocation
==14160==    at 0x80484AC: ??? (go.S:19)

如果我从 Valgrind 调试--vgdb-error=0并打印定义,它表示所有位都是未定义的。

(gdb) p &pc
$1 = (int *) 0xfea5e4a8
(gdb) mo xb 0xfea5e4a8 4
              ff      ff      ff      ff
0xFEA5E4A8:     0x9e    0x84    0x04    0x08

0xfea5e4a8 处的值为

(gdb) x/x 0xfea5e4a8
0xfea5e4a8:     0x0804849e

(gdb) x/i 0x0804849e
   0x804849e <go+10>:   leave  
(gdb)

主程序

#include<stdio.h>

int *a;

extern void go();

int main() {
    go();
    printf("finito\n");
    return 0;
}

int print() {
    int answer = a[0];
    int pc = a[-1];

    // use the vars
    if (pc == 0x42) {
        printf("%d\n", 0);
    }
}

去.S

    .text

.globl go

go:
    pushl %ebp
    movl %esp, %ebp

    pushl $0x42
    call og

    leave
    ret

og:
    addl $4, %esp
    movl %esp, a
    sub $4, %esp
    call print
    ret
4

1 回答 1

1

问题是这个代码序列:

addl $4, %esp
movl %esp, a
sub $4, %esp

当您向上移动%esp时,valgrind 会将新堆栈指针位置下方的所有内容标记为未定义,即使您将其移回,它也会保持这种状态。

无论如何它都不安全,因为如果在 add 和 sub 之间有信号命中,那么该堆栈真的可能会被覆盖(在 32 位代码中 - 在 64 位代码中,指针下方有一个“红色区域”是安全的,但 valgrind 知道这一点)。

于 2016-01-09T15:54:20.710 回答