This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc 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]

GNU C Library master sources branch master updated. glibc-2.27.9000-490-g646c283


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  646c2833ee84aa5ecc7e219f0cc6156e61c371d3 (commit)
      from  152fbfb3ad6387051f97248747394d6798b383ba (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=646c2833ee84aa5ecc7e219f0cc6156e61c371d3

commit 646c2833ee84aa5ecc7e219f0cc6156e61c371d3
Author: Joseph Myers <joseph@codesourcery.com>
Date:   Tue Jun 19 11:52:18 2018 +0000

    Fix scanf rounding of negative floating-point numbers (bug 23280).
    
    As reported in bug 23280, scanf functions produce incorrectly rounded
    result for floating-point formats in FE_UPWARD and FE_DOWNWARD modes,
    because they pass the input with sign removed to strtod functions, and
    then negate the result if there was a '-' at the start of the input.
    
    This patch fixes this by arranging for the sign to be passed to strtod
    rather than scanf doing the negation itself.  In turn, keeping the
    sign around in the buffer being built up for strtod requires updating
    places that examine char_buffer_size (&charbuf) to allow for the sign
    being there as an extra character.
    
    Tested for x86_64.
    
    	[BZ #23280]
    	* stdio-common/vfscanf.c (_IO_vfscanf_internal): Pass sign of
    	floating-point number to strtod functions rather than possibly
    	negating result of those functions.
    	* stdio-common/tst-scanf-round.c: New file.
    	* stdio-common/Makefile (tests): Add tst-scanf-round.
    	($(objpfx)tst-scanf-round): Depend on $(libm).

diff --git a/ChangeLog b/ChangeLog
index e83db88..90b65fd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2018-06-19  Joseph Myers  <joseph@codesourcery.com>
+
+	[BZ #23280]
+	* stdio-common/vfscanf.c (_IO_vfscanf_internal): Pass sign of
+	floating-point number to strtod functions rather than possibly
+	negating result of those functions.
+	* stdio-common/tst-scanf-round.c: New file.
+	* stdio-common/Makefile (tests): Add tst-scanf-round.
+	($(objpfx)tst-scanf-round): Depend on $(libm).
+
 2018-06-18  Samuel Thibault  <samuel.thibault@ens-lyon.org>
 
 	* sysdeps/mach/hurd/localplt.data: Move to...
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 9dfc115..4503837 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -61,6 +61,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 tst-printf-bz18872 tst-vfprintf-width-prec tst-fmemopen4 \
 	 tst-vfprintf-user-type \
 	 tst-vfprintf-mbs-prec \
+	 tst-scanf-round \
 
 test-srcs = tst-unbputc tst-printf
 
@@ -158,3 +159,4 @@ $(objpfx)tst-setvbuf1-cmp.out: tst-setvbuf1.expect $(objpfx)tst-setvbuf1.out
 	$(evaluate-test)
 
 $(objpfx)tst-printf-round: $(libm)
+$(objpfx)tst-scanf-round: $(libm)
diff --git a/stdio-common/tst-scanf-round.c b/stdio-common/tst-scanf-round.c
new file mode 100644
index 0000000..a2fb620
--- /dev/null
+++ b/stdio-common/tst-scanf-round.c
@@ -0,0 +1,51 @@
+/* Test for correct rounding of negative floating-point numbers by scanf
+   (bug 23280).
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+#ifdef FE_DOWNWARD
+  if (fesetround (FE_DOWNWARD) == 0)
+    {
+      double a = strtod ("-0.1", NULL);
+      double b = 0;
+      int r = sscanf ("-0.1", "%lf", &b);
+      TEST_VERIFY (r == 1);
+      TEST_VERIFY (a == b);
+    }
+#endif
+#ifdef FE_UPWARD
+  if (fesetround (FE_UPWARD) == 0)
+    {
+      double a = strtod ("-0.1", NULL);
+      double b = 0;
+      int r = sscanf ("-0.1", "%lf", &b);
+      TEST_VERIFY (r == 1);
+      TEST_VERIFY (a == b);
+    }
+#endif
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index 3263268..1ce836a 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf.c
@@ -292,7 +292,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   /* Errno of last failed inchar call.  */
   int inchar_errno = 0;
   /* Status for reading F-P nums.  */
-  char got_digit, got_dot, got_e, negative;
+  char got_digit, got_dot, got_e, got_sign;
   /* If a [...] is a [^...].  */
   CHAR_T not_in;
 #define exp_char not_in
@@ -1914,20 +1914,19 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	  if (__glibc_unlikely (c == EOF))
 	    input_error ();
 
-	  got_digit = got_dot = got_e = 0;
+	  got_digit = got_dot = got_e = got_sign = 0;
 
 	  /* Check for a sign.  */
 	  if (c == L_('-') || c == L_('+'))
 	    {
-	      negative = c == L_('-');
+	      got_sign = 1;
+	      char_buffer_add (&charbuf, c);
 	      if (__glibc_unlikely (width == 0 || inchar () == EOF))
 		/* EOF is only an input error before we read any chars.  */
 		conv_error ();
 	      if (width > 0)
 		--width;
 	    }
-	  else
-	    negative = 0;
 
 	  /* Take care for the special arguments "nan" and "inf".  */
 	  if (TOLOWER (c) == L_('n'))
@@ -2176,7 +2175,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 		 digits with ASCII letters.  */
 	      && !(flags & HEXA_FLOAT)
 	      /* Minimum requirement.  */
-	      && (char_buffer_size (&charbuf) == 0 || got_dot)
+	      && (char_buffer_size (&charbuf) == got_sign || got_dot)
 	      && (map = __wctrans ("to_inpunct")) != NULL)
 	    {
 	      /* Reget the first character.  */
@@ -2195,8 +2194,8 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 		 for localized FP numbers, then we may have localized
 		 digits.  Note, we test GOT_DOT above.  */
 #ifdef COMPILE_WSCANF
-	      if (char_buffer_size (&charbuf) == 0
-		  || (char_buffer_size (&charbuf) == 1
+	      if (char_buffer_size (&charbuf) == got_sign
+		  || (char_buffer_size (&charbuf) == got_sign + 1
 		      && wcdigits[11] == decimal))
 #else
 	      char mbdigits[12][MB_LEN_MAX + 1];
@@ -2204,13 +2203,13 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	      mbstate_t state;
 	      memset (&state, '\0', sizeof (state));
 
-	      bool match_so_far = char_buffer_size (&charbuf) == 0;
+	      bool match_so_far = char_buffer_size (&charbuf) == got_sign;
 	      size_t mblen = __wcrtomb (mbdigits[11], wcdigits[11], &state);
 	      if (mblen != (size_t) -1)
 		{
 		  mbdigits[11][mblen] = '\0';
 		  match_so_far |=
-		    (char_buffer_size (&charbuf) == strlen (decimal)
+		    (char_buffer_size (&charbuf) == strlen (decimal) + got_sign
 		     && strcmp (decimal, mbdigits[11]) == 0);
 		}
 	      else
@@ -2220,7 +2219,8 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 		     from a file.  */
 		  if (decimal_len <= MB_LEN_MAX)
 		    {
-		      match_so_far |= char_buffer_size (&charbuf) == decimal_len;
+		      match_so_far |= (char_buffer_size (&charbuf)
+				       == decimal_len + got_sign);
 		      memcpy (mbdigits[11], decimal, decimal_len + 1);
 		    }
 		  else
@@ -2284,7 +2284,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 		      if (got_e && charbuf.current[-1] == exp_char
 			  && (c == L_('-') || c == L_('+')))
 			char_buffer_add (&charbuf, c);
-		      else if (char_buffer_size (&charbuf) > 0 && !got_e
+		      else if (char_buffer_size (&charbuf) > got_sign && !got_e
 			       && (CHAR_T) TOLOWER (c) == exp_char)
 			{
 			  char_buffer_add (&charbuf, exp_char);
@@ -2408,9 +2408,10 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	  /* Have we read any character?  If we try to read a number
 	     in hexadecimal notation and we have read only the `0x'
 	     prefix this is an error.  */
-	  if (__glibc_unlikely (char_buffer_size (&charbuf) == 0
+	  if (__glibc_unlikely (char_buffer_size (&charbuf) == got_sign
 				|| ((flags & HEXA_FLOAT)
-				    && char_buffer_size (&charbuf) == 2)))
+				    && (char_buffer_size (&charbuf)
+					== 2 + got_sign))))
 	    conv_error ();
 
 	scan_float:
@@ -2427,21 +2428,21 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	      long double d = __strtold_internal
 		(char_buffer_start (&charbuf), &tw, flags & GROUP);
 	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
-		*ARG (long double *) = negative ? -d : d;
+		*ARG (long double *) = d;
 	    }
 	  else if (flags & (LONG | LONGDBL))
 	    {
 	      double d = __strtod_internal
 		(char_buffer_start (&charbuf), &tw, flags & GROUP);
 	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
-		*ARG (double *) = negative ? -d : d;
+		*ARG (double *) = d;
 	    }
 	  else
 	    {
 	      float d = __strtof_internal
 		(char_buffer_start (&charbuf), &tw, flags & GROUP);
 	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
-		*ARG (float *) = negative ? -d : d;
+		*ARG (float *) = d;
 	    }
 
 	  if (__glibc_unlikely (tw == char_buffer_start (&charbuf)))

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |   10 ++++
 stdio-common/Makefile                              |    2 +
 .../tst-scanf-round.c                              |   45 +++++++++++---------
 stdio-common/vfscanf.c                             |   35 ++++++++-------
 4 files changed, 55 insertions(+), 37 deletions(-)
 copy nptl/tst-minstack-exit.c => stdio-common/tst-scanf-round.c (59%)


hooks/post-receive
-- 
GNU C Library master sources


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