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


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]