我遇到了 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 认为变量中的值pc
(answer
如果你把它放在里面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