|
From: Dave N. <dc...@us...> - 2006-02-16 00:33:13
|
I was creating an example for a valgrind ppc demo and was surprised to
see that a dereference of an uninitialized global data variable did not
result in an error from valgrind, but when the same variable was
propagated to exit() via the return value of main() the error was
detected. Is this a bug or am I misunderstanding what should be
happening? I expected to see uninitialized value errors around lines
10-14 and 20-22 in the program listed below.
I am seeing this on a IBM Power5 running SUSE LINUX Enterprise Server 9
both using Valgrind 3.1.0 and an svn build from Feb 7.
uname -a: Linux elm3b149 2.6.5-7.97-pseries64.nm #1 SMP Thu Mar 31
I see the same behavior on the 32-bit program and the 64-bit program.
==18069== Conditional jump or move depends on uninitialised value(s)
==18069== at 0x1000045C: proc (uninit.c:17)
==18069== by 0x100004B8: main (uninit.c:31)
==18069==
==18069== Invalid write of size 4
==18069== at 0x100004C8: main (uninit.c:33)
==18069== Address 0xFEFFDFBC is just below the stack ptr. To suppress,
use: --workaround-gcc296-bugs=yes
==18069==
==18069== Syscall param exit_group(exit_code) contains uninitialised byte(s)
==18069== at 0xFF05720: _Exit (in /lib/tls/libc.so.6)
==18069== by 0xFEA654C: exit (in /lib/tls/libc.so.6)
==18069== by 0xFE8EAC4: (below main) (in /lib/tls/libc.so.6)
------------------ uninit.c -----------------------------
int *bad_ptr;
int uninit_int1;
int uninit_int2;
void proc(int arg)
{
int proc_local;
/* access uninit_global */
if (uninit_int1 > 0) { /* WHY NO UNINIT ERROR HERE? */
/* WHY NO UNINIT ERROR ON ONE OF THE */
uninit_int1 += 1; /* BRANCHES ? */
} else {
uninit_int1 += 2;
}
/* read propagated value from uninit_local argument */
if (arg != 0) {
/* WHY NO UNINIT ERROR ON ONE OF THE */
uninit_int2 = arg+2; /* BRANCHES ? */
} else {
uninit_int2 = arg+1;
}
/* save pointer to local variable */
bad_ptr = &proc_local;
}
int main()
{
int uninit_local;
proc(uninit_local);
*bad_ptr = 1;
return uninit_int1 + uninit_int2;
}
------------------ valgrind -v output -------------------
==18049== Memcheck, a memory error detector.
==18049== Copyright (C) 2002-2005, and GNU GPL'd, by Julian Seward et
al.==18049== Using LibVEX rev 1559, a library for dynamic binary
translation.
==18049== Copyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP.
==18049== Using valgrind-3.2.0.SVN, a dynamic binary instrumentation
framework.
==18049== Copyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et
al.==18049==
--18049-- Command line
--18049-- uninit
--18049-- Startup, with flags:
--18049-- -v
--18049-- Contents of /proc/version:
--18049-- Linux version 2.6.5-7.97-pseries64.nm (geeko@buildhost) (gcc
version 3.3.3 (SuSE Linux)) #1 SMP Thu Mar 31 10:55:11 PST 2005
--18049-- Arch and hwcaps: PPC32, ppc32-int-flt-FX-GX
--18049-- Valgrind library directory:
/home/dcn/svn/nightly/valgrind/.in_place/
--18049-- Reading syms from /lib/ld-2.3.3.so (0x4100000)
--18049-- Reading syms from /home/dcn/demo/uninit (0x10000000)
--18049-- Reading syms from
/home/dcn/svn/nightly/valgrind/memcheck/memcheck-ppc32-linux (0x70000000)
--18049-- object doesn't have a dynamic symbol table
--18049-- Reading suppressions file:
/home/dcn/svn/nightly/valgrind/.in_place//default.supp
--18049-- REDIR: 0x4113040 (strlen) redirected to 0x70027F60
(vgPlain_ppc32_linux_REDIR_FOR_strlen)
--18049-- Reading syms from
/home/dcn/svn/nightly/valgrind/coregrind/vgpreload_core-ppc32-linux.so
(0xFFDF000)
--18049-- Reading syms from
/home/dcn/svn/nightly/valgrind/memcheck/vgpreload_memcheck-ppc32-linux.so
(0xFFBA000)
--18049-- Reading syms from /lib/tls/libc.so.6 (0xFE73000)
--18049-- REDIR: 0xFEE7300 (rindex) redirected to 0xFFBD164 (rindex)
==18049== Conditional jump or move depends on uninitialised value(s)
==18049== at 0x1000045C: proc (uninit.c:17)
==18049== by 0x100004B8: main (uninit.c:31)
==18049==
==18049== Invalid write of size 4
==18049== at 0x100004C8: main (uninit.c:33)
==18049== Address 0xFEFFDFBC is just below the stack ptr. To suppress,
use: --workaround-gcc296-bugs=yes
==18049==
==18049== Syscall param exit_group(exit_code) contains uninitialised byte(s)
==18049== at 0xFF05720: _Exit (in /lib/tls/libc.so.6)
==18049== by 0xFEA654C: exit (in /lib/tls/libc.so.6)
==18049== by 0xFE8EAC4: (below main) (in /lib/tls/libc.so.6)
--18049-- REDIR: 0xFEE11E4 (free) redirected to 0xFFBC0AC (free)
--18049-- REDIR: 0xFEE8044 (memset) redirected to 0xFFBE210 (memset)
==18049==
==18049== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 6 from 2)
==18049==
==18049== 1 errors in context 1 of 3:
==18049== Syscall param exit_group(exit_code) contains uninitialised byte(s)
==18049== at 0xFF05720: _Exit (in /lib/tls/libc.so.6)
==18049== by 0xFEA654C: exit (in /lib/tls/libc.so.6)
==18049== by 0xFE8EAC4: (below main) (in /lib/tls/libc.so.6)
==18049==
==18049== 1 errors in context 2 of 3:
==18049== Invalid write of size 4
==18049== at 0x100004C8: main (uninit.c:33)
==18049== Address 0xFEFFDFBC is just below the stack ptr. To suppress,
use: --workaround-gcc296-bugs=yes
==18049==
==18049== 1 errors in context 3 of 3:
==18049== Conditional jump or move depends on uninitialised value(s)
==18049== at 0x1000045C: proc (uninit.c:17)
==18049== by 0x100004B8: main (uninit.c:31)
--18049--
--18049-- supp: 4 glibc-2.3.5-on-SuSE-10.0-(PPC)-1
--18049-- supp: 2 Ugly strchr error in /lib/ld-2.3.3.so
==18049==
==18049== IN SUMMARY: 3 errors from 3 contexts (suppressed: 6 from 2)
==18049==
==18049== malloc/free: in use at exit: 0 bytes in 0 blocks.
==18049== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==18049==
==18049== All heap blocks were freed -- no leaks are possible.
--18049-- memcheck: sanity checks: 0 cheap, 1 expensive
--18049-- memcheck: auxmaps: 0 auxmap entries (0k, 0M) in use
--18049-- memcheck: auxmaps: 0 searches, 0 comparisons
--18049-- memcheck: secondaries: 17 issued (1088k, 1M)
--18049-- memcheck: secondaries: 18 accessible and distinguished
(1152k, 1M)
--18049-- translate: fast SP updates identified: 205 ( 61.3%)
--18049-- translate: generic_known SP updates identified: 100 ( 29.9%)
--18049-- translate: generic_unknown SP updates identified: 29 ( 8.6%)
--18049-- tt/tc: 3,125 tt lookups requiring 3,146 probes
--18049-- tt/tc: 3,125 fast-cache updates, 6 flushes
--18049-- transtab: new 1,422 (39,644 -> 664,380; ratio 167:10)
[0 scs]
--18049-- transtab: dumped 0 (0 -> ??)
--18049-- transtab: discarded 20 (864 -> ??)
--18049-- scheduler: 23,217 jumps (bb entries).
--18049-- scheduler: 0/1,775 major/minor sched events.
--18049-- sanity: 1 cheap, 1 expensive checks.
--18049-- exectx: 30,011 lists, 7 contexts (avg 0 per list)
--18049-- exectx: 9 searches, 2 full compares (222 per 1000)
--18049-- exectx: 0 cmp2, 14 cmp4, 0 cmpAll
------------------ uninit.c -----------------------------
int *bad_ptr;
int uninit_int1;
int uninit_int2;
void proc(int arg)
{
int proc_local;
/* access uninit_global */
if (uninit_int1 > 0) { /* WHY NO UNINIT ERROR HERE? */
/* WHY NO UNINIT ERROR ON ONE OF THE */
uninit_int1 += 1; /* BRANCHES ? */
} else {
uninit_int1 += 2;
}
/* read propagated value from uninit_local argument */
if (arg != 0) {
/* WHY NO UNINIT ERROR ON ONE OF THE */
uninit_int2 = arg+2; /* BRANCHES ? */
} else {
uninit_int2 = arg+1;
}
/* save pointer to local variable */
bad_ptr = &proc_local;
}
int main()
{
int uninit_local;
proc(uninit_local);
*bad_ptr = 1;
return uninit_int1 + uninit_int2;
}
|
|
From: John R.
|
Dave Nomura wrote: > I was creating an example for a valgrind ppc demo and was surprised to > see that a dereference of an uninitialized global data variable did not > result in an error from valgrind, but when the same variable was > propagated to exit() via the return value of main() the error was > detected. Is this a bug or am I misunderstanding what should be > happening? Global data is always initialized; it can never be uninitialized except via explicit copying from some other uninitialized data. If the source code contains no explicit initialization: int foo; /* at top level (file scope) */ then as far as guaranteed values are concerned it is equivalent to: int foo = 0; The first case (no explicit initialization) resides in .bss which is cleared to zero upon instantiation by the kernel or by the runtime module loader ld-linux.so. The second case (explicit initialization) resides in .data, except that some recent compiler tools put explicit initialization to 0 into .bss because in many cases it is an optimization (of space in the filesystem). However, the behavior with respect to data caches at runtime might be different. -- |
|
From: Nicholas N. <nj...@cs...> - 2006-02-16 02:52:50
|
On Wed, 15 Feb 2006, John Reiser wrote: >> I was creating an example for a valgrind ppc demo and was surprised to >> see that a dereference of an uninitialized global data variable did not >> result in an error from valgrind, but when the same variable was >> propagated to exit() via the return value of main() the error was >> detected. Is this a bug or am I misunderstanding what should be >> happening? > > Global data is always initialized; it can never be uninitialized > except via explicit copying from some other uninitialized data. John is right. Also, if the global variable became uninitialized somehow, it's possible that the dereference wasn't complained about because it didn't affect the program's behaviour -- ie. it wasn't used as a pointer, or as input to a system call, or in a conditional branch. For example, just copying around uninitialized data doesn't elicit complaints from Memcheck. See http://www.valgrind.org/docs/memcheck2005.pdf for details. Nick |
|
From: Dave N. <dc...@us...> - 2006-02-16 17:21:42
|
So if Valgrind treats global BSS data as initialized, why does valgrind complain when my main program returns this global BSS as a return value? from main(): return uninit_int1 + uninit_int2; =18069== Syscall param exit_group(exit_code) contains uninitialised byte(s) ==18069== at 0xFF05720: _Exit (in /lib/tls/libc.so.6) ==18069== by 0xFEA654C: exit (in /lib/tls/libc.so.6) ==18069== by 0xFE8EAC4: (below main) (in /lib/tls/libc.so.6) John Reiser wrote: > Dave Nomura wrote: > >>I was creating an example for a valgrind ppc demo and was surprised to >>see that a dereference of an uninitialized global data variable did not >>result in an error from valgrind, but when the same variable was >>propagated to exit() via the return value of main() the error was >>detected. Is this a bug or am I misunderstanding what should be >>happening? > > > Global data is always initialized; it can never be uninitialized > except via explicit copying from some other uninitialized data. > > If the source code contains no explicit initialization: > int foo; /* at top level (file scope) */ > then as far as guaranteed values are concerned it is equivalent to: > int foo = 0; > The first case (no explicit initialization) resides in .bss > which is cleared to zero upon instantiation by the kernel or by > the runtime module loader ld-linux.so. The second case (explicit > initialization) resides in .data, except that some recent compiler > tools put explicit initialization to 0 into .bss because in many > cases it is an optimization (of space in the filesystem). However, > the behavior with respect to data caches at runtime might be different. > |
|
From: Dave N. <dc...@us...> - 2006-02-16 17:32:42
|
OK, I see now what is going on. valgrind treats global data as initialized but my test program assigned an uninitialized variable to the global variable that was used in the return. Thanks for the reply! John Reiser wrote: > Dave Nomura wrote: > >>I was creating an example for a valgrind ppc demo and was surprised to >>see that a dereference of an uninitialized global data variable did not >>result in an error from valgrind, but when the same variable was >>propagated to exit() via the return value of main() the error was >>detected. Is this a bug or am I misunderstanding what should be >>happening? > > > Global data is always initialized; it can never be uninitialized > except via explicit copying from some other uninitialized data. > > If the source code contains no explicit initialization: > int foo; /* at top level (file scope) */ > then as far as guaranteed values are concerned it is equivalent to: > int foo = 0; > The first case (no explicit initialization) resides in .bss > which is cleared to zero upon instantiation by the kernel or by > the runtime module loader ld-linux.so. The second case (explicit > initialization) resides in .data, except that some recent compiler > tools put explicit initialization to 0 into .bss because in many > cases it is an optimization (of space in the filesystem). However, > the behavior with respect to data caches at runtime might be different. > |