|
From: Evan L. <sa2...@cy...> - 2007-08-08 09:13:25
|
Nicholas Nethercote wrote:
> So it seems you're passing these partially undefined 16 byte values to
> the write() system call. That lookss like a genuine bug. Just copying
> around undefined data won't cause Valgrind to complain, it only
> complains when you use undefined data in ways that may affect execution,
> and passing the data to a system call like write() is one such case.
I didn't look at the 2005 case in detail but, for the sake of argument,
let's assume that the OP had an array of long doubles that he wanted to
write to a file. Any call to 'write' is going to involve using 'sizeof'
somewhere. He might, for example, have calculated the length of the
array as "num_elements * sizeof(long double)". If gcc reports
sizeof(long double) as 16, and you have 10 elements, you're going to
call 'write' for 160 bytes, which has lots of holes in it. Sure, this
could potentially be an error, but almost certainly isn't.
My case is actually very similar. I need to store long doubles somewhere
in memory, and retrieve them at a later time. The code looks like this:
================================================================
template <typename T>
int TVLBigInt::mp_set_real(BigInt *dst, T src)
{
uint8_t *cptr = (uint8_t *)&src;
...<cut: set Dbits to the number of bits in the templated type>
// **BODGE** fixes valgrind error messages: is there a better
// way to do this?
// if(Dbits == 128)
// Dbits = 80;
for(int i = 0; i < Dbits; i += 8) {
mask = *cptr++; // <--- VALGRIND REPORTS ERROR HERE
mask <<= i;
*dst |= mask;
}
================================================================
This code works, and doesn't depend on an uninitialised value, but
Valgrind reports an error when 'T' is a long double. I don't care that
'mask' will have uninitialised bytes in it; 'mask' will only ever be
used as part of a long double. The code still works if I uncomment the
block that starts with **BODGE**, and Valgrind then doesn't report an error.
But, my point is, Valgrind is being too smart. It 'knows' that a long
double is 80 bits, but I can only rely on what the compiler tells me,
which is that a long double is 128 bits. I don't (semantically) use the
uninitialised bytes, because I only ever operate on long doubles using
C++ operations; I just occasionally need to store and retrieve them from
an unusual place. For this, I have to use sizeof, because that's what
sizeof is for. However, Valgrind gives me hundreds of errors.
Ideally, I think that I need to tell Valgrind to use C's size definition
here, rather than its built-in knowledge. I could potentially find a
system header somewhere that could tell me that a long double is
actually 80 bits, but this wouldn't help: C would still store long
doubles in 16 bytes of memory, and I couldn't correctly operate on
arrays of long doubles. In other words, I still need sizeof (actually, I
never operate on arrays, but you get the idea).
Any ideas?
Thanks -
Evan
|