This is the mail archive of the newlib@sources.redhat.com mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA: fix vfscanf problem with long numbers


Patch checked in. I am having some problems testing out the powerpc version so I didn't want to delay checking it in.

-- Jeff J.

Jeff Johnston wrote:
Thanks Joern. I will massage the fix to apply to the powerpc version and then check it in.

-- Jeff J.

Joern Rennecke wrote:

The following testcase fails with newlib on configurations without
long doubles > 64 bit (e.g. sh-elf) because the buffer used by vsscanf
overflows:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int
main ()
{
  char s[1100];
  int i;
  double d;

  memset (s, '0', 1024);
  strcpy (s+1024, "42");
  sscanf(s, "%d", &i);
  if (i != 42)
    abort ();
  s[1] = '.';
  strcpy (s+1024, "1e1023");
  sscanf(s, "%lf", &d);
  if (d != 1.0)
    abort ();
  exit (0);
}

The floating point failure is actually a regression intruduced by this
patch:

2003-03-20 Jeff Johnston <jjohnstn@redhat.com>

* libc/stdio/vfscanf.c (__svfscanf_r): For floating point conversion,
count all characters used to create number against maximum width.
* libc/machine/powerpc/vfscanf.c (__svfscanf_r): Ditto.


The following patch both this regression and the long-standing failure
for integers:

2004-04-21 J"orn Rennecke <joern.rennecke@superh.com>

    * libc/stdio/vfscanf.c (NNZDIGITS): New define.
    (__svfscanf_r): In integer conversions, leave out leading zeroes
    which are not part of a base prefix.
    Keep track of width truncation to fit into buf, not counting left-out
    zeroes against width till the truncation has been compensated for.

Index: vfscanf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/vfscanf.c,v
retrieving revision 1.18
diff -p -r1.18 vfscanf.c
*** vfscanf.c    2 Apr 2004 00:59:17 -0000    1.18
--- vfscanf.c    21 Apr 2004 16:08:01 -0000
*************** extern _LONG_DOUBLE _strtold _PARAMS((ch
*** 179,184 ****
--- 179,185 ----
    #define    PFXOK        0x200    /* 0x prefix is (still) legal */
  #define    NZDIGITS    0x400    /* no zero digits detected */
+ #define    NNZDIGITS    0x800    /* no non-zero digits detected */
    /*
   * Conversion types.
*************** __svfscanf_r (rptr, fp, fmt0, ap)
*** 759,775 ****
        continue;
        case CT_INT:
        /* scan an integer as if by strtol/strtoul */
  #ifdef hardway
        if (width == 0 || width > sizeof (buf) - 1)
-         width = sizeof (buf) - 1;
  #else
        /* size_t is unsigned, hence this optimisation */
!       if (--width > sizeof (buf) - 2)
!         width = sizeof (buf) - 2;
!       width++;
  #endif
!       flags |= SIGNOK | NDIGITS | NZDIGITS;
        for (p = buf; width; width--)
          {
            c = *fp->_p;
--- 760,779 ----
        continue;
        case CT_INT:
+     {
        /* scan an integer as if by strtol/strtoul */
+       unsigned width_left = 0;
  #ifdef hardway
        if (width == 0 || width > sizeof (buf) - 1)
  #else
        /* size_t is unsigned, hence this optimisation */
!       if (width - 1 > sizeof (buf) - 2)
  #endif
!         {
!           width_left = width - (sizeof (buf) - 1);
!           width = sizeof (buf) - 1;
!         }
!       flags |= SIGNOK | NDIGITS | NZDIGITS | NNZDIGITS;
        for (p = buf; width; width--)
          {
            c = *fp->_p;
*************** __svfscanf_r (rptr, fp, fmt0, ap)
*** 789,804 ****
             * will turn it off if we have scanned any nonzero digits).
             */
          case '0':
            if (base == 0)
              {
                base = 8;
                flags |= PFXOK;
              }
            if (flags & NZDIGITS)
!             flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
!           else
!             flags &= ~(SIGNOK | PFXOK | NDIGITS);
!           goto ok;
              /* 1 through 7 always legal */
          case '1':
--- 793,817 ----
             * will turn it off if we have scanned any nonzero digits).
             */
          case '0':
+           if (! (flags & NNZDIGITS))
+             goto ok;
            if (base == 0)
              {
                base = 8;
                flags |= PFXOK;
              }
            if (flags & NZDIGITS)
!             {
!               flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
!               goto ok;
!             }
!           flags &= ~(SIGNOK | PFXOK | NDIGITS);
!           if (width_left)
!             {
!               width_left--;
!               width++;
!             }
!           goto skip;
              /* 1 through 7 always legal */
          case '1':
*************** __svfscanf_r (rptr, fp, fmt0, ap)
*** 809,815 ****
          case '6':
          case '7':
            base = basefix[base];
!           flags &= ~(SIGNOK | PFXOK | NDIGITS);
            goto ok;
              /* digits 8 and 9 ok iff decimal or hex */
--- 822,828 ----
          case '6':
          case '7':
            base = basefix[base];
!           flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS);
            goto ok;
              /* digits 8 and 9 ok iff decimal or hex */
*************** __svfscanf_r (rptr, fp, fmt0, ap)
*** 818,824 ****
            base = basefix[base];
            if (base <= 8)
              break;    /* not legal here */
!           flags &= ~(SIGNOK | PFXOK | NDIGITS);
            goto ok;
              /* letters ok iff hex */
--- 831,837 ----
            base = basefix[base];
            if (base <= 8)
              break;    /* not legal here */
!           flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS);
            goto ok;
              /* letters ok iff hex */
*************** __svfscanf_r (rptr, fp, fmt0, ap)
*** 837,843 ****
            /* no need to fix base here */
            if (base <= 10)
              break;    /* not legal here */
!           flags &= ~(SIGNOK | PFXOK | NDIGITS);
            goto ok;
              /* sign ok only as first character */
--- 850,856 ----
            /* no need to fix base here */
            if (base <= 10)
              break;    /* not legal here */
!           flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS);
            goto ok;
              /* sign ok only as first character */
*************** __svfscanf_r (rptr, fp, fmt0, ap)
*** 872,877 ****
--- 885,891 ----
             * c is legal: store it and look at the next.
             */
            *p++ = c;
+         skip:
            if (--fp->_r > 0)
          fp->_p++;
            else
*************** __svfscanf_r (rptr, fp, fmt0, ap)
*** 939,945 ****
          }
        nread += p - buf;
        break;
!   #ifdef FLOATING_POINT
      case CT_FLOAT:
      {
--- 953,959 ----
          }
        nread += p - buf;
        break;
!     }
  #ifdef FLOATING_POINT
      case CT_FLOAT:
      {
*************** __svfscanf_r (rptr, fp, fmt0, ap)
*** 951,965 ****
        long leading_zeroes = 0;
        long zeroes, exp_adjust;
        char *exp_start = NULL;
  #ifdef hardway
        if (width == 0 || width > sizeof (buf) - 1)
-         width = sizeof (buf) - 1;
  #else
        /* size_t is unsigned, hence this optimisation */
!       if (--width > sizeof (buf) - 2)
!         width = sizeof (buf) - 2;
!       width++;
  #endif
        flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
        zeroes = 0;
        exp_adjust = 0;
--- 965,981 ----
        long leading_zeroes = 0;
        long zeroes, exp_adjust;
        char *exp_start = NULL;
+       unsigned width_left = 0;
  #ifdef hardway
        if (width == 0 || width > sizeof (buf) - 1)
  #else
        /* size_t is unsigned, hence this optimisation */
!       if (width - 1 > sizeof (buf) - 2)
  #endif
+         {
+           width_left = width - (sizeof (buf) - 1);
+           width = sizeof (buf) - 1;
+         }
        flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
        zeroes = 0;
        exp_adjust = 0;
*************** __svfscanf_r (rptr, fp, fmt0, ap)
*** 978,983 ****
--- 994,1004 ----
              {
                flags &= ~SIGNOK;
                zeroes++;
+               if (width_left)
+             {
+               width_left--;
+               width++;
+             }
                goto fskip;
              }
            /* Fall through.  */




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]