|
From: John R.
|
Valgrind 2.0.0 (memcheck) does not notice when a conditional jump
depends on an uninitialized bit.
-----jfrtest2.c
#include <stdio.h> /* printf */
int
test2()
{
unsigned const b = 2; /* has exactly one '1' bit; rest are '0' */
unsigned x; /* uninitialized */
/* Uncomment the following line to see complaints
* from memcheck about 'x' uninit as used by printf.
*/
/*printf("uninitialized x=%#x\n", x);*/
x &= 0x80808080; /* leaving 4 bits uninit */
x |= 0x11111111; /* each nibble now is either 1 or 9 */
/* (x % 15) adds the nibbles because 1==(16 mod 15) */
/* The possible values of (x % 15) are {1,2,8,9,10} only. */
if (b & (x % 15)) {
printf("uninit caught %#x\n", x);
}
return 0;
}
void
proof2() /* Prove "b & (x % 15)" can have both zero and non-zero value. */
{
unsigned const b = 2; /* has exactly one '1' bit; rest are '0' */
int seen = 0;
int summary = 0;
unsigned j = 0;
do { /* check all 2**32 possible values; takes 2.5 minutes @ 1.6GHz */
unsigned x = --j;
x &= 0x80808080; /* leaving 4 bits uninit */
x |= 0x11111111; /* each nibble is either 1 or 9 */
summary |= 1<<(x % 15);
if (0==((1<<1) & seen) && 0!=(b & (x % 15))) {
seen |= (1<<1);
printf("1 %#x %#x\n", j, x);
} else
if (0==((1<<0) & seen) && 0==(b & (x % 15))) {
seen |= (1<<0);
printf("0 %#x %#x\n", j, x);
}
if (0 && ((1<<1)|(1<<0))==seen) { /* enable for shortest both-ways examples */
break;
}
} while (0!=j);
printf("summary of possible bits = %#x\n", summary);
}
int
main()
{
int const r = test2();
/*proof2();*/ /* optional */
return r;
}
-----end jfrtest2.c
$ gcc -g -o jfrtest2 jfrtest2.c
$ valgrind ./jfrtest2
==7141== Memcheck, a.k.a. Valgrind, a memory error detector for x86-linux.
==7141== Copyright (C) 2002-2003, and GNU GPL'd, by Julian Seward.
==7141== Using valgrind-2.0.0, a program supervision framework for x86-linux.
==7141== Copyright (C) 2000-2003, and GNU GPL'd, by Julian Seward.
==7141== Estimated CPU clock rate is 1630 MHz
==7141== For more details, rerun with: -v
==7141==
==7141==
==7141== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$ gdb jfrtest2 ## generated assembly code looks OK
(gdb) x/23i test2
0x8048328 <test2>: push %ebp
0x8048329 <test2+1>: mov %esp,%ebp
0x804832b <test2+3>: sub $0x18,%esp
0x804832e <test2+6>: movl $0x2,0xfffffffc(%ebp)
0x8048335 <test2+13>: lea 0xfffffff8(%ebp),%eax
0x8048338 <test2+16>: andl $0x80808080,(%eax)
0x804833e <test2+22>: lea 0xfffffff8(%ebp),%eax
0x8048341 <test2+25>: orl $0x11111111,(%eax)
0x8048347 <test2+31>: mov 0xfffffff8(%ebp),%edx
0x804834a <test2+34>: mov %edx,%eax
0x804834c <test2+36>: mov $0xf,%ecx
0x8048351 <test2+41>: mov $0x0,%edx
0x8048356 <test2+46>: div %ecx
0x8048358 <test2+48>: mov %edx,%eax
0x804835a <test2+50>: and 0xfffffffc(%ebp),%eax
0x804835d <test2+53>: test %eax,%eax
0x804835f <test2+55>: je 0x8048374 <test2+76> ## should complain here
# uncomment the "proof2();" and re-run (2.5 minutes @ 1.6GHz)
$ ./jfrtest2
1 0xffffffff 0x91919191 ## so 0xffffffff results in !=0
0 0xffff7f7f 0x91911111 ## so 0xffff7f7f results in ==0
summary of possible bits = 0x706
$ ## 0x706 is bits 1,2,8,9,10
gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
glibc-2.3.2-27.9.6
System is Red Hat 9: 2.4.20-20.9.
--
John Reiser, jreiser@BitWagon.com
|