NetBSD-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

vfprintf() issue of printing negative float value



Hi,

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.

This 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.

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. So, to bypass this
Aliasing rules I used ?__may_alias__? attribute as below.


$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.

Please let me know if there are any issues.

Waiting for the reply.

Thank You,
Nikunj


Home | Main Index | Thread Index | Old Index