我遇到了Memcheck报告未初始化值的问题,我认为这些都是完全合法的。我设法创建了一个展示此行为的小示例程序。我想知道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
和打印definedness,它说,所有的位是不确定的。
(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)
的main.c
#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);
}
}
go.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
我认为这个问题可能是,只要你做'addl $ 4,%esp',你不再拥有超出esp的堆栈部分。情况总是如此。虽然它很少发生,但O/S可以自由地覆盖堆栈的那部分,比如在中断处理程序中。 –