Я столкнулся с проблемой, что 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)
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. Это всегда так. Хотя это случается редко, операционная система может перезаписать эту часть стека, скажем, в обработчике прерывания. - person 500 - Internal Server Error   schedule 09.01.2016