|
From: Edward M. <Edw...@ce...> - 2004-04-30 17:03:01
|
Hi, A colleague of mine has found some problems reported in his code, and he doesn't think that it's too serious. I would like to check that he is correct, and since I don't really know how valgrind works at a fine level, I was wondering if I could ask the list? The error is: ==30741== Conditional jump or move depends on uninitialised value(s) ==30741== at 0x4202D15A: __strtol_internal (in /lib/i686/libc-2.2.5.so) ==30741== by 0x64FB7C66: LArFCALCalculatorBase::GetElectrodes() (/usr/include/stdlib.h:301) ==30741== by 0x64FB14AB: LArFCAL1Calculator::LArFCAL1Calculator() (../src/LArFCAL1Calculator.cc:31) ==30741== by 0x64FB1238: LArFCAL1Calculator::GetInstance() (../src/LArFCAL1Calculator.cc:16) His response was that it looked like there were two char[3] arrays, but the last element of the array was unitialised, causing the valgrind error. He believed that compilers should normally initialize a character array to binary zero and so it shouldn't be a problem. My understanding of valgrind was that it ran the machine code, and so if it reports an error then the compiler HASN'T initialize the memory at all. Am I correct? Cheers, Ed |
|
From: David H. <dw...@ov...> - 2004-04-30 17:22:28
|
> His response was that it looked like there were two char[3]
> arrays, but the last element of the array was unitialised,
> causing the valgrind error. He believed that compilers
> should normally initialize a character array to
> binary zero and so it shouldn't be a problem.
In general if the array is 'on the stack', i.e. a local
variable within the scope of a function call, then the
variables are NOT initialized.
Go ahead and take a look at the assembly output, if you
make sure you haven't omitted frame pointers, then you'll
see the compiler setup the frame pointer, and then
move the frame pointer by an amount equivalent to the
number of bytes of local variables. Variables in
the source are referenced then with respect to the
frame pointer. There is usually NO initialization
of these variables.
so ideally, you want to code up something like
int some_function(int some_arg)
{
char str[3] = {0, 0, 0};
....
if (some_condition) {
str[0] = 1;
str[1] = 2;
/* no assignment to str[3] */
/* call a function, passing it str */
some_other_function(str);
}
}
and in this case, all variables are initilized before
passing the array to another function.
Cheers
Dave
|
|
From: Edward M. <Edw...@ce...> - 2004-04-30 17:55:28
|
On Friday 30 April 2004 19:26, David Hawkins wrote: > > His response was that it looked like there were two char[3] > > arrays, but the last element of the array was unitialised, > > causing the valgrind error. He believed that compilers > > should normally initialize a character array to > > binary zero and so it shouldn't be a problem. > > In general if the array is 'on the stack', i.e. a local > variable within the scope of a function call, then the > variables are NOT initialized. > > Go ahead and take a look at the assembly output, if you > make sure you haven't omitted frame pointers, then you'll > see the compiler setup the frame pointer, and then > move the frame pointer by an amount equivalent to the > number of bytes of local variables. Variables in > the source are referenced then with respect to the > frame pointer. There is usually NO initialization > of these variables. Wow. Thanks for the prompt response. On monday I will indeed have a go at reading the assembly output. Can I just ask though whether if valgrind reporting this means that it is definitely uninitialized? I mean, if this error crops up again and again (which it probably will) if I *know* that valgrind reports it correctly then I can just tell people that they have a problem they must fix, and I don't need to bother with proving it by assembly. Cheers (and thanks again for replying so fast and so comprehensively) Ed |
|
From: David H. <dw...@ov...> - 2004-04-30 18:21:39
|
Hiya,
> Wow. Thanks for the prompt response. On monday I will indeed have a go at
> reading the assembly output.
Have fun!
> Can I just ask though whether if valgrind reporting this means that it is
> definitely uninitialized? I mean, if this error crops up again and again
> (which it probably will) if I *know* that valgrind reports it
> correctly then I can just tell people that they have a problem they must
fix,
> and I don't need to bother with proving it by assembly.
>
> Cheers (and thanks again for replying so fast and so comprehensively)
I've only started to use Valgrind myself, but I would consider the valgrind
warning is correct. Note that it is a warning and may not cause a
problem - today ... but who knows when ... make sure you program
defensively, and you'll be a happy programmer.
As a suggestion, here's another good technique:
lets say I have a struct:
typedef struct {
int a;
int b;
int c:
float d;
} astruct_t;
and I use dynamic allocation:
astruct_t *ptr;
ptr = (astruct_t *) malloc(sizeof(astruct_t));
<error check goes here>
memset(ptr, 0, sizeof(astruct_t));
ptr->b = 5;
ptr->d = 0.0;
By using memset, I can ensure that all members of the structure
are initilized to 0x00000000. However, if any of the members need
a different default, I change only the ones that require it.
This is a lifesaver when you add a new member to your structure.
The code already initializes it to zero, and with luck that is
valid. Otherwise, start welcoming in the weird and hard to find
bugs.
Cheers
Dave
|
|
From: Nicholas N. <nj...@ca...> - 2004-04-30 22:23:53
|
On Fri, 30 Apr 2004, David Hawkins wrote:
> > Can I just ask though whether if valgrind reporting this means that it is
> > definitely uninitialized? I mean, if this error crops up again and again
> > (which it probably will) if I *know* that valgrind reports it
> > correctly then I can just tell people that they have a problem they must fix,
> > and I don't need to bother with proving it by assembly.
The short answer I would give: trust Valgrind. It does sometimes give
false positives, but they're pretty rare.
> As a suggestion, here's another good technique:
>
> lets say I have a struct:
>
> typedef struct {
> int a;
> int b;
> int c:
> float d;
> } astruct_t;
>
> and I use dynamic allocation:
>
> astruct_t *ptr;
>
> ptr = (astruct_t *) malloc(sizeof(astruct_t));
> <error check goes here>
>
> memset(ptr, 0, sizeof(astruct_t));
> ptr->b = 5;
> ptr->d = 0.0;
>
> By using memset, I can ensure that all members of the structure
> are initilized to 0x00000000. However, if any of the members need
> a different default, I change only the ones that require it.
Or you could use calloc(), which does zero the memory. Then there's no
chance for screwing up the memset call (it's easy to accidentally swap the
last two args).
N
|
|
From: Gerald G. <ger...@ya...> - 2004-05-02 06:56:10
|
> Or you could use calloc(), which does zero the > memory. Then there's no > chance for screwing up the memset call (it's easy to > accidentally swap the > last two args). > I wouldn't rely on calloc for initializing my pointer to zero, I'd take my chances with memset though. __________________________________ Do you Yahoo!? Win a $20,000 Career Makeover at Yahoo! HotJobs http://hotjobs.sweepstakes.yahoo.com/careermakeover |
|
From: Robert W. <rj...@du...> - 2004-05-02 07:23:21
|
> I wouldn't rely on calloc for initializing my pointer > to zero, I'd take my chances with memset though. Huh? Why not? -- Robert Walsh Amalgamated Durables, Inc. "We bring dead things to life" |