about summary refs log tree commit diff
path: root/stdio-common/tst-scanf-round.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2018-06-19 11:52:18 +0000
committerJoseph Myers <joseph@codesourcery.com>2018-06-19 11:52:18 +0000
commit646c2833ee84aa5ecc7e219f0cc6156e61c371d3 (patch)
tree1996262927420672f6acf917723309ffecfc7396 /stdio-common/tst-scanf-round.c
parent152fbfb3ad6387051f97248747394d6798b383ba (diff)
downloadglibc-646c2833ee84aa5ecc7e219f0cc6156e61c371d3.tar.gz
glibc-646c2833ee84aa5ecc7e219f0cc6156e61c371d3.tar.xz
glibc-646c2833ee84aa5ecc7e219f0cc6156e61c371d3.zip
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).
Diffstat (limited to 'stdio-common/tst-scanf-round.c')
-rw-r--r--stdio-common/tst-scanf-round.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/stdio-common/tst-scanf-round.c b/stdio-common/tst-scanf-round.c
new file mode 100644
index 0000000000..a2fb620abf
--- /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>