bug in gcc?

J

jacob navia

#include <stdio.h>

char Fn5973(float arg1,long long arg2)
{
return arg2 - arg1 + arg1 - arg1 + arg1 + arg1 * arg1 - arg1;

}
int main(void)
{
long double mm;
mm = Fn5973(14907.5F,20524);
printf("result of Fn5973=%.20Lg\n",mm);
}
Without optimizations answer is zero
jacob@ubuntu-32:/tmp$ gcc bug1.c -o bug1
jacob@ubuntu-32:/tmp$ ./bug1
result of Fn5973=0

With optimizations answer is -64

jacob@ubuntu-32:/tmp$ gcc -O3 bug1.c -o bug1opt
jacob@ubuntu-32:/tmp$ ./bug1opt
result of Fn5973=-64

jacob@ubuntu-32:/tmp$ gcc -v
Reading specs from /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.2/specs
Configured with: ../gcc-3.2/configure --enable-language=c,c++
Thread model: posix
gcc version 3.2
jacob@ubuntu-32:/tmp$


can anyone infirm/confirm this?

Thanks
 
L

lndresnick

#include <stdio.h>

char Fn5973(float arg1,long long arg2)
{
         return arg2 - arg1 + arg1 - arg1 + arg1 + arg1 * arg1 - arg1;

}

int main(void)
{
         long double mm;
         mm =    Fn5973(14907.5F,20524);
         printf("result of Fn5973=%.20Lg\n",mm);}

Without optimizations answer is zero
jacob@ubuntu-32:/tmp$ gcc bug1.c -o bug1
jacob@ubuntu-32:/tmp$ ./bug1
result of Fn5973=0

With optimizations answer is -64

jacob@ubuntu-32:/tmp$ gcc -O3 bug1.c -o bug1opt
jacob@ubuntu-32:/tmp$ ./bug1opt
result of Fn5973=-64

jacob@ubuntu-32:/tmp$ gcc -v
Reading specs from /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.2/specs
Configured with: ../gcc-3.2/configure --enable-language=c,c++
Thread model: posix
gcc version 3.2
jacob@ubuntu-32:/tmp$

can anyone infirm/confirm this?

Looks like inlining of functions does this:

temp(974)$ gcc -Wall --std=c99 -pedantic -o foo foo.c; foo
result of Fn5973=0
temp(975)$ gcc -Wall --std=c99 -pedantic -O2 -o foo foo.c; foo
result of Fn5973=0
temp(976)$ gcc -Wall --std=c99 -pedantic -O3 -o foo foo.c; foo
result of Fn5973=127
temp(977)$ gcc -Wall --std=c99 -pedantic -O2 -finline-functions -o foo
foo.c; foo
result of Fn5973=127

-David
 
J

jacob navia

jacob navia wrote:

return arg2 - arg1 + arg1 - arg1 + arg1 + arg1 * arg1 - arg1;

Simplifying

return arg2 + arg1 * arg1 - arg1;

arg2 +arg1*arg1-arg1;

20524+14907.5*14907.5-14907.5 --> 222 239 172.75

All this in float precision...

Then transformed to a char!

I do not know if this is a bug.

lcc-win returns -60 both with optimization and without them, but
lcc-win's optimizations aren't those of gcc :)

Is this a bug or not?

MSVC returns the same result as gcc with -O3: -64, both with
and without optimizations.
 
F

Fred

#include <stdio.h>

char Fn5973(float arg1,long long arg2)
{
         return arg2 - arg1 + arg1 - arg1 + arg1 + arg1 * arg1 - arg1;

}

int main(void)
{
         long double mm;
         mm =    Fn5973(14907.5F,20524);
         printf("result of Fn5973=%.20Lg\n",mm);}

Without optimizations answer is zero
jacob@ubuntu-32:/tmp$ gcc bug1.c -o bug1
jacob@ubuntu-32:/tmp$ ./bug1
result of Fn5973=0

With optimizations answer is -64

jacob@ubuntu-32:/tmp$ gcc -O3 bug1.c -o bug1opt
jacob@ubuntu-32:/tmp$ ./bug1opt
result of Fn5973=-64

jacob@ubuntu-32:/tmp$ gcc -v
Reading specs from /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.2/specs
Configured with: ../gcc-3.2/configure --enable-language=c,c++
Thread model: posix
gcc version 3.2
jacob@ubuntu-32:/tmp$

can anyone infirm/confirm this?

I get the same (0 and -64) results using gcc 3.3.5
 
H

Harald van Dijk

jacob said:
#include <stdio.h>

char Fn5973(float arg1,long long arg2)
{
return arg2 - arg1 + arg1 - arg1 + arg1 + arg1 * arg1 - arg1;

}
int main(void)
{
long double mm;
mm = Fn5973(14907.5F,20524);
printf("result of Fn5973=%.20Lg\n",mm);
}
Without optimizations answer is zero
jacob@ubuntu-32:/tmp$ gcc bug1.c -o bug1
jacob@ubuntu-32:/tmp$ ./bug1
result of Fn5973=0

With optimizations answer is -64

jacob@ubuntu-32:/tmp$ gcc -O3 bug1.c -o bug1opt
jacob@ubuntu-32:/tmp$ ./bug1opt
result of Fn5973=-64

The behaviour is undefined because you are converting an out-of-range float
to an integer type in your return statement. There is no single correct
output for this program; all are equally acceptable.
 
J

jacob navia

Harald said:
The behaviour is undefined because you are converting an out-of-range float
to an integer type in your return statement. There is no single correct
output for this program; all are equally acceptable.
20524+14907.5*14907.5-14907.5 --> 222 239 172.75

Nowhere there is an out of range float since FLT_MAX is

3.402823466e+38F
 
J

jacob navia

Harald said:
The behaviour is undefined because you are converting an out-of-range float
to an integer type in your return statement. There is no single correct
output for this program; all are equally acceptable.

You mean out of range floating point value for char...

OK, now I see.
 
C

Carl

jacob said:
20524+14907.5*14907.5-14907.5 --> 222 239 172.75

Nowhere there is an out of range float since FLT_MAX is

3.402823466e+38F

Correct me if I am mistaken, but there are only 23 bits in the mantissa,
which would mean there are only about ~8 million unique mantissas. That
would the last few bits would be lost.
 
J

jacob navia

Carl said:
Correct me if I am mistaken, but there are only 23 bits in the mantissa,
which would mean there are only about ~8 million unique mantissas. That
would the last few bits would be lost.

No, the error is that the number doesn't fit in a char of course.
Then, since this is UB, any result is valid. That was the
point I was missing
 
M

Martin Ambuhl

jacob said:
20524+14907.5*14907.5-14907.5 --> 222 239 172.75

Nowhere there is an out of range float since FLT_MAX is

3.402823466e+38F

I suspect that CHAR_MAX < 222239172.75
After discarding the fractional part, 222239172 must be less than
CHAR_MAX to have defined behavior.
The floating-point value is out-of-range for conversion to char.
 
E

Eric Sosman

jacob said:
jacob navia wrote:

return arg2 - arg1 + arg1 - arg1 + arg1 + arg1 * arg1 - arg1;

Simplifying

return arg2 + arg1 * arg1 - arg1;

arg2 +arg1*arg1-arg1;

20524+14907.5*14907.5-14907.5 --> 222 239 172.75

That's 1101001111110001100111000100.11 in binary, a number
with thirty significant bits. Rounding to the twenty-four
bits that are typical of most floats nowadays loses the low-
order six bits, giving 110100111111000110011100(2) * 16(10),
or 222239168. (Rounding the result might not be quite right,
since the intermediate calculations are themselves rounded --
I'll leave that computation as an exercise for the student.)

With sufficiently aggressive optimization, the compiler
may "see" that the whole computation involves only constants,
and may choose to pre-compute the result at compile time.
The compiler's computations are not necessarily carried out
in the same floating-point precision as would obtain at run
time, so the precomputed result might not be identical to the
one you'd obtain with unoptimized code. For example, if the
compiler performs the computation using a double with fifty-
three fraction bits, no bits will be lost to rounding and
the low-order four integer bits will be 0100 instead of 0000.
All this in float precision...

Then transformed to a char!

On most implementations, either char is unsigned and
CHAR_MAX is 255, or char is signed and CHAR_MAX is 127. In
the first case, the value 222239168 (if you get it) would
convert to a char with the value 192. In the second case,
the result is implementation-defined or a signal is raised.
Is this a bug or not?

Not on the evidence offered.
 
L

lawrence.jones

jacob navia said:
#include <stdio.h>

char Fn5973(float arg1,long long arg2)
{
return arg2 - arg1 + arg1 - arg1 + arg1 + arg1 * arg1 - arg1;

}

You can almost certainly simplify that to arg2 + arg1 * arg1 - arg1
without changing the result.
int main(void)
{
long double mm;
mm = Fn5973(14907.5F,20524);
printf("result of Fn5973=%.20Lg\n",mm);
}
Without optimizations answer is zero
With optimizations answer is -64

With gcc 2.95.2, I get -60 and -64, which would appear to be the "right"
answers, assuming typical data formats. If the expression is evaluated
to double precision (which is allowed, but not required), the result is
exact and is 222239172.75, which is too large to fit in a char so the
result is officially undefined but typically results in -60. If,
however, the expression is evaluated to float precision (which is also
allowed), the result is approximate and is 222239168, which typically
results in -64. Gcc has been known to play fast and loose with floating
point precision, particularly on the Intel platforms. You may be able
to get consistent results for the undefined behavior by using the
appropriate compile options to get it to follow the official rules, but
there are no guarantees.
 
K

Keith Thompson

Eric Sosman said:
On most implementations, either char is unsigned and
CHAR_MAX is 255, or char is signed and CHAR_MAX is 127. In
the first case, the value 222239168 (if you get it) would
convert to a char with the value 192. In the second case,
the result is implementation-defined or a signal is raised.

Not quite. If a conversion from a floating-point type to an integral
type would yield a value outside the range of the integral type, the
behavior is undefined, even if the target type is unsigned. C99
6.3.1.4p1.
 
E

Eric Sosman

Keith said:
Not quite. If a conversion from a floating-point type to an integral
type would yield a value outside the range of the integral type, the
behavior is undefined, even if the target type is unsigned. C99
6.3.1.4p1.

Thanks for the correction. Then in Jacob's program, *any*
outcome is "correct" and there is no possibility of a compiler
bug (from the C standpoint, anyhow; the compiler may have given
promises beyond the Standard's, and could be failing to keep
those promises). It's not contingent on the signedness of char.
 
J

jacob navia

Thanks to all people that answered. The result is undefined
since the program tries to mut a number (severel hundred
millions) into a char. This is UB.

I got this from a huge program generated by a program I am writing
to test lcc-win. This program will generate random operations in
thousands of automatically generated functions.

Now, I have to check that the generated types do not invoke
UB. If the result type is char, I have to constrain
the result to be
CHAR_MIN <= result = CHAR_MAX
obviously, before returning.

Still, I have discovered several bugs in lcc-win this way.

The problem with my test-suites is that they are actually
a known bug database. Every bug of lcc-win and from gcc
and other compilers have been stored there. (Well only
the ones available to me of course).

But that is a skewed sample. Using automatically generated
random code is a far better way to test for unknown bugs.

Generating a 1.5MB huge program takes less than a second!

This allows me to look for new bugs, bugs that do NOT
appear in the bug database.
 
K

Kaz Kylheku

Reading specs from /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.2/specs
Configured with: ../gcc-3.2/configure --enable-language=c,c++
Thread model: posix
gcc version 3.2
jacob@ubuntu-32:/tmp$

can anyone infirm/confirm this?

Pointless. GCC 3.2 is old. The newest version of GCC 3 is 3.4.6 and this is an
``end of life'' version. Even if you reproduce the problem with 3.4.6, nothing
is going to happen upstream from you; there won't be a 3.4.7.

GCC 4.4 was released last week; try it with that one.
 
L

lawrence.jones

jacob navia said:
I got this from a huge program generated by a program I am writing
to test lcc-win. This program will generate random operations in
thousands of automatically generated functions.

Some guys at DEC did a bunch of research along those lines about the
same time as the original ANSI C standard was published (I remember them
making a presentation to the committee on their approach and some
anecdotes about bugs they'd found in their compiler). If you're
interested, Google for William McKeeman's paper "Differential Testing
for Software" as a starting point.
 
D

Dik T. Winter

> 20524+14907.5*14907.5-14907.5 --> 222 239 172.75

That numbers is not representable as a single precision floating-point
number. So when you convert it to char it depends on how the conversion
is performed, is it first calculated in floating-point and next rounded
up, or down, or is the conversion done from double precision or extended
precision? All are allowed.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top