Re: [ANNOUNCE] kmemcheck v7

From: Jeremy Fitzhardinge
Date: Sat May 10 2008 - 16:45:45 EST


Andi Kleen wrote:
It tracks changes to the stack pointer, and any memory below it is considered uninitialized. But, yes, if you mean that if you use the

But it does not invalidate anything below the stack pointer as soon
as it changes right ?

Yeah, as soon as the stack pointer changes, everything below it is invalidated (except if the stack-pointer change was actually determined to be a stack switch).

variable (or slot) once in a function, then again later, it will still be considered initialized. But that's no different from any other memory.

What I meant is e.g.

f1();
f2();

both f1 and f2 use the same stack memory, but f2 uses it uninitialized,
then I think valgrind would still think it is initialized in f2 from the
execution of f1. It would only detect such things in f1 (assuming there
were no other users of the stack before that)

No, it won't. If the stack pointer goes up then down between f1 and f2, then f2 will get fresh values.

The big thing Valgrind hasn't traditionally helped with is overruns of on-stack arrays. You may be thinking of that.

In theory it could throw away all stack related uninitizedness on each
SP change, but that would be likely prohibitively expensive and also
it might be hard to know the exact boundaries of the stack.

No, its not all that expensive compared the overall cost of valgrind and the amount of diagnostic power it provides. Determining stack boundaries has always been a bit fraught. Typically a stack switch has been determined heuristically by looking for a "large" change in stack pointer, but there's a callback to specifically mark a range of memory as a stack, so that movements into and out of a stack can be determined as a switch (added specifically to deal with small densely packed stacks in uml).

BTW on running a test program here it doesn't seem to detect any uninitialized
stack frames here with 3.2.3. Test program is http://halobates.de/t10.c (should be compiled without optimization)

Hm, I'd expect it to. Oh, your test program doesn't use the value. Valgrind doesn't complain about uninitialized values unless they actually affect execution (ie, a conditional depends on one, you use it as an address for a dereference, or pass it to a syscall).

The attached version emits errors as I'd expect:

$ valgrind t10
==30474== Memcheck, a memory error detector.
==30474== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==30474== Using LibVEX rev 1804, a library for dynamic binary translation.
==30474== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==30474== Using valgrind-3.3.0, a dynamic binary instrumentation framework.
==30474== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==30474== For more details, rerun with: -v
==30474== f1 set y to 1
==30474== Conditional jump or move depends on uninitialised value(s)
==30474== at 0x8048420: test (t10.c:22)
==30474== by 0x8048451: main (t10.c:29)
==30474== ==30474== Use of uninitialised value of size 4
==30474== at 0xB5C5B6: _itoa_word (in /lib/libc-2.8.so)
==30474== by 0xB5FF90: vfprintf (in /lib/libc-2.8.so)
==30474== by 0xB6769F: printf (in /lib/libc-2.8.so)
==30474== by 0x8048436: test (t10.c:23)
==30474== by 0x8048451: main (t10.c:29)
==30474== ==30474== Conditional jump or move depends on uninitialised value(s)
==30474== at 0xB5C5BE: _itoa_word (in /lib/libc-2.8.so)
==30474== by 0xB5FF90: vfprintf (in /lib/libc-2.8.so)
==30474== by 0xB6769F: printf (in /lib/libc-2.8.so)
==30474== by 0x8048436: test (t10.c:23)
==30474== by 0x8048451: main (t10.c:29)
==30474== ==30474== Conditional jump or move depends on uninitialised value(s)
==30474== at 0xB5EADE: vfprintf (in /lib/libc-2.8.so)
==30474== by 0xB6769F: printf (in /lib/libc-2.8.so)
==30474== by 0x8048436: test (t10.c:23)
==30474== by 0x8048451: main (t10.c:29)
==30474== ==30474== Conditional jump or move depends on uninitialised value(s)
==30474== at 0xB60828: vfprintf (in /lib/libc-2.8.so)
==30474== by 0xB6769F: printf (in /lib/libc-2.8.so)
==30474== by 0x8048436: test (t10.c:23)
==30474== by 0x8048451: main (t10.c:29)
==30474== ==30474== Conditional jump or move depends on uninitialised value(s)
==30474== at 0xB5EB88: vfprintf (in /lib/libc-2.8.so)
==30474== by 0xB6769F: printf (in /lib/libc-2.8.so)
==30474== by 0x8048436: test (t10.c:23)
==30474== by 0x8048451: main (t10.c:29)
f2 set y to 13123572
==30474== ==30474== ERROR SUMMARY: 20 errors from 6 contexts (suppressed: 13 from 1)
==30474== malloc/free: in use at exit: 0 bytes in 0 blocks.
==30474== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==30474== For counts of detected errors, rerun with: -v
==30474== All heap blocks were freed -- no leaks are possible.



J #include <stdio.h>
int y;

void f1(void)
{
int x = 1;
y = x;
}

void f2(void)
{
int x;
y = x;
}

void test()
{
f1();
if (y)
printf("f1 set y to %d\n", y);
f2();
if (y)
printf("f2 set y to %d\n", y);
}

main()
{
char buf[16 * 1024];
test();
}