Open Quuxplusone opened 11 years ago
Bugzilla Link | PR16825 |
Status | NEW |
Importance | P normal |
Reported by | Michael Hecht (michael.hecht@jmp.com) |
Reported on | 2013-08-07 12:17:32 -0700 |
Last modified on | 2013-08-30 19:06:57 -0700 |
Version | unspecified |
Hardware | Macintosh MacOS X |
CC | jrose@belkadan.com, llvm-bugs@lists.llvm.org, michael.morrell@intel.com |
Fixed by commit(s) | |
Attachments | |
Blocks | |
Blocked by | |
See also |
The analyzer doesn't model floating-point values at all right now, even for repeated checks. Definitely a limitation.
So, would this be the same reason I get a "Undefined or garbage value returned
to caller" warning from this (using checker-275 on a Mac):
float foo(float *data)
{
double newData[2];
newData[0] = ((double*) data)[0];
newData[1] = ((double*) data)[1];
data = newData;
return data[1];
}
or should I file a new bug?
No, that's because you can't mix float * and double * in any sensible way. The
upper 32 bits of a double don't make a sensible float.
I'm not sure what you mean. I did leave off a cast -- the last assignment
should read "data = (float *)newData", but I'm not sure that will make a
difference. The parameter can be treated as an array of floats or an array of
doubles legitimately, I believe.
Also, if I try different returns (trying all 4 -- data[0], data[1], data[2],
and data[3]), I only see the complaint with data[1] and data[3]. No complaint
from data[0] or data[2].
Looking at the compiled code, the compiler is OK with this (it didn't give a
warning -- I used -Wall and -Wextra).
The compiler will do something, but exactly what is pretty much random.
Converting a double* to a float* and then loading from it means "treat this
array as if it contains floats instead of doubles". This is completely
incorrect code, but unfortunately the compiler won't warn about it if you put
the cast in, because it assumes you know what you're doing.
You are basically doing this:
float foo(float *data) {
char *rawData = (char *)data;
double newData[2];
char *rawNewData = (char *)newData;
memcpy(&rawNewData[0], &rawData[0], 8);
memcpy(&rawNewData[8], &rawData[8], 8);
float result;
memcpy(&result, &rawNewData[4], 4);
return result;
}
...which happens to return data[1], because copying 8 bytes from &data[0] is
copying data[0] and data[1] over newData[0], and copying ((float *)newData)[1]
pulls out the second half of newData[0].
Please do not do this.