NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lib/44449: vfprintf() prints incorrect negative float value for GCC-4.5
>Number: 44449
>Category: lib
>Synopsis: vfprintf() prints incorrect negative float value for GCC-4.5
>Confidential: no
>Severity: critical
>Priority: high
>Responsible: lib-bug-people
>State: open
>Class: support
>Submitter-Id: net
>Arrival-Date: Mon Jan 24 07:25:00 +0000 2011
>Originator: Amol Pise
>Release: NetBsd 4.0
>Organization:
Tata Elxsi limited
>Environment:
Linux 10.4.3.29 2.6.29.6-rt24-alp_nl-beagleboard #2 PREEMPT Mon Jan 17 15:44:46
IST 2011 armv7l GNU/Linux
>Description:
I have found one issue in stdio module of NetBSD library while compiling it for
ARMv7a (Cortex architecture) using the GNU GCC-4.5 toolchain.
The issue is while printing negative float value and the float value
greater than 9.0, vfprintf() prints malicious characters.
Later, I modified the optimization flag from O2 to O1 and build the NetBsd
library and found the issue is resolved.
On these lines further I have analyzed and suspected this ?wrong optimization?
may be cause due to ?strict aliasing?
The man page of GNU GCC says about ?strict aliasing?:
?-fstrict-aliasing
Allows the compiler to assume the strictest aliasing rules
applicable to the language being compiled. For C (and C++), this activates
optimizations based on the type of expressions. In particular, an object of
one type is assumed never to reside at the same address as an object of a
different type, unless the types are almost the same. For example, an
"unsigned int" can alias an "int", but not a "void*" or a "double". A
character type may alias any other type. ?
To confirm this I have build NetBsd library using ?-fno-strict-aliasing? flag
with O2 optimization to suppress the ?strict aliasing? and found the above
issue is resolved.
Further I have investigated it in the NetBsd source and found the flow of
vfprintf as below:
Vfprintf()
---> __vfprintf_unlocked
---> cvt()
---> __dtoa
The dtoa() implementation in NetBsd as follows:
$cat src/lib/libc/gdtoa/dtoa.c
{{{
148: if (word0(d) & Sign_bit) {
149: /* set sign for everything, including 0's and NaNs */
150: *sign = 1;
151: word0(d) &= ~Sign_bit; /* clear sign bit */
152: }
}}}
$cat src/lib/libc/gdtoa/gdtoaimp.h
{{{
176: #define ULong uint32_t
:
278:
279: typedef union { double d; ULong L[2]; } U;
:
291: #ifdef IEEE_LITTLE_ENDIAN
292: #define word0(x) ( /* LINTED */ (U*)&x)->L[1]
293: #define word1(x) ( /* LINTED */ (U*)&x)->L[0]
}}}
Since at line:292 its breaking the strict aliasing rule. Cuases floating point
number convetion fails.
>How-To-Repeat:
This issue can be reproduce using the sample test as below:
% Cat Sample_vfprintf.c
{{{
#include <stdio.h>
#include <stdarg.h>
void format (FILE * stream, char * format, ...)
{
va_list args;
va_start (args, format);
vfprintf (stream, format, args);
va_end (args);
}
int main ()
{
FILE * fp;
fp = fopen ("myfile.txt","w");
format (fp,"Call with %f \n",-3.14);
format (fp,"Call with %f \n",10.0);
fclose (fp);
return 0;
}
}}}
The output on beagleboard target is:
{{{
-bash-3.2# ./sample_vfprintf
-bash-3.2# cat myfile.txt
Call with 0.,0000
Call with :.000000
}}}
>From the above sample it is seen that for negative float value and the float
>value greater than 9.0, vfprintf() prints malicious characters.
>Fix:
To bypass this strict aliasing rules I used ?__may_alias__? attribute as below
(This is the workaround fix).
$cat src/lib/libc/gdtoa/gdtoaimp.h
{{{
- typedef union { double d; ULong L[2]; } U;
+ typedef union { double d; ULong L[2]; } __attribute__((__may_alias__)) U;
}}}
With these changes vfprintf() is able to convert floating point number
correctly without any issue.
Home |
Main Index |
Thread Index |
Old Index