public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 1/9] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (3 preceding siblings ...)
  2018-03-07 19:32 ` [PATCH 4/9] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl Zack Weinberg
@ 2018-03-07 19:32 ` Zack Weinberg
  2018-03-12 20:36   ` Adhemerval Zanella
  2018-03-26 15:17   ` Gabriel F. T. Gomes
  2018-03-07 19:32 ` [PATCH 5/9] Add __v*printf_internal with flags arguments Zack Weinberg
                   ` (6 subsequent siblings)
  11 siblings, 2 replies; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:32 UTC (permalink / raw)
  To: libc-alpha

This patch takes the first step toward removing the global flag
__ldbl_is_dbl, creating a __vstrfmon_l_internal that takes a flags
parameter instead.

This change arguably makes the generated code slightly worse on
architectures where __ldbl_is_dbl is never true; right now, on those
architectures, it's a compile-time constant; after this change, the
compiler could theoretically prove that __vstrfmon_l_internal was
never called with a nonzero flags argument, but it would probably need
LTO to do it.  This is not performance critical code and I tend to
think that the maintainability benefits of removing action at a
distance are worth it.  However, we _could_ wrap the runtime flag
check with a macro that was defined to ignore its argument and always
return false on architectures where __ldbl_is_dbl is never true, if
people think the codegen benefits are important.

	* include/monetary.h (STRFMON_LDBL_IS_DBL): New constant.
	(__vstrfmon_l): Rename to __vstrfmon_l_internal and add flags
	argument.
	* stdlib/strfmon_l.c (__vstrfmon_l): Rename to __vstrfmon_l_internal
	and add flags argument.	 Check flags instead of __ldbl_is_dbl when
	deciding whether to set is_long_double.
	(__strfmon_l): Call __vstrfmon_l_internal instead of __vstrfmon_l,
	passing zero for flags argument.
	* stdlib/strfmon.c (strfmon): Same change as made to __strfmon_l.

	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
	(__nldbl___vstrfmon, __nldbl___vstrfmon_l)
	(__nldbl_strfmon, __nldbl___strfmon_l): Call __vstrfmon_l_internal
	directly, passing STRFMON_LDBL_IS_DBL for flags argument.  Normalize
	variable names.  Remove libc_hidden_def/libc_hidden_proto.
	* sysdeps/ieee754/ldbl-opt/nldbl-compat.h: Don't use NLDBL_DECL
	for __nldbl___vstrfmon_l.

	* manual/locale.texi: Update a reference to vstrfmon_l in comments.
---
 include/monetary.h                      | 10 +++++++---
 manual/locale.texi                      |  9 +++++----
 stdlib/strfmon.c                        |  3 ++-
 stdlib/strfmon_l.c                      |  8 ++++----
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 34 ++++++++++++---------------------
 sysdeps/ieee754/ldbl-opt/nldbl-compat.h |  8 +++++---
 6 files changed, 35 insertions(+), 37 deletions(-)

diff --git a/include/monetary.h b/include/monetary.h
index c130ed56a3..d12ae03dd3 100644
--- a/include/monetary.h
+++ b/include/monetary.h
@@ -2,7 +2,11 @@
 #ifndef _ISOMAC
 #include <stdarg.h>
 
-extern ssize_t __vstrfmon_l (char *s, size_t maxsize, locale_t loc,
-			     const char *format, va_list ap)
-     attribute_hidden;
+extern ssize_t __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
+                                      const char *format, va_list ap,
+                                      unsigned int flags);
+
+/* Flags for __vstrfmon_l_internal.  */
+#define STRFMON_LDBL_IS_DBL 0x0001
+
 #endif
diff --git a/manual/locale.texi b/manual/locale.texi
index dabb959f9e..720e0ca952 100644
--- a/manual/locale.texi
+++ b/manual/locale.texi
@@ -1209,10 +1209,11 @@ numbers according to these rules.
 
 @deftypefun ssize_t strfmon (char *@var{s}, size_t @var{maxsize}, const char *@var{format}, @dots{})
 @safety{@prelim{}@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}}
-@c It (and strfmon_l) both call vstrfmon_l, which, besides accessing the
-@c locale object passed to it, accesses the active locale through
-@c isdigit (but to_digit assumes ASCII digits only).  It may call
-@c __printf_fp (@mtslocale @ascuheap @acsmem) and guess_grouping (safe).
+@c It (and strfmon_l) both call __vstrfmon_l_internal, which, besides
+@c accessing the locale object passed to it, accesses the active
+@c locale through isdigit (but to_digit assumes ASCII digits only).
+@c It may call __printf_fp (@mtslocale @ascuheap @acsmem) and
+@c guess_grouping (safe).
 The @code{strfmon} function is similar to the @code{strftime} function
 in that it takes a buffer, its size, a format string,
 and values to write into the buffer as text in a form specified
diff --git a/stdlib/strfmon.c b/stdlib/strfmon.c
index 01980d3e15..2b742c7ad7 100644
--- a/stdlib/strfmon.c
+++ b/stdlib/strfmon.c
@@ -30,7 +30,8 @@ __strfmon (char *s, size_t maxsize, const char *format, ...)
 
   va_start (ap, format);
 
-  ssize_t res = __vstrfmon_l (s, maxsize, _NL_CURRENT_LOCALE, format, ap);
+  ssize_t res = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE,
+                                       format, ap, 0);
 
   va_end (ap);
 
diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
index cd3796ced9..f0ebd99bd3 100644
--- a/stdlib/strfmon_l.c
+++ b/stdlib/strfmon_l.c
@@ -76,8 +76,8 @@
    too.  Some of the information contradicts the information which can
    be specified in format string.  */
 ssize_t
-__vstrfmon_l (char *s, size_t maxsize, locale_t loc, const char *format,
-	      va_list ap)
+__vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
+                       const char *format, va_list ap, unsigned int flags)
 {
   struct __locale_data *current = loc->__locales[LC_MONETARY];
   _IO_strfile f;
@@ -268,7 +268,7 @@ __vstrfmon_l (char *s, size_t maxsize, locale_t loc, const char *format,
       if (*fmt == 'L')
 	{
 	  ++fmt;
-	  if (!__ldbl_is_dbl)
+	  if (__glibc_likely ((flags & STRFMON_LDBL_IS_DBL) == 0))
 	    is_long_double = 1;
 	}
 
@@ -608,7 +608,7 @@ ___strfmon_l (char *s, size_t maxsize, locale_t loc, const char *format, ...)
 
   va_start (ap, format);
 
-  ssize_t res = __vstrfmon_l (s, maxsize, loc, format, ap);
+  ssize_t res = __vstrfmon_l_internal (s, maxsize, loc, format, ap, 0);
 
   va_end (ap);
 
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index bf54090d4f..7d19eaba8d 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -50,8 +50,6 @@ libc_hidden_proto (__nldbl___vswprintf_chk)
 libc_hidden_proto (__nldbl___vasprintf_chk)
 libc_hidden_proto (__nldbl___vdprintf_chk)
 libc_hidden_proto (__nldbl___obstack_vprintf_chk)
-libc_hidden_proto (__nldbl___vstrfmon)
-libc_hidden_proto (__nldbl___vstrfmon_l)
 libc_hidden_proto (__nldbl___isoc99_vsscanf)
 libc_hidden_proto (__nldbl___isoc99_vfscanf)
 libc_hidden_proto (__nldbl___isoc99_vswscanf)
@@ -779,12 +777,13 @@ attribute_compat_text_section
 __nldbl_strfmon (char *s, size_t maxsize, const char *format, ...)
 {
   va_list ap;
-  ssize_t res;
+  ssize_t ret;
 
   va_start (ap, format);
-  res = __nldbl___vstrfmon (s, maxsize, format, ap);
+  ret = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE, format, ap,
+                               STRFMON_LDBL_IS_DBL);
   va_end (ap);
-  return res;
+  return ret;
 }
 
 ssize_t
@@ -793,12 +792,13 @@ __nldbl___strfmon_l (char *s, size_t maxsize, locale_t loc,
 		     const char *format, ...)
 {
   va_list ap;
-  ssize_t res;
+  ssize_t ret;
 
   va_start (ap, format);
-  res = __nldbl___vstrfmon_l (s, maxsize, loc, format, ap);
+  ret = __vstrfmon_l_internal (s, maxsize, loc, format, ap,
+                               STRFMON_LDBL_IS_DBL);
   va_end (ap);
-  return res;
+  return ret;
 }
 weak_alias (__nldbl___strfmon_l, __nldbl_strfmon_l)
 
@@ -806,28 +806,18 @@ ssize_t
 attribute_compat_text_section
 __nldbl___vstrfmon (char *s, size_t maxsize, const char *format, va_list ap)
 {
-  ssize_t res;
-  __no_long_double = 1;
-  res = __vstrfmon_l (s, maxsize, _NL_CURRENT_LOCALE, format, ap);
-  __no_long_double = 0;
-  va_end (ap);
-  return res;
+  return __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE, format, ap,
+				STRFMON_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl___vstrfmon)
 
 ssize_t
 attribute_compat_text_section
 __nldbl___vstrfmon_l (char *s, size_t maxsize, locale_t loc,
 		      const char *format, va_list ap)
 {
-  ssize_t res;
-  __no_long_double = 1;
-  res = __vstrfmon_l (s, maxsize, loc, format, ap);
-  __no_long_double = 0;
-  va_end (ap);
-  return res;
+  return __vstrfmon_l_internal (s, maxsize, loc, format, ap,
+				STRFMON_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl___vstrfmon_l)
 
 void
 attribute_compat_text_section
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
index 74f0e459fa..a9a77dce99 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
@@ -60,7 +60,6 @@ NLDBL_DECL (vsyslog);
 NLDBL_DECL (qecvt);
 NLDBL_DECL (qfcvt);
 NLDBL_DECL (qgcvt);
-NLDBL_DECL (__vstrfmon_l);
 NLDBL_DECL (__isoc99_scanf);
 NLDBL_DECL (__isoc99_fscanf);
 NLDBL_DECL (__isoc99_sscanf);
@@ -74,10 +73,13 @@ NLDBL_DECL (__isoc99_vwscanf);
 NLDBL_DECL (__isoc99_vfwscanf);
 NLDBL_DECL (__isoc99_vswscanf);
 
-/* This one does not exist in the normal interface, only
-   __nldbl___vstrfmon really exists.  */
+/* These do not exist in the normal interface, but must exist in the
+   __nldbl interface so that they can be called from libnldbl.  */
 extern ssize_t __nldbl___vstrfmon (char *, size_t, const char *, va_list)
   __THROW;
+extern ssize_t __nldbl___vstrfmon_l (char *, size_t, locale_t, const char *,
+				     va_list)
+  __THROW;
 
 /* These don't use __typeof because they were not declared by the headers,
    since we don't compile with _FORTIFY_SOURCE.  */
-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
  2018-03-07 19:32 ` [PATCH 8/9] Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl Zack Weinberg
  2018-03-07 19:32 ` [PATCH 3/9] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD Zack Weinberg
@ 2018-03-07 19:32 ` Zack Weinberg
  2018-03-13 12:35   ` Adhemerval Zanella
                     ` (3 more replies)
  2018-03-07 19:32 ` [PATCH 4/9] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl Zack Weinberg
                   ` (8 subsequent siblings)
  11 siblings, 4 replies; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:32 UTC (permalink / raw)
  To: libc-alpha

There are two flags currently defined: SCANF_LDBL_IS_DBL is the mode
used by __nldbl_ scanf variants, and SCANF_ISOC99_A is the mode used
by __isoc99_ scanf variants.  In this patch, the new functions honor
these flag bits if they're set, but they still also look at the
corresponding bits of environmental state, and callers all pass zero.

The new functions do *not* have the "errp" argument possessed by
_IO_vfscanf and _IO_vfwscanf.  All internal callers passed NULL for
that argument.  External callers could theoretically exist, so I
preserved wrappers, but they are flagged as compat symbols and they
don't preserve the three-way distinction among types of errors that
was formerly exposed.  These functions probably should have been in
the list of deprecated _IO_ symbols in 2.27 NEWS -- they're not just
aliases for vfscanf and vfwscanf.

(It was necessary to introduce ldbl_compat_symbol for _IO_vfscanf.
Please check that part of the patch very carefully, I am still not
confident I understand all of the details of ldbl-opt.)

This patch also introduces helper inlines in libio/strfile.h that
encapsulate the process of initializing an _IO_strfile object for
reading.  This allows us to call __vfscanf_internal directly from
sscanf, and __vfwscanf_internal directly from swscanf, without
duplicating the initialization code.  (Previously, they called their
v-counterparts, but that won't work if we want to control *both* C99
mode and ldbl-is-dbl mode using the flags argument to__vfscanf_internal.)
It's still a little awkward, especially for wide strfiles, but it's
much better than what we had.

	* libio/libioP.h (SCANF_LDBL_IS_DBL, SCANF_ISOC99_A): New constants.
	(__vfscanf_internal, __vfwscanf_internal): New function prototypes.
        * libio/libio.h: Remove libc_hidden_proto for _IO_vfscanf.
	* libio/strfile.h: Add multiple inclusion guard.
	(_IO_strfile_read, _IO_strfile_readw): New inline functions.

	* sysdeps/generic/math_ldbl_opt.h: Include shlib-compat.h, for
	consistency with the other version of this file.
	(ldbl_compat_symbol): New macro.
	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h (ldbl_compat_symbol):
	New macro.

	* stdio-common/vfscanf-internal.c: Rename from vfscanf.c.
	Define __vfscanf_internal or __vfwscanf_internal, depending on
	COMPILE_WPRINTF; don't define any other public symbols.
	Temporarily check __ldbl_is_dbl and _IO_FLAGS2_SCANF_STD as well
	as the mode_flags argument.
	(encode_error, conv_error, input_error): Don't set errval.
	* stdio-common/vfwscanf-internal.c: Rename from vfwscanf.c.
	Include vfscanf-internal.c.
	* stdio-common/vfscanf.c, stdio-common/vfwscanf.c: New files
	defining the public entry points vfscanf and vfwscanf respectively.
	* stdio-common/iovfscanf.c, stdio-common/iovfwscanf.c: New files
	defining the compat symbols _IO_vfscanf and _IO_vfwscanf respectively.
	* stdio-common/Makefile (routines): Add vfscanf-internal,
	vfwscanf-internal, iovfscanf, iovfwscanf.
        * stdio-common/Versions: Mention GLIBC_2.28, so that
        it can be used in SHLIB_COMPAT expressions.
	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl__IO_vfscanf):
	Wrap definition and compat_symbol line in #if SHLIB_COMPAT.

	* libio/iovsscanf.c, libio/vscanf.c, libio/vwscanf.c, libio/wscanf.c
	* libio/iovswscanf.c, stdio-common/isoc99_fscanf.c
	* stdio-common/isoc99_scanf.c, stdio-common/isoc99_vfscanf.c
	* stdio-common/isoc99_vscanf.c, stdio-common/isoc99_vsscanf.c
	* stdio-common/scanf.c, sysdeps/ieee754/ldbl-opt/nldbl-compat.c
	* wcsmbs/isoc99_fwscanf.c, wcsmbs/isoc99_vfwscanf.c
	* wcsmbs/isoc99_vswscanf.c, wcsmbs/isoc99_vwscanf.c
	* wcsmbs/isoc99_wscanf.c: Use __vfscanf_internal instead of
	_IO_vfscanf, and/or __vfwscanf_internal instead of _IO_vfwscanf.

	* libio/iovsscanf.c, stdio-common/isoc99_vsscanf.c:
	Use _IO_strfile_read.  Clean up includes.
	* stdio-common/sscanf.c, stdio-common/isoc99_sscanf.c:
	Use _IO_strfile_read to set up a FILE, and then call
	__vfwcanf_internal directly.  Clean up includes.

	* libio/iovswscanf.c, wcsmbs/isoc99_vswscanf.c:
	Use _IO_strfile_readw.  Clean up includes.
	* libio/swscanf.c, wcsmbs/isoc99_swscanf.c:
	Use _IO_strfile_readw to set up a FILE, and then call
	__vfwscanf_internal directly.  Clean up includes.
---
 libio/iovsscanf.c                                |   12 +-
 libio/iovswscanf.c                               |   14 +-
 libio/libio.h                                    |    1 -
 libio/libioP.h                                   |    9 +
 libio/strfile.h                                  |   33 +-
 libio/swscanf.c                                  |   10 +-
 libio/vscanf.c                                   |    2 +-
 libio/vwscanf.c                                  |    2 +-
 libio/wscanf.c                                   |    2 +-
 stdio-common/Makefile                            |    3 +-
 stdio-common/Versions                            |    3 +
 stdio-common/iovfscanf.c                         |   34 +
 stdio-common/iovfwscanf.c                        |   34 +
 stdio-common/isoc99_fscanf.c                     |    2 +-
 stdio-common/isoc99_scanf.c                      |    2 +-
 stdio-common/isoc99_sscanf.c                     |    8 +-
 stdio-common/isoc99_vfscanf.c                    |    2 +-
 stdio-common/isoc99_vscanf.c                     |    2 +-
 stdio-common/isoc99_vsscanf.c                    |   17 +-
 stdio-common/scanf.c                             |    2 +-
 stdio-common/sscanf.c                            |   12 +-
 stdio-common/{vfscanf.c => vfscanf-internal.c}   |   46 +-
 stdio-common/vfscanf.c                           |   27 +
 stdio-common/{vfwscanf.c => vfwscanf-internal.c} |    2 +-
 stdio-common/vfwscanf.c                          |   25 +
 sysdeps/generic/math_ldbl_opt.h                  |    4 +
 sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h         |    4 +
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c          |   12 +-
 wcsmbs/isoc99_fwscanf.c                          |    2 +-
 wcsmbs/isoc99_swscanf.c                          |   12 +-
 wcsmbs/isoc99_vfwscanf.c                         |    2 +-
 wcsmbs/isoc99_vswscanf.c                         |   16 +-
 wcsmbs/isoc99_vwscanf.c                          |    2 +-
 wcsmbs/isoc99_wscanf.c                           |    2 +-
 34 files changed, 211 insertions(+), 115 deletions(-)
 create mode 100644 stdio-common/iovfscanf.c
 create mode 100644 stdio-common/iovfwscanf.c
 create mode 100644 stdio-common/vfscanf.c
 create mode 100644 stdio-common/vfwscanf.c

diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
index e56ab8bd7d..ee6a99ec6a 100644
--- a/libio/iovsscanf.c
+++ b/libio/iovsscanf.c
@@ -24,22 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include "libioP.h"
 #include "strfile.h"
 
 int
 _IO_vsscanf (const char *string, const char *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
-  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_read (&sf, string);
+  return __vfscanf_internal (f, format, args, 0);
 }
 ldbl_weak_alias (_IO_vsscanf, __vsscanf)
 ldbl_weak_alias (_IO_vsscanf, vsscanf)
diff --git a/libio/iovswscanf.c b/libio/iovswscanf.c
index 5bd1c88412..cb9cbe15cc 100644
--- a/libio/iovswscanf.c
+++ b/libio/iovswscanf.c
@@ -24,24 +24,16 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include "libioP.h"
-#include "strfile.h"
 #include <wchar.h>
+#include "strfile.h"
 
 int
 __vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
   struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
-  _IO_fwide (&sf._sbf._f, 1);
-  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
-  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_readw (&sf, &wd, string);
+  return __vfwscanf_internal (f, format, args, 0);
 }
 libc_hidden_def (__vswscanf)
 ldbl_hidden_def (__vswscanf, vswscanf)
diff --git a/libio/libio.h b/libio/libio.h
index 00f9169613..d4eba2df54 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -321,7 +321,6 @@ libc_hidden_proto (_IO_padn)
 libc_hidden_proto (_IO_putc)
 libc_hidden_proto (_IO_sgetn)
 libc_hidden_proto (_IO_vfprintf)
-libc_hidden_proto (_IO_vfscanf)
 
 #ifdef _IO_MTSAFE_IO
 # undef _IO_peekc
diff --git a/libio/libioP.h b/libio/libioP.h
index 8afe7032e3..a471c90be8 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -704,6 +704,15 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)
 
 #endif /* _G_HAVE_MMAP */
 
+/* Flags for __vfscanf_internal and __vfwscanf_internal.  */
+#define SCANF_LDBL_IS_DBL 0x0001
+#define SCANF_ISOC99_A    0x0002
+
+extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
+                               unsigned int flags);
+extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
+                                unsigned int flags);
+
 extern int _IO_vscanf (const char *, va_list) __THROW;
 
 #ifdef _IO_MTSAFE_IO
diff --git a/libio/strfile.h b/libio/strfile.h
index 46ac81809a..715149f5bd 100644
--- a/libio/strfile.h
+++ b/libio/strfile.h
@@ -24,7 +24,9 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <stdio.h>
+#ifndef STRFILE_H_
+#define STRFILE_H_
+
 #include "libioP.h"
 
 typedef void *(*_IO_alloc_type) (size_t);
@@ -81,3 +83,32 @@ typedef struct
 } _IO_wstrnfile;
 
 extern const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden;
+
+/* Initialize an _IO_strfile SF to read from narrow string STRING, and
+   return the corresponding FILE object.  It is not necessary to fclose
+   the FILE when it is no longer needed.  */
+static inline FILE *
+_IO_strfile_read (_IO_strfile *sf, const char *string)
+{
+  sf->_sbf._f._lock = NULL;
+  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
+  _IO_JUMPS (&sf->_sbf) = &_IO_str_jumps;
+  _IO_str_init_static_internal (sf, (char*)string, 0, NULL);
+  return &sf->_sbf._f;
+}
+
+/* Initialize an _IO_strfile SF and _IO_wide_data WD to read from wide
+   string STRING, and return the corresponding FILE object.  It is not
+   necessary to fclose the FILE when it is no longer needed.  */
+static inline FILE *
+_IO_strfile_readw (_IO_strfile *sf, struct _IO_wide_data *wd,
+                   const wchar_t *string)
+{
+  sf->_sbf._f._lock = NULL;
+  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, 0, wd, &_IO_wstr_jumps);
+  _IO_fwide (&sf->_sbf._f, 1);
+  _IO_wstr_init_static (&sf->_sbf._f, (wchar_t *)string, 0, NULL);
+  return &sf->_sbf._f;
+}
+
+#endif /* strfile.h.  */
diff --git a/libio/swscanf.c b/libio/swscanf.c
index c8686bcbaf..90f721cc51 100644
--- a/libio/swscanf.c
+++ b/libio/swscanf.c
@@ -15,20 +15,22 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <wchar.h>
+#include "strfile.h"
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
+
 int
 __swscanf (const wchar_t *s, const wchar_t *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
 
   va_start (arg, format);
-  done = __vswscanf (s, format, arg);
+  done = __vfwscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/libio/vscanf.c b/libio/vscanf.c
index 9c27122c27..a3e2dd43f2 100644
--- a/libio/vscanf.c
+++ b/libio/vscanf.c
@@ -32,6 +32,6 @@
 int
 _IO_vscanf (const char *format, va_list args)
 {
-  return _IO_vfscanf (_IO_stdin, format, args, NULL);
+  return __vfscanf_internal (_IO_stdin, format, args, 0);
 }
 ldbl_weak_alias (_IO_vscanf, vscanf)
diff --git a/libio/vwscanf.c b/libio/vwscanf.c
index 0d5f558758..7af770c8c3 100644
--- a/libio/vwscanf.c
+++ b/libio/vwscanf.c
@@ -30,6 +30,6 @@
 int
 __vwscanf (const wchar_t *format, va_list args)
 {
-  return _IO_vfwscanf (_IO_stdin, format, args, NULL);
+  return __vfwscanf_internal (_IO_stdin, format, args, 0);
 }
 ldbl_strong_alias (__vwscanf, vwscanf)
diff --git a/libio/wscanf.c b/libio/wscanf.c
index c8cdad0acd..fe27ff6fa6 100644
--- a/libio/wscanf.c
+++ b/libio/wscanf.c
@@ -30,7 +30,7 @@ __wscanf (const wchar_t *format, ...)
   int done;
 
   va_start (arg, format);
-  done = _IO_vfwscanf (stdin, format, arg, NULL);
+  done = __vfwscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 9dfc115313..b7b1f01bdd 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -39,7 +39,8 @@ routines	:=							      \
 	flockfile ftrylockfile funlockfile				      \
 	isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
 	isoc99_vsscanf							      \
-	psiginfo gentempfd
+	psiginfo gentempfd						      \
+	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
 
 aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
 
diff --git a/stdio-common/Versions b/stdio-common/Versions
index 5016f69c20..7af44949f7 100644
--- a/stdio-common/Versions
+++ b/stdio-common/Versions
@@ -57,6 +57,9 @@ libc {
     psiginfo;
     register_printf_modifier; register_printf_type; register_printf_specifier;
   }
+  GLIBC_2.28 {
+    # SHLIB_COMPAT(GLIBC_2_0, GLIBC_2_28) used in iovfscanf.c etc
+  }
   GLIBC_PRIVATE {
     # global variables
     _itoa_lower_digits;
diff --git a/stdio-common/iovfscanf.c b/stdio-common/iovfscanf.c
new file mode 100644
index 0000000000..fb347d60cb
--- /dev/null
+++ b/stdio-common/iovfscanf.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1991-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 <libioP.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+
+int
+attribute_compat_text_section
+__IO_vfscanf (FILE *fp, const char *format, va_list ap, int *errp)
+{
+  int rv = __vfscanf_internal (fp, format, ap, 0);
+  if (__glibc_unlikely (errp != 0))
+    *errp = (rv == -1);
+  return rv;
+}
+ldbl_compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
+
+#endif
diff --git a/stdio-common/iovfwscanf.c b/stdio-common/iovfwscanf.c
new file mode 100644
index 0000000000..73936f68b2
--- /dev/null
+++ b/stdio-common/iovfwscanf.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1991-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 <libioP.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+
+int
+attribute_compat_text_section
+__IO_vfwscanf (FILE *fp, const wchar_t *format, va_list ap, int *errp)
+{
+  int rv = __vfwscanf_internal (fp, format, ap, 0);
+  if (__glibc_unlikely (errp != 0))
+    *errp = (rv == -1);
+  return rv;
+}
+compat_symbol (libc, __IO_vfwscanf, _IO_vfwscanf, GLIBC_2_0);
+
+#endif
diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
index 9cdf85e679..4210d11f2b 100644
--- a/stdio-common/isoc99_fscanf.c
+++ b/stdio-common/isoc99_fscanf.c
@@ -31,7 +31,7 @@ __isoc99_fscanf (FILE *stream, const char *format, ...)
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfscanf (stream, format, arg, NULL);
+  done = __vfscanf_internal (stream, format, arg, 0);
   va_end (arg);
 
   _IO_release_lock (stream);
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
index bf7dbe86bb..64c873eed9 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/isoc99_scanf.c
@@ -34,7 +34,7 @@ __isoc99_scanf (const char *format, ...)
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfscanf (stdin, format, arg, NULL);
+  done = __vfscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
 #ifdef _IO_MTSAFE_IO
diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
index 56a60a2c05..95b94a68b5 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -16,8 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
+#include <libio/strfile.h>
 
 /* Read formatted input from S, according to the format string FORMAT.  */
 /* VARARGS2 */
@@ -26,9 +25,12 @@ __isoc99_sscanf (const char *s, const char *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __isoc99_vsscanf (s, format, arg);
+  done = __vfscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
index b80e05f8db..c96ca831ae 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stream);
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfscanf (stream, format, args, NULL);
+  done = __vfscanf_internal (stream, format, args, 0);
   _IO_release_lock (stream);
   return done;
 }
diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
index 0b747f85ba..72ae72ddee 100644
--- a/stdio-common/isoc99_vscanf.c
+++ b/stdio-common/isoc99_vscanf.c
@@ -27,7 +27,7 @@ __isoc99_vscanf (const char *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stdin);
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfscanf (stdin, format, args, NULL);
+  done = __vfscanf_internal (stdin, format, args, 0);
   _IO_release_lock (stdin);
   return done;
 }
diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
index ac85ef2d0d..02bc0f50e6 100644
--- a/stdio-common/isoc99_vsscanf.c
+++ b/stdio-common/isoc99_vsscanf.c
@@ -24,23 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <libioP.h>
-#include <stdio.h>
-#include "../libio/strfile.h"
+#include <libio/strfile.h>
 
 int
 __isoc99_vsscanf (const char *string, const char *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
-  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
-  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_read (&sf, string);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+  return __vfscanf_internal (f, format, args, 0);
 }
 libc_hidden_def (__isoc99_vsscanf)
diff --git a/stdio-common/scanf.c b/stdio-common/scanf.c
index e61b5f1ad3..de38d70353 100644
--- a/stdio-common/scanf.c
+++ b/stdio-common/scanf.c
@@ -30,7 +30,7 @@ __scanf (const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = _IO_vfscanf (stdin, format, arg, NULL);
+  done = __vfscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/sscanf.c b/stdio-common/sscanf.c
index 88cd641798..e25e9c27a5 100644
--- a/stdio-common/sscanf.c
+++ b/stdio-common/sscanf.c
@@ -16,26 +16,24 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
-#define __vsscanf(s, f, a) _IO_vsscanf (s, f, a)
+#include <libio/strfile.h>
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
+
 int
 __sscanf (const char *s, const char *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
 
   va_start (arg, format);
-  done = __vsscanf (s, format, arg);
+  done = __vfscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
 }
 ldbl_hidden_def (__sscanf, sscanf)
 ldbl_strong_alias (__sscanf, sscanf)
-#undef _IO_sscanf
-/* This is for libg++.  */
 ldbl_strong_alias (__sscanf, _IO_sscanf)
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf-internal.c
similarity index 98%
rename from stdio-common/vfscanf.c
rename to stdio-common/vfscanf-internal.c
index 3263268c7e..93b07ad4bc 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf-internal.c
@@ -132,16 +132,13 @@
 #include "printf-parse.h" /* Use read_int.  */
 
 #define encode_error() do {						      \
-			  errval = 4;					      \
 			  __set_errno (EILSEQ);				      \
 			  goto errout;					      \
 			} while (0)
 #define conv_error()	do {						      \
-			  errval = 2;					      \
 			  goto errout;					      \
 			} while (0)
 #define input_error()	do {						      \
-			  errval = 1;					      \
 			  if (done == 0) done = EOF;			      \
 			  goto errout;					      \
 			} while (0)
@@ -267,12 +264,12 @@ char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
    Return the number of assignments made, or -1 for an input error.  */
 #ifdef COMPILE_WSCANF
 int
-_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
-	      int *errp)
+__vfwscanf_internal (FILE *s, const wchar_t *format, va_list argptr,
+                     unsigned int mode_flags)
 #else
 int
-_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
-		      int *errp)
+__vfscanf_internal (FILE *s, const char *format, va_list argptr,
+                    unsigned int mode_flags)
 #endif
 {
   va_list arg;
@@ -283,7 +280,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   WINT_T c = 0;	/* Last char read.  */
   int width;		/* Maximum field width.  */
   int flags;		/* Modifiers for current format element.  */
-  int errval = 0;
 #ifndef COMPILE_WSCANF
   locale_t loc = _NL_CURRENT_LOCALE;
   struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
@@ -335,6 +331,14 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   struct char_buffer charbuf;
   scratch_buffer_init (&charbuf.scratch);
 
+#define LDBL_DISTINCT (__glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
+#define USE_ISOC99_A  (__glibc_likely (mode_flags & SCANF_ISOC99_A))
+  /* Temporarily honor the environmental mode bits.  */
+  if (__ldbl_is_dbl)
+    mode_flags |= SCANF_LDBL_IS_DBL;
+  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+    mode_flags |= SCANF_ISOC99_A;
+
 #ifdef __va_copy
   __va_copy (arg, argptr);
 #else
@@ -566,7 +570,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	    }
 	  /* In __isoc99_*scanf %as, %aS and %a[ extension is not
 	     supported at all.  */
-	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+	  if (USE_ISOC99_A)
 	    {
 	      --f;
 	      break;
@@ -2422,7 +2426,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	      done = EOF;
 	      goto errout;
 	    }
-	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
+	  if ((flags & LONGDBL) && LDBL_DISTINCT)
 	    {
 	      long double d = __strtold_internal
 		(char_buffer_start (&charbuf), &tw, flags & GROUP);
@@ -3017,8 +3021,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   UNLOCK_STREAM (s);
 
   scratch_buffer_free (&charbuf.scratch);
-  if (errp != NULL)
-    *errp |= errval;
 
   if (__glibc_unlikely (done == EOF))
     {
@@ -3044,23 +3046,3 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
     }
   return done;
 }
-
-#ifdef COMPILE_WSCANF
-int
-__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
-{
-  return _IO_vfwscanf (s, format, argptr, NULL);
-}
-ldbl_weak_alias (__vfwscanf, vfwscanf)
-#else
-int
-___vfscanf (FILE *s, const char *format, va_list argptr)
-{
-  return _IO_vfscanf_internal (s, format, argptr, NULL);
-}
-ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
-ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
-ldbl_strong_alias (___vfscanf, __vfscanf)
-ldbl_hidden_def (___vfscanf, __vfscanf)
-ldbl_weak_alias (___vfscanf, vfscanf)
-#endif
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index 0000000000..5eedca8340 100644
--- /dev/null	2018-02-21 11:21:31.435874074 -0500
+++ b/stdio-common/vfscanf.c	2018-03-07 08:44:37.578545222 -0500
@@ -0,0 +1,27 @@
+/* Copyright (C) 1991-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 <libioP.h>
+
+int
+___vfscanf (FILE *s, const char *format, va_list argptr)
+{
+  return __vfscanf_internal (s, format, argptr, 0);
+}
+ldbl_strong_alias (___vfscanf, __vfscanf)
+ldbl_hidden_def (___vfscanf, __vfscanf)
+ldbl_weak_alias (___vfscanf, vfscanf)
diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf-internal.c
similarity index 50%
rename from stdio-common/vfscanf.c
rename to stdio-common/vfscanf-internal.c
index 26b1a66608..26c89270b7 100644
--- a/stdio-common/vfwscanf.c
+++ b/stdio-common/vfwscanf-internal.c
@@ -1,2 +1,2 @@
 #define COMPILE_WSCANF	1
-#include "vfscanf.c"
+#include "vfscanf-internal.c"
diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
new file mode 100644
index 0000000000..0554b7eae1
--- a/stdio-common/vfwscanf.c
+++ b/stdio-common/vfwscanf.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 1991-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 <libioP.h>
+
+int
+__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
+{
+  return __vfwscanf_internal (s, format, argptr, 0);
+}
+ldbl_weak_alias (__vfwscanf, vfwscanf)
diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
index 8a5d8ba107..92f670dff7 100644
--- a/sysdeps/generic/math_ldbl_opt.h
+++ b/sysdeps/generic/math_ldbl_opt.h
@@ -6,9 +6,13 @@
    for platforms where compatibility symbols are required for a previous
    ABI that defined long double functions as aliases for the double code.  */
 
+#include <shlib-compat.h>
+
 #define LONG_DOUBLE_COMPAT(lib, introduced) 0
 #define long_double_symbol(lib, local, symbol)
 #define ldbl_hidden_def(local, name) libc_hidden_def (name)
 #define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
 #define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
+#define ldbl_compat_symbol(lib, local, symbol, version) \
+  compat_symbol (lib, local, symbol, version)
 #define __ldbl_is_dbl 0
diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
index af861c11ea..ee70d085fd 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -20,10 +20,14 @@
   long_double_symbol (libc, __GL_##name##_##aliasname, aliasname);
 # define long_double_symbol_1(lib, local, symbol, version) \
   versioned_symbol (lib, local, symbol, version)
+# define ldbl_compat_symbol(lib, local, symbol, version) \
+  compat_symbol (lib, local, symbol, LONG_DOUBLE_COMPAT_VERSION)
 #else
 # define ldbl_hidden_def(local, name) libc_hidden_def (name)
 # define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
 # define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
+# define ldbl_compat_symbol(lib, local, symbol, version) \
+  compat_symbol (lib, local, symbol, version)
 # ifndef __ASSEMBLER__
 /* Note that weak_alias cannot be used - it is defined to nothing
    in most of the C files.  */
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 7d19eaba8d..9ac88deb74 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -329,16 +329,20 @@ __nldbl_wprintf (const wchar_t *fmt, ...)
   return done;
 }
 
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
 int
 attribute_compat_text_section
 __nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfscanf (s, fmt, ap, errp);
+  res = __vfscanf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
+  if (__glibc_unlikely (errp != 0))
+    *errp = (res == -1);
   return res;
 }
+#endif
 
 int
 attribute_compat_text_section
@@ -346,7 +350,7 @@ __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfscanf (s, fmt, ap, NULL);
+  res = __vfscanf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return res;
 }
@@ -422,7 +426,7 @@ __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfwscanf (s, fmt, ap, NULL);
+  res = __vfwscanf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return res;
 }
@@ -1026,7 +1030,9 @@ compat_symbol (libc, __nldbl_vdprintf, vdprintf, GLIBC_2_0);
 compat_symbol (libc, __nldbl_vsnprintf, vsnprintf, GLIBC_2_0);
 compat_symbol (libc, __nldbl_vsprintf, vsprintf, GLIBC_2_0);
 compat_symbol (libc, __nldbl__IO_sscanf, _IO_sscanf, GLIBC_2_0);
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
 compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
+#endif
 compat_symbol (libc, __nldbl___vfscanf, __vfscanf, GLIBC_2_0);
 compat_symbol (libc, __nldbl___vsscanf, __vsscanf, GLIBC_2_0);
 compat_symbol (libc, __nldbl_fscanf, fscanf, GLIBC_2_0);
diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
index 0c6a2c47ac..00b07dd48e 100644
--- a/wcsmbs/isoc99_fwscanf.c
+++ b/wcsmbs/isoc99_fwscanf.c
@@ -32,7 +32,7 @@ __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfwscanf (stream, format, arg, NULL);
+  done = __vfwscanf_internal (stream, format, arg, 0);
   va_end (arg);
 
   _IO_release_lock (stream);
diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
index ff523db706..40401d0aa1 100644
--- a/wcsmbs/isoc99_swscanf.c
+++ b/wcsmbs/isoc99_swscanf.c
@@ -16,20 +16,22 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
-#include <wchar.h>
+#include <libio/strfile.h>
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
+
 int
 __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __isoc99_vswscanf (s, format, arg);
+  done = __vfwscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
index 7beb45b4d3..f70c6b596d 100644
--- a/wcsmbs/isoc99_vfwscanf.c
+++ b/wcsmbs/isoc99_vfwscanf.c
@@ -28,7 +28,7 @@ __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stream);
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfwscanf (stream, format, args, NULL);
+  done = __vfwscanf_internal (stream, format, args, 0);
   _IO_release_lock (stream);
   return done;
 }
diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
index 130769154d..b91eb651a3 100644
--- a/wcsmbs/isoc99_vswscanf.c
+++ b/wcsmbs/isoc99_vswscanf.c
@@ -24,24 +24,16 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <libioP.h>
 #include <wchar.h>
-#include "../libio/strfile.h"
+#include <libio/strfile.h>
 
 int
 __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
   struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
-  _IO_fwide (&sf._sbf._f, 1);
-  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
-  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
-  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_readw (&sf, &wd, string);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+  return __vfwscanf_internal (f, format, args, 0);
 }
 libc_hidden_def (__isoc99_vswscanf)
diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
index 049521b964..eb22c8acae 100644
--- a/wcsmbs/isoc99_vwscanf.c
+++ b/wcsmbs/isoc99_vwscanf.c
@@ -28,7 +28,7 @@ __isoc99_vwscanf (const wchar_t *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stdin);
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfwscanf (stdin, format, args, NULL);
+  done = __vfwscanf_internal (stdin, format, args, 0);
   _IO_release_lock (stdin);
   return done;
 }
diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
index abfbd50c11..59f80d78fb 100644
--- a/wcsmbs/isoc99_wscanf.c
+++ b/wcsmbs/isoc99_wscanf.c
@@ -33,7 +33,7 @@ __isoc99_wscanf (const wchar_t *format, ...)
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfwscanf (stdin, format, arg, NULL);
+  done = __vfwscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
   _IO_release_lock (stdin);
-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (5 preceding siblings ...)
  2018-03-07 19:32 ` [PATCH 5/9] Add __v*printf_internal with flags arguments Zack Weinberg
@ 2018-03-07 19:32 ` Zack Weinberg
  2018-03-13 11:59   ` Florian Weimer
  2018-03-07 19:51 ` [PATCH 9/9] Post-cleanup: don't include math.h/math_private.h in math_ldbl_opt.h Zack Weinberg
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:32 UTC (permalink / raw)
  To: libc-alpha

__nldbl___vsyslog_chk will ultimately want to pass PRINTF_LDBL_IS_DBL
down to __vfprintf_internal *as well as* possibly setting PRINTF_FORTIFY.
To make that possible, we need a __vsyslog_internal that takes the
same flags as printf.  The code in misc/syslog.c does also get a
little simpler.

	* misc/syslog.c: Include libioP.h, not iolibio.h.
	(__vsyslog_internal): New function with the former body of
	__vsyslog_chk; takes mode_flags argument same as
	__v*printf_internal.  Call __vfprintf_internal directly.

	(__vsyslog_chk): Now a wrapper around __vsyslog_internal.
	Remove libc_hidden_def.
	(__syslog, __syslog_chk): Use __vsyslog_internal.
	(__vsyslog): Move to just below __syslog.  Use __vsyslog_internal.

	* include/sys/syslog.h: Add multiple inclusion guard.
	Add prototype for __vsyslog_internal.
	Remove libc_hidden_proto for __vsyslog_chk.

	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl___vsyslog_chk):
	Use __vsyslog_internal.
---
 include/sys/syslog.h                    | 15 +++++++++++---
 misc/syslog.c                           | 35 ++++++++++++++++++---------------
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c |  2 +-
 3 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/include/sys/syslog.h b/include/sys/syslog.h
index 3be3189ed1..459ca70746 100644
--- a/include/sys/syslog.h
+++ b/include/sys/syslog.h
@@ -1,11 +1,20 @@
+#ifndef _LIBC_SYS_SYSLOG_H
+#define _LIBC_SYS_SYSLOG_H 1
 #include <misc/sys/syslog.h>
-
 #ifndef _ISOMAC
+
 libc_hidden_proto (syslog)
 libc_hidden_proto (vsyslog)
 
+/* __vsyslog_internal uses the same mode_flags bits as
+   __v*printf_internal; see libio/libioP.h.  */
+extern void __vsyslog_internal (int pri, const char *fmt, __gnuc_va_list ap,
+                                unsigned int mode_flags)
+     __attribute__ ((__format__ (__printf__, 2, 0)));
+
 extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
 			   __gnuc_va_list __ap)
      __attribute__ ((__format__ (__printf__, 3, 0)));
-libc_hidden_proto (__vsyslog_chk)
-#endif
+
+#endif /* _ISOMAC */
+#endif /* syslog.h */
diff --git a/misc/syslog.c b/misc/syslog.c
index 644dbe80ec..eb1283a604 100644
--- a/misc/syslog.c
+++ b/misc/syslog.c
@@ -53,7 +53,7 @@ static char sccsid[] = "@(#)syslog.c	8.4 (Berkeley) 3/18/94";
 
 #include <stdarg.h>
 
-#include <libio/iolibio.h>
+#include <libio/libioP.h>
 #include <math_ldbl_opt.h>
 
 #include <kernel-features.h>
@@ -114,24 +114,39 @@ __syslog(int pri, const char *fmt, ...)
 	va_list ap;
 
 	va_start(ap, fmt);
-	__vsyslog_chk(pri, -1, fmt, ap);
+	__vsyslog_internal(pri, fmt, ap, 0);
 	va_end(ap);
 }
 ldbl_hidden_def (__syslog, syslog)
 ldbl_strong_alias (__syslog, syslog)
 
+void
+__vsyslog(int pri, const char *fmt, va_list ap)
+{
+	__vsyslog_internal(pri, fmt, ap, 0);
+}
+ldbl_hidden_def (__vsyslog, vsyslog)
+ldbl_weak_alias (__vsyslog, vsyslog)
+
 void
 __syslog_chk(int pri, int flag, const char *fmt, ...)
 {
 	va_list ap;
 
 	va_start(ap, fmt);
-	__vsyslog_chk(pri, flag, fmt, ap);
+	__vsyslog_internal(pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
 	va_end(ap);
 }
 
 void
 __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
+{
+	__vsyslog_internal(pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
+}
+
+void
+__vsyslog_internal(int pri, const char *fmt, va_list ap,
+		   unsigned int mode_flags)
 {
 	struct tm now_tm;
 	time_t now;
@@ -216,10 +231,7 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
 
 	    /* We have the header.  Print the user's format into the
                buffer.  */
-	    if (flag == -1)
-	      vfprintf (f, fmt, ap);
-	    else
-	      __vfprintf_chk (f, flag, fmt, ap);
+            __vfprintf_internal (f, fmt, ap, mode_flags);
 
 	    /* Close the memory stream; this will finalize the data
 	       into a malloc'd buffer in BUF.  */
@@ -316,15 +328,6 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
 	if (buf != failbuf)
 		free (buf);
 }
-libc_hidden_def (__vsyslog_chk)
-
-void
-__vsyslog(int pri, const char *fmt, va_list ap)
-{
-  __vsyslog_chk (pri, -1, fmt, ap);
-}
-ldbl_hidden_def (__vsyslog, vsyslog)
-ldbl_weak_alias (__vsyslog, vsyslog)
 
 static struct sockaddr_un SyslogAddr;	/* AF_UNIX address of local logger */
 
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 7e8af80d63..f00eb55eb5 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -842,7 +842,7 @@ attribute_compat_text_section
 __nldbl___vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
 {
   set_no_long_double ();
-  __vsyslog_chk (pri, flag, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
   clear_no_long_double ();
 }
 libc_hidden_def (__nldbl___vsyslog_chk)
-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 8/9] Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
@ 2018-03-07 19:32 ` Zack Weinberg
  2018-03-07 19:32 ` [PATCH 3/9] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD Zack Weinberg
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:32 UTC (permalink / raw)
  To: libc-alpha

After all that prep work, nldbl-compat.c can now use PRINTF_LDBL_IS_DBL
instead of __no_long_double to control the behavior of printf-like
functions; this is the last thing we needed __no_long_double for, so it
can go away entirely.

	* stdio-common/vfprintf-internal.c
	(__vfprintf_internal, __vfwprintf_internal): Don't use __ldbl_is_dbl.
	* sysdeps/generic/math_ldbl_opt.h: Remove __ldbl_is_dbl.
	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h: Remove __ldbl_is_dbl
	and __no_long_double.
	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.c: Remove file.
	* sysdeps/ieee754/ldbl-opt/Makefile (routines): Remove math_ldbl_opt.
	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
	(__nldbl_cleanup, set_no_long_double, clear_no_long_double): Remove.
	(__nldbl___asprintf, __nldbl_dprintf, __nldbl_fprintf)
	(__nldbl_fwprintf, __nldbl_printf, __nldbl_sprintf)
	(__nldbl_vfprintf, __nldbl___vsprintf, __nldbl_obstack_vprintf)
	(__ndlbl_obstack_printf, __nldbl_snprintf, __nldbl_swprintf)
	(__nldbl_vasprintf, __nldbl_vdprintf, __nldbl_vfwprintf)
	(__nldbl_vprintf, __nldbl_vsnprintf, __ndlbl_vswprintf)
	(__nldbl_vwprintf, __nldbl_wprintf):
	Directly call the appropriate __v*printf_internal routine, passing
	PRINTF_LDBL_IS_DBL.  Do not mess with __no_long_double. Normalize
	variable names.
	(__nldbl___fprintf_chk, __nldbl___fwprintf_chk)
	(__nldbl___printf_chk, __nldbl___snprintf_chk)
	(__nldbl___sprintf_chk, __nldbl___swprintf_chk)
	(__nldbl___vfprintf_chk, __nldbl___vfwprintf_chk)
	(__nldbl___vprintf_chk, __nldbl___vsnprintf_chk)
	(__nldbl___vsprintf_chk, __nldbl___vswprintf_chk)
	(__nldbl___vwprintf_chk, __nldbl___wprintf_chk)
	(__nldbl___vasprintf_chk, __nldbl___asprintf_chk)
	(__nldbl___vdprintf_chk, __nldbl___dprintf_chk)
	(__nldbl___obstack_vprintf_chk, __nldbl___obstack_printf_chk):
	Likewise, and also pass PRINTF_FORTIFY when appropriate.
	(__nldbl_syslog, __nldbl_vsyslog):
	Directly call __vsyslog_internal, passing PRINTF_LDBL_IS_DBL.
	(__nldbl_syslog_chk): Likewise, and also pass PRINTF_FORTIFY when
	appropriate.
	(__nldbl_vsyslog_chk): Likewise, and also pass PRINTF_FORTIFY when
	appropriate.  Remove libc_hidden_proto and libc_hidden_def.
---
 stdio-common/vfprintf-internal.c         |   4 -
 sysdeps/generic/math_ldbl_opt.h          |   1 -
 sysdeps/ieee754/ldbl-opt/Makefile        |   2 +-
 sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h |   5 -
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c  | 472 ++++++++++++++++---------------
 5 files changed, 238 insertions(+), 246 deletions(-)

diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index e2f44b74f3..2d9016e83b 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -1282,10 +1282,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
      0 if unknown.  */
   int readonly_format = 0;
 
-  /* Temporarily honor environmental settings.  */
-  if (__ldbl_is_dbl)
-    mode_flags |= PRINTF_LDBL_IS_DBL;
-
   /* Orient the stream.  */
 #ifdef ORIENT
   ORIENT;
diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
index 92f670dff7..fbd2c82e2f 100644
--- a/sysdeps/generic/math_ldbl_opt.h
+++ b/sysdeps/generic/math_ldbl_opt.h
@@ -15,4 +15,3 @@
 #define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
 #define ldbl_compat_symbol(lib, local, symbol, version) \
   compat_symbol (lib, local, symbol, version)
-#define __ldbl_is_dbl 0
diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile
index 2340e4ce29..f23c6312ed 100644
--- a/sysdeps/ieee754/ldbl-opt/Makefile
+++ b/sysdeps/ieee754/ldbl-opt/Makefile
@@ -8,7 +8,7 @@ endif
 
 ifeq ($(subdir),math)
 libm-routines += s_nexttowardfd
-routines += math_ldbl_opt nldbl-compat
+routines += nldbl-compat
 
 extra-libs += libnldbl
 libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \
diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
index ee70d085fd..2b8f3e3c10 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -42,9 +42,4 @@
 #ifndef __ASSEMBLER__
 # include <math.h>
 # include <math_private.h>
-
-/* Set temporarily to non-zero if long double should be considered
-   the same as double.  */
-extern __thread int __no_long_double attribute_tls_model_ie attribute_hidden;
-# define __ldbl_is_dbl __builtin_expect (__no_long_double, 0)
 #endif
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index f29c28e888..e9cb5d32de 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -44,7 +44,6 @@ libc_hidden_proto (__nldbl_obstack_vprintf)
 libc_hidden_proto (__nldbl___vfwprintf_chk)
 libc_hidden_proto (__nldbl___vsnprintf_chk)
 libc_hidden_proto (__nldbl___vfprintf_chk)
-libc_hidden_proto (__nldbl___vsyslog_chk)
 libc_hidden_proto (__nldbl___vsprintf_chk)
 libc_hidden_proto (__nldbl___vswprintf_chk)
 libc_hidden_proto (__nldbl___vasprintf_chk)
@@ -55,17 +54,6 @@ libc_hidden_proto (__nldbl___isoc99_vfscanf)
 libc_hidden_proto (__nldbl___isoc99_vswscanf)
 libc_hidden_proto (__nldbl___isoc99_vfwscanf)
 
-static void
-__nldbl_cleanup (void *arg)
-{
-  __no_long_double = 0;
-}
-
-#define set_no_long_double() \
-  __libc_cleanup_push (__nldbl_cleanup, NULL); __no_long_double = 1
-#define clear_no_long_double() \
-  __no_long_double = 0; __libc_cleanup_pop (0)
-
 /* Compatibility with IEEE double as long double.
    IEEE quad long double is used by default for most programs, so
    we don't need to split this into one file per function for the
@@ -75,14 +63,14 @@ int
 attribute_compat_text_section
 __nldbl___asprintf (char **string_ptr, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vasprintf (string_ptr, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vasprintf_internal (string_ptr, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 weak_alias (__nldbl___asprintf, __nldbl_asprintf)
 
@@ -90,28 +78,28 @@ int
 attribute_compat_text_section
 __nldbl_dprintf (int d, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vdprintf (d, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vdprintf_internal (d, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_fprintf (FILE *stream, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfprintf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stream, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf)
 
@@ -119,28 +107,28 @@ int
 attribute_compat_text_section weak_function
 __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwprintf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stream, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_printf (const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfprintf (stdout, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 strong_alias (__nldbl_printf, __nldbl__IO_printf)
 
@@ -148,14 +136,14 @@ int
 attribute_compat_text_section
 __nldbl_sprintf (char *s, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vsprintf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vsprintf_internal (s, -1, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 strong_alias (__nldbl_sprintf, __nldbl__IO_sprintf)
 
@@ -163,11 +151,7 @@ int
 attribute_compat_text_section
 __nldbl_vfprintf (FILE *s, const char *fmt, va_list ap)
 {
-  int done;
-  set_no_long_double ();
-  done = __vfprintf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return done;
+  return __vfprintf_internal (s, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vfprintf)
 strong_alias (__nldbl_vfprintf, __nldbl__IO_vfprintf)
@@ -176,11 +160,7 @@ int
 attribute_compat_text_section
 __nldbl___vsprintf (char *string, const char *fmt, va_list ap)
 {
-  int done;
-  __no_long_double = 1;
-  done = __vsprintf_internal (string, -1, fmt, ap, 0);
-  __no_long_double = 0;
-  return done;
+  return __vsprintf_internal (string, -1, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 strong_alias (__nldbl___vsprintf, __nldbl__IO_vsprintf)
 weak_alias (__nldbl___vsprintf, __nldbl_vsprintf)
@@ -191,11 +171,7 @@ attribute_compat_text_section
 __nldbl_obstack_vprintf (struct obstack *obstack, const char *fmt,
 			 va_list ap)
 {
-  int done;
-  __no_long_double = 1;
-  done = __obstack_vprintf_internal (obstack, fmt, ap, 0);
-  __no_long_double = 0;
-  return done;
+  return __obstack_vprintf_internal (obstack, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_obstack_vprintf)
 
@@ -203,63 +179,55 @@ int
 attribute_compat_text_section
 __nldbl_obstack_printf (struct obstack *obstack, const char *fmt, ...)
 {
-  int result;
+  int ret;
   va_list ap;
   va_start (ap, fmt);
-  result = __nldbl_obstack_vprintf (obstack, fmt, ap);
+  ret = __obstack_vprintf_internal (obstack, fmt, ap, PRINTF_LDBL_IS_DBL);
   va_end (ap);
-  return result;
+  return ret;
 }
 
 int
 attribute_compat_text_section weak_function
 __nldbl_snprintf (char *s, size_t maxlen, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vsnprintf (s, maxlen, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vsnprintf_internal (s, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vswprintf (s, n, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vswprintf_internal (s, n, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section weak_function
 __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vasprintf_internal (result_ptr, fmt, ap, 0);
-  __no_long_double = 0;
-  return res;
+  return __vasprintf_internal (result_ptr, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vasprintf)
 
 int
 attribute_compat_text_section
-__nldbl_vdprintf (int d, const char *fmt, va_list arg)
+__nldbl_vdprintf (int d, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vdprintf_internal (d, fmt, arg, 0);
-  clear_no_long_double ();
-  return res;
+  return __vdprintf_internal (d, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vdprintf)
 
@@ -267,11 +235,7 @@ int
 attribute_compat_text_section weak_function
 __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfwprintf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return res;
+  return __vfwprintf_internal (s, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vfwprintf)
 
@@ -279,7 +243,7 @@ int
 attribute_compat_text_section
 __nldbl_vprintf (const char *fmt, va_list ap)
 {
-  return __nldbl_vfprintf (stdout, fmt, ap);
+  return __vfprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 
 int
@@ -287,11 +251,7 @@ attribute_compat_text_section
 __nldbl_vsnprintf (char *string, size_t maxlen, const char *fmt,
 		   va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vsnprintf_internal (string, maxlen, fmt, ap, 0);
-  __no_long_double = 0;
-  return res;
+  return __vsnprintf_internal (string, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vsnprintf)
 weak_alias (__nldbl_vsnprintf, __nldbl___vsnprintf)
@@ -301,11 +261,7 @@ attribute_compat_text_section weak_function
 __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
 		   va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vswprintf_internal (string, maxlen, fmt, ap, 0);
-  __no_long_double = 0;
-  return res;
+  return __vswprintf_internal (string, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vswprintf)
 
@@ -313,21 +269,21 @@ int
 attribute_compat_text_section
 __nldbl_vwprintf (const wchar_t *fmt, va_list ap)
 {
-  return __nldbl_vfwprintf (stdout, fmt, ap);
+  return __vfwprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 
 int
 attribute_compat_text_section
 __nldbl_wprintf (const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwprintf (stdout, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
@@ -490,42 +446,51 @@ int
 attribute_compat_text_section
 __nldbl___fprintf_chk (FILE *stream, int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfprintf_chk (stream, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stream, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfwprintf_chk (stream, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stream, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___printf_chk (int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfprintf_chk (stdout, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stdout, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
@@ -533,54 +498,72 @@ attribute_compat_text_section
 __nldbl___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
 			const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
 
-  va_start (arg, fmt);
-  done = __nldbl___vsnprintf_chk (s, maxlen, flag, slen, fmt, arg);
-  va_end (arg);
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  return done;
+  va_start (ap, fmt);
+  ret = __vsnprintf_internal (s, maxlen, fmt, ap, mode);
+  va_end (ap);
+
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___sprintf_chk (char *s, int flag, size_t slen, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  if (slen == 0)
+    __chk_fail ();
+
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vsprintf_chk (s, flag, slen, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vsprintf_internal (s, slen, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen,
+__nldbl___swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
 			const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vswprintf_chk (s, n, flag, slen, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vswprintf_internal (s, maxlen, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfprintf_internal (s, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vfprintf_chk)
 
@@ -588,11 +571,11 @@ int
 attribute_compat_text_section
 __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfwprintf_internal (s, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vfwprintf_chk)
 
@@ -600,7 +583,11 @@ int
 attribute_compat_text_section
 __nldbl___vprintf_chk (int flag, const char *fmt, va_list ap)
 {
-  return __nldbl___vfprintf_chk (stdout, flag, fmt, ap);
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfprintf_internal (stdout, fmt, ap, mode);
 }
 
 int
@@ -611,12 +598,11 @@ __nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen,
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  int res;
-  __no_long_double = 1;
-  res = __vsnprintf_internal (string, maxlen, fmt, ap,
-			      (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vsnprintf_internal (string, maxlen, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vsnprintf_chk)
 
@@ -628,12 +614,11 @@ __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
   if (slen == 0)
     __chk_fail ();
 
-  int res;
-  __no_long_double = 1;
-  res = __vsprintf_internal (string, slen, fmt, ap,
-			     (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vsprintf_internal (string, slen, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vsprintf_chk)
 
@@ -645,12 +630,11 @@ __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  int res;
-  __no_long_double = 1;
-  res = __vswprintf_internal (string, maxlen, fmt, ap,
-			      (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vswprintf_internal (string, maxlen, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vswprintf_chk)
 
@@ -658,33 +642,39 @@ int
 attribute_compat_text_section
 __nldbl___vwprintf_chk (int flag, const wchar_t *fmt, va_list ap)
 {
-  return __nldbl___vfwprintf_chk (stdout, flag, fmt, ap);
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfwprintf_internal (stdout, fmt, ap, mode);
 }
 
 int
 attribute_compat_text_section
 __nldbl___wprintf_chk (int flag, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfwprintf_chk (stdout, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stdout, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg)
+__nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vasprintf_internal (ptr, fmt, arg,
-			      (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vasprintf_internal (ptr, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vasprintf_chk)
 
@@ -692,25 +682,28 @@ int
 attribute_compat_text_section
 __nldbl___asprintf_chk (char **ptr, int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vasprintf_chk (ptr, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vasprintf_internal (ptr, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg)
+__nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vdprintf_internal (d, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vdprintf_chk)
 
@@ -718,27 +711,29 @@ int
 attribute_compat_text_section
 __nldbl___dprintf_chk (int d, int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vdprintf_chk (d, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vdprintf_internal (d, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag,
-			       const char *fmt, va_list arg)
+			       const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __obstack_vprintf_internal (obstack, fmt, arg,
-				    (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __obstack_vprintf_internal (obstack, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___obstack_vprintf_chk)
 
@@ -747,14 +742,17 @@ attribute_compat_text_section
 __nldbl___obstack_printf_chk (struct obstack *obstack, int flag,
 			      const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___obstack_vprintf_chk (obstack, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __obstack_vprintf_internal (obstack, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 extern __typeof (printf_size) __printf_size;
@@ -836,18 +834,28 @@ __nldbl_syslog (int pri, const char *fmt, ...)
 {
   va_list ap;
   va_start (ap, fmt);
-  __nldbl___vsyslog_chk (pri, -1, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_IS_DBL);
   va_end (ap);
 }
 
+void
+attribute_compat_text_section
+__nldbl_vsyslog (int pri, const char *fmt, va_list ap)
+{
+  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_IS_DBL);
+}
+
 void
 attribute_compat_text_section
 __nldbl___syslog_chk (int pri, int flag, const char *fmt, ...)
 {
   va_list ap;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
   va_start (ap, fmt);
-  __nldbl___vsyslog_chk (pri, flag, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, mode);
   va_end(ap);
 }
 
@@ -855,17 +863,11 @@ void
 attribute_compat_text_section
 __nldbl___vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
 {
-  set_no_long_double ();
-  __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-}
-libc_hidden_def (__nldbl___vsyslog_chk)
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-void
-attribute_compat_text_section
-__nldbl_vsyslog (int pri, const char *fmt, va_list ap)
-{
-  __nldbl___vsyslog_chk (pri, -1, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, mode);
 }
 
 int
-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 4/9] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (2 preceding siblings ...)
  2018-03-07 19:32 ` [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments Zack Weinberg
@ 2018-03-07 19:32 ` Zack Weinberg
  2018-03-14 12:22   ` Florian Weimer
  2018-03-26 15:36   ` Gabriel F. T. Gomes
  2018-03-07 19:32 ` [PATCH 1/9] Use STRFMON_LDBL_IS_DBL " Zack Weinberg
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:32 UTC (permalink / raw)
  To: libc-alpha

Change the callers of __vfscanf_internal and __vfwscanf_internal that
want to treat 'long double' as another name for 'double' (all of which
happen to be in sysdeps/ieee754/ldbl-opt/nldbl-compat.c) to communicate
this via the new flags argument, instead of the per-thread variable
__no_long_double and its __ldbl_is_dbl wrapper macro.

	* stdio-common/vfscanf-internal.c: Don't look at __ldbl_is_dbl.
	* sysdeps/ieee754/ldbl-opt/ndlbl-compat.c:
	Include libio/strfile.h instead of libioP.h.
	(__nldbl_IO_vfscanf, __ndlbl___vfscanf, __nldbl_sscanf)
	(__nldbl___vsscanf, __nldbl_vscanf, __nldbl_fscanf)
	(__nldbl_scanf, __nldbl_vfwscanf, __nldbl_swscanf)
	(__nldbl_vswscanf, __nldbl_vwscanf, __nldbl_fwscanf)
	(__nldbl_wscanf): Call __vfscanf_internal / __vfwscanf_internal
	directly, passing SCANF_LDBL_IS_DBL.  Set up a strfile if
	necessary.  Do not set __no_long_double.  Normalize variable names.

	(__nldbl___isoc99_vfscanf, __nldbl___isoc99_sscanf)
	(__nldbl___isoc99_vsscanf, __nldbl___isoc99_vscanf)
	(__nldbl___isoc99_fscanf, __nldbl___isoc99_scanf)
	(__nldbl___isoc99_vfwscanf, __nldbl___isoc99_swscanf)
	(__nldbl___isoc99_vswscanf, __nldbl___isoc99_vwscanf)
	(__nldbl___isoc99_fwscanf, __nldbl___isoc99_wscanf):
	Call __vfscanf_internal / __vfwscanf_internal directly, passing
	SCANF_LDBL_IS_DBL | SCANF_ISOC99_A.  Set up a strfile if necessary.
        Do not set __no_long_double.  Normalize variable names.
---
 stdio-common/vfscanf-internal.c         |   3 -
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 245 +++++++++++++++-----------------
 2 files changed, 116 insertions(+), 132 deletions(-)

diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 9f99d237d2..87b14edfdb 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -333,9 +333,6 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
 
 #define LDBL_DISTINCT (__glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
 #define USE_ISOC99_A  (__glibc_likely (mode_flags & SCANF_ISOC99_A))
-  /* Temporarily honor the environmental mode bits.  */
-  if (__ldbl_is_dbl)
-    mode_flags |= SCANF_LDBL_IS_DBL;
 
 #ifdef __va_copy
   __va_copy (arg, argptr);
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 9ac88deb74..15f212ffce 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -19,7 +19,7 @@
 
 #include <stdarg.h>
 #include <stdio.h>
-#include <libioP.h>
+#include <libio/strfile.h>
 #include <wchar.h>
 #include <printf.h>
 #include <monetary.h>
@@ -334,13 +334,10 @@ int
 attribute_compat_text_section
 __nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfscanf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
+  int ret = __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
   if (__glibc_unlikely (errp != 0))
-    *errp = (res == -1);
-  return res;
+    *errp = (ret == -1);
+  return ret;
 }
 #endif
 
@@ -348,11 +345,7 @@ int
 attribute_compat_text_section
 __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfscanf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return res;
+  return __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 weak_alias (__nldbl___vfscanf, __nldbl_vfscanf)
 libc_hidden_def (__nldbl_vfscanf)
@@ -361,26 +354,26 @@ int
 attribute_compat_text_section
 __nldbl_sscanf (const char *s, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vsscanf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 strong_alias (__nldbl_sscanf, __nldbl__IO_sscanf)
 
 int
 attribute_compat_text_section
-__nldbl___vsscanf (const char *string, const char *fmt, va_list ap)
+__nldbl___vsscanf (const char *s, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = _IO_vsscanf (string, fmt, ap);
-  __no_long_double = 0;
-  return res;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+  return __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 weak_alias (__nldbl___vsscanf, __nldbl_vsscanf)
 libc_hidden_def (__nldbl_vsscanf)
@@ -389,46 +382,42 @@ int
 attribute_compat_text_section weak_function
 __nldbl_vscanf (const char *fmt, va_list ap)
 {
-  return __nldbl_vfscanf (stdin, fmt, ap);
+  return __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 
 int
 attribute_compat_text_section
 __nldbl_fscanf (FILE *stream, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfscanf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (stream, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_scanf (const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfwscanf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return res;
+  return __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vfwscanf)
 
@@ -436,25 +425,28 @@ int
 attribute_compat_text_section
 __nldbl_swscanf (const wchar_t *s, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vswscanf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl_vswscanf (const wchar_t *string, const wchar_t *fmt, va_list ap)
+__nldbl_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = vswscanf (string, fmt, ap);
-  __no_long_double = 0;
-  return res;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+
+  return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vswscanf)
 
@@ -462,35 +454,35 @@ int
 attribute_compat_text_section weak_function
 __nldbl_vwscanf (const wchar_t *fmt, va_list ap)
 {
-  return __nldbl_vfwscanf (stdin, fmt, ap);
+  return __vfwscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 
 int
 attribute_compat_text_section
 __nldbl_fwscanf (FILE *stream, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwscanf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (stream, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_wscanf (const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
@@ -865,11 +857,7 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_vfscanf (FILE *s, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __isoc99_vfscanf (s, fmt, ap);
-  clear_no_long_double ();
-  return res;
+  return __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 libc_hidden_def (__nldbl___isoc99_vfscanf)
 
@@ -877,25 +865,26 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_sscanf (const char *s, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vsscanf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___isoc99_vsscanf (const char *string, const char *fmt, va_list ap)
+__nldbl___isoc99_vsscanf (const char *s, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __isoc99_vsscanf (string, fmt, ap);
-  __no_long_double = 0;
-  return res;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+
+  return __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 libc_hidden_def (__nldbl___isoc99_vsscanf)
 
@@ -903,46 +892,42 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_vscanf (const char *fmt, va_list ap)
 {
-  return __nldbl___isoc99_vfscanf (stdin, fmt, ap);
+  return __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 
 int
 attribute_compat_text_section
-__nldbl___isoc99_fscanf (FILE *stream, const char *fmt, ...)
+__nldbl___isoc99_fscanf (FILE *s, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfscanf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___isoc99_scanf (const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int rv;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  rv = __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return rv;
 }
 
 int
 attribute_compat_text_section
 __nldbl___isoc99_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __isoc99_vfwscanf (s, fmt, ap);
-  clear_no_long_double ();
-  return res;
+  return __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 libc_hidden_def (__nldbl___isoc99_vfwscanf)
 
@@ -950,26 +935,28 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_swscanf (const wchar_t *s, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vswscanf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___isoc99_vswscanf (const wchar_t *string, const wchar_t *fmt,
-			   va_list ap)
+__nldbl___isoc99_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __isoc99_vswscanf (string, fmt, ap);
-  __no_long_double = 0;
-  return res;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+
+  return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 libc_hidden_def (__nldbl___isoc99_vswscanf)
 
@@ -982,30 +969,30 @@ __nldbl___isoc99_vwscanf (const wchar_t *fmt, va_list ap)
 
 int
 attribute_compat_text_section
-__nldbl___isoc99_fwscanf (FILE *stream, const wchar_t *fmt, ...)
+__nldbl___isoc99_fwscanf (FILE *s, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfwscanf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___isoc99_wscanf (const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfwscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add __v*printf_internal with flags arguments.
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (4 preceding siblings ...)
  2018-03-07 19:32 ` [PATCH 1/9] Use STRFMON_LDBL_IS_DBL " Zack Weinberg
@ 2018-03-07 19:32 ` Zack Weinberg
  2018-03-26 15:41   ` Gabriel F. T. Gomes
  2018-03-07 19:32 ` [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal Zack Weinberg
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:32 UTC (permalink / raw)
  To: libc-alpha

There are a lot more printf variants than there are scanf variants,
and the code for setting up and tearing down their custom FILE
variants around the call to __vf(w)printf is more complicated and
variable.  Therefore, I have added _internal versions of all the
v*printf variants, rather than introducing helper routines so that
they can all directly call __vf(w)printf_internal, as was done with
scanf.

As with the scanf changes, in this patch the _internal functions still
look at the environmental mode bits and all callers pass 0 for the flags
parameter.

Several of the affected public functions had _IO_ name aliases that
were not exported (but, in one case, appeared in libio.h anyway);
I was originally planning to leave them as aliases to avoid having
to touch internal callers, but it turns out ldbl_*_alias only work
for exported symbols, so they've all been removed instead.  It also
turns out there were hardly any internal callers.  _IO_vsprintf
*is* exported, so that one sticks around.

	* libio/libioP.h (__vfprintf_internal, __vfwprintf_internal)
	(__vasprintf_internal, __vdprintf_internal, __obstack_vprintf_internal)
	(__vsprintf_internal, __vsnprintf_internal, __vswprintf_internal):
	New functions.
	(PRINTF_LDBL_IS_DBL, PRINTF_FORTIFY): New constants.
	(_IO_vasprintf, _IO_vdprintf, _IO_vsnprintf): Remove prototypes.

	* stdio-common/vfprintf-internal.c: Rename from vfprintf.c.
	Include wctype.h here if COMPILE_WPRINTF is defined.
	Define __vfprintf_internal or __vfwprintf_internal, depending
	on COMPILE_WPRINTF.
	Temporarily, on entry to this function, update mode_flags
	according to the environmental settings corresponding to
	PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY.
	(LDBL_IS_DBL, DO_FORTIFY): New macros.	Throughout, use
	LDBL_IS_DBL instead of __ldbl_is_dbl, and DO_FORTIFY instead of
	checking _IO_FLAGS2_FORTIFY on the destination FILE.
	* stdio-common/vfwprintf-internal.c: Rename from vfwprintf.c.
	Include vfprintf-internal.c.  Don't include wctype.h.
	* stdio-common/vfprintf.c: New file.  Just define __vfprintf
	as a wrapper around __vfprintf_internal, with aliases _IO_vfprintf
	and vfprintf.
	* stdio-common/vfwprintf.c: New file.  Just define __vfwprintf
	as a wrapper around __vfwprintf_internal, with aliases _IO_vfwprintf
	and vfwprintf.
	* stdio-common/Makefile: Add vfprintf-internal and vfwprintf-internal.

	* libio/iovdprintf.c (_IO_vdprintf): Rename to __vdprintf_internal
	and add mode_flags argument; use __vfprintf_internal.
	(__vdprintf): New function.  Alias vdprintf to this.
	* libio/iovsprintf.c (_IO_vsprintf, __vsprintf): Similarly.
	* libio/vasprintf.c (_IO_vasprintf, __vasprintf): Similarly.
	* libio/obprintf.c (_IO_obstack_vprintf, __obstack_vprintf): Similarly.
	(__obstack_printf): Use __obstack_printf_internal.
	* libio/vsnprintf.c (_IO_vsnprintf, ___vsnprintf): Similarly, with
	public aliases __vsnprintf and vsnprintf.
	* libio/vswprintf (_IO_vswprintf, __vswprintf): Similarly, with
	public aliases _IO_vsprintf and vsprintf.
	* libio/swprintf.c (__swprintf): Use __vswprintf_internal.
	* stdio-common/asprintf.c (__asprintf): Use __vasprintf_internal.
	* stdio-common/dprintf.c (__dprintf): Use __vdprintf_internal.
	* stdio-common/snprintf.c (__snprintf): Use __vsprintf_internal.
	* stdio-common/sprintf.c (__sprintf): Use __vsprintf_internal.

	* debug/obprintf_chk.c, debug/vasprintf_chk.c, debug/vdprintf_chk.c
	* debug/vsnprintf_chk.c, debug/vsprintf_chk.c, hurd/vpprintf.c
	* stdio-common/fprintf.c, stdio-common/fxprintf.c
	* stdio-common/printf.c: Use __vfprintf_internal.

	* debug/fwprintf_chk.c, debug/vfwprintf_chk.c, debug/vswprintf_chk.c
	* debug/vwprintf_chk.c, debug/wprintf_chk.c, libio/fwprintf.c
	* libio/vwprintf.c, libio/wprintf.c: Use __vfwprintf_internal.

	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Use __vsprintf_internal,
	__obstack_vprintf_internal, __vasprintf_internal, __vdprintf_internal,
	__vsnprintf_internal, __vswprintf_internal, __vfprintf_internal, and
	__vfwprintf_internal.

	* libio/libio.h: Remove libc_hidden_proto for _IO_vfprintf.
	Remove declaration of _IO_vfwprintf.
	* libio/iolibio.h: Remove libc_hidden_proto for _IO_vsprintf.
	Remove declarations of _IO_vswprintf, _IO_obstack_printf, and
	_IO_obstack_printf.
	* include/stdio.h: Add libc_hidden_proto for __vsnprintf and
	prototype for __vasprintf.

	* argp/argp-fmtstream.c: Use __vsnprintf, not _IO_vsnprintf.
	* argp/argp-help.c: Use __vasprintf, not _IO_vasprintf.
	* argp/argp-namefrob.c: Update to match.
---
 argp/argp-fmtstream.c                              |    1 -
 argp/argp-help.c                                   |    4 +-
 argp/argp-namefrob.h                               |    2 +
 debug/fwprintf_chk.c                               |    2 +-
 debug/obprintf_chk.c                               |    2 +-
 debug/vasprintf_chk.c                              |    2 +-
 debug/vdprintf_chk.c                               |    2 +-
 debug/vfwprintf_chk.c                              |    2 +-
 debug/vsnprintf_chk.c                              |    2 +-
 debug/vsprintf_chk.c                               |    2 +-
 debug/vswprintf_chk.c                              |    2 +-
 debug/vwprintf_chk.c                               |    2 +-
 debug/wprintf_chk.c                                |    2 +-
 hurd/vpprintf.c                                    |    2 +-
 include/stdio.h                                    |    4 +
 libio/fwprintf.c                                   |    2 +-
 libio/iolibio.h                                    |    7 -
 libio/iovdprintf.c                                 |   13 +-
 libio/iovsprintf.c                                 |   16 +-
 libio/libio.h                                      |    3 -
 libio/libioP.h                                     |   32 +-
 libio/obprintf.c                                   |   19 +-
 libio/swprintf.c                                   |    2 +-
 libio/vasprintf.c                                  |   20 +-
 libio/vsnprintf.c                                  |   17 +-
 libio/vswprintf.c                                  |   16 +-
 libio/vwprintf.c                                   |    2 +-
 libio/wprintf.c                                    |    2 +-
 stdio-common/Makefile                              |    3 +-
 stdio-common/asprintf.c                            |    7 +-
 stdio-common/dprintf.c                             |    5 +-
 stdio-common/fprintf.c                             |    2 +-
 stdio-common/fxprintf.c                            |    4 +-
 stdio-common/printf.c                              |    3 +-
 stdio-common/snprintf.c                            |    4 +-
 stdio-common/sprintf.c                             |    4 +-
 stdio-common/{vfprintf.c => vfprintf-internal.c}   |   68 +-
 stdio-common/vfprintf.c                            |   27 +
 stdio-common/{vfwprintf.c => vfwprintf-internal.c} |    3 +-
 stdio-common/vfwprintf.c                           |   25 +
 stdio-common/vprintf.c                             |    4 +-
 stdlib/strfrom-skeleton.c                          |    2 +-
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c |   21 +-
 43 files changed, 210 insertions(+), 131 deletions(-)
 create mode 100644 stdio-common/vfprintf.c
 create mode 100644 stdio-common/vfwprintf.c

diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c
index e43a0c7cf1..2be2f521ad 100644
--- a/argp/argp-fmtstream.c
+++ b/argp/argp-fmtstream.c
@@ -42,7 +42,6 @@
 #ifdef _LIBC
 # include <wchar.h>
 # include <libio/libioP.h>
-# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
 #endif
 
 #define INIT_BUF_SIZE 200
diff --git a/argp/argp-help.c b/argp/argp-help.c
index 2b6b0775d6..9f25338ca0 100644
--- a/argp/argp-help.c
+++ b/argp/argp-help.c
@@ -1769,7 +1769,7 @@ __argp_error (const struct argp_state *state, const char *fmt, ...)
 #ifdef _LIBC
 	  char *buf;
 
-	  if (_IO_vasprintf (&buf, fmt, ap) < 0)
+	  if (__vasprintf (&buf, fmt, ap) < 0)
 	    buf = NULL;
 
 	  __fxprintf (stream, "%s: %s\n",
@@ -1839,7 +1839,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
 #ifdef _LIBC
 	      char *buf;
 
-	      if (_IO_vasprintf (&buf, fmt, ap) < 0)
+	      if (__vasprintf (&buf, fmt, ap) < 0)
 		buf = NULL;
 
 	      __fxprintf (stream, ": %s", buf);
diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h
index 5588fe172a..60381e7cd8 100644
--- a/argp/argp-namefrob.h
+++ b/argp/argp-namefrob.h
@@ -98,6 +98,8 @@
 #define __strerror_r strerror_r
 #undef __strndup
 #define __strndup strndup
+#undef __vasprintf
+#define __vasprintf vasprintf
 #undef __vsnprintf
 #define __vsnprintf vsnprintf
 
diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
index aeb83077da..63167c1839 100644
--- a/debug/fwprintf_chk.c
+++ b/debug/fwprintf_chk.c
@@ -32,7 +32,7 @@ __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
     fp->_flags2 |= _IO_FLAGS2_FORTIFY;
 
   va_start (ap, format);
-  done = _IO_vfwprintf (fp, format, ap);
+  done = __vfwprintf_internal (fp, format, ap, 0);
   va_end (ap);
 
   if (flag > 0)
diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index 3ac5a3cd4f..41dd481c34 100644
--- a/debug/obprintf_chk.c
+++ b/debug/obprintf_chk.c
@@ -91,7 +91,7 @@ __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
   if (flags > 0)
     new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;
 
-  result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
+  result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);
 
   /* Shrink the buffer to the space we really currently need.  */
   obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
index 46603d9538..6136694431 100644
--- a/debug/vasprintf_chk.c
+++ b/debug/vasprintf_chk.c
@@ -63,7 +63,7 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format,
   if (flags > 0)
     sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
 
-  ret = _IO_vfprintf (&sf._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf._sbf._f, format, args, 0);
   if (ret < 0)
     {
       free (sf._sbf._f._IO_buf_base);
diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
index bc713b4962..4386127cfe 100644
--- a/debug/vdprintf_chk.c
+++ b/debug/vdprintf_chk.c
@@ -55,7 +55,7 @@ __vdprintf_chk (int d, int flags, const char *format, va_list arg)
   if (flags > 0)
     tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
 
-  done = _IO_vfprintf (&tmpfil.file, format, arg);
+  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
 
   _IO_FINISH (&tmpfil.file);
 
diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c
index 1ffd18cbd2..abf2bd6517 100644
--- a/debug/vfwprintf_chk.c
+++ b/debug/vfwprintf_chk.c
@@ -30,7 +30,7 @@ __vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap)
   if (flag > 0)
     fp->_flags2 |= _IO_FLAGS2_FORTIFY;
 
-  done = _IO_vfwprintf (fp, format, ap);
+  done = __vfwprintf_internal (fp, format, ap, 0);
 
   if (flag > 0)
     fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index d20d0fbd93..95d286f416 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -60,7 +60,7 @@ ___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
     sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
 
   _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
-  ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
 
   if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
     *sf.f._sbf._f._IO_write_ptr = '\0';
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
index 9a443bb699..53f07236ae 100644
--- a/debug/vsprintf_chk.c
+++ b/debug/vsprintf_chk.c
@@ -80,7 +80,7 @@ ___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
   if (flags > 0)
     f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
 
-  ret = _IO_vfprintf (&f._sbf._f, format, args);
+  ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
 
   *f._sbf._f._IO_write_ptr = '\0';
   return ret;
diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
index c6a7edcacd..4d616f8835 100644
--- a/debug/vswprintf_chk.c
+++ b/debug/vswprintf_chk.c
@@ -59,7 +59,7 @@ __vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
     sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
 
   _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
-  ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
+  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
 
   if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
     /* ISO C99 requires swprintf/vswprintf to return an error if the
diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
index 51b67c159d..fedc7a46bf 100644
--- a/debug/vwprintf_chk.c
+++ b/debug/vwprintf_chk.c
@@ -31,7 +31,7 @@ __vwprintf_chk (int flag, const wchar_t *format, va_list ap)
   if (flag > 0)
     stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
 
-  done = _IO_vfwprintf (stdout, format, ap);
+  done = __vfwprintf_internal (stdout, format, ap, 0);
 
   if (flag > 0)
     stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
index 17023b6bb4..819050e5af 100644
--- a/debug/wprintf_chk.c
+++ b/debug/wprintf_chk.c
@@ -33,7 +33,7 @@ __wprintf_chk (int flag, const wchar_t *format, ...)
     stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
 
   va_start (ap, format);
-  done = _IO_vfwprintf (stdout, format, ap);
+  done = __vfwprintf_internal (stdout, format, ap, 0);
   va_end (ap);
 
   if (flag > 0)
diff --git a/hurd/vpprintf.c b/hurd/vpprintf.c
index 76cd31f922..b9634afc2b 100644
--- a/hurd/vpprintf.c
+++ b/hurd/vpprintf.c
@@ -53,7 +53,7 @@ vpprintf (io_t port, const char *format, va_list arg)
   _IO_cookie_init (&temp_f.cfile, _IO_NO_READS,
 		   (void *) port, (cookie_io_functions_t) { write: do_write });
 
-  done = _IO_vfprintf (&temp_f.cfile.__fp.file, format, arg);
+  done = __vfprintf_internal (&temp_f.cfile.__fp.file, format, arg, 0);
 
   return done;
 }
diff --git a/include/stdio.h b/include/stdio.h
index f140813ad6..93b9385524 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -17,6 +17,10 @@ libc_hidden_proto (__snprintf)
 extern int __vsnprintf (char *__restrict __s, size_t __maxlen,
 			const char *__restrict __format, __gnuc_va_list __arg)
      __attribute__ ((__format__ (__printf__, 3, 0)));
+libc_hidden_proto (__vsnprintf)
+extern int __vasprintf (char **__result_ptr, const char *__restrict __format,
+			va_list args)
+     __attribute__ ((__format__ (__printf__, 2, 0)));
 extern int __vfscanf (FILE *__restrict __s,
 		      const char *__restrict __format,
 		      __gnuc_va_list __arg)
diff --git a/libio/fwprintf.c b/libio/fwprintf.c
index fab63a8716..9903f1f342 100644
--- a/libio/fwprintf.c
+++ b/libio/fwprintf.c
@@ -30,7 +30,7 @@ __fwprintf (FILE *stream, const wchar_t *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vfwprintf (stream, format, arg);
+  done = __vfwprintf_internal (stream, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/libio/iolibio.h b/libio/iolibio.h
index 69e1c0e699..3a6a27a58c 100644
--- a/libio/iolibio.h
+++ b/libio/iolibio.h
@@ -51,14 +51,7 @@ extern int _IO_sprintf (char *, const char*, ...) __THROW;
 extern int _IO_ungetc (int, FILE*) __THROW;
 extern int _IO_vsscanf (const char *, const char *, __gnuc_va_list) __THROW;
 extern int _IO_vsprintf (char*, const char*, __gnuc_va_list) __THROW;
-libc_hidden_proto (_IO_vsprintf)
-extern int _IO_vswprintf (wchar_t*, size_t, const wchar_t*, __gnuc_va_list)
-       __THROW;
 
-struct obstack;
-extern int _IO_obstack_vprintf (struct obstack *, const char *, __gnuc_va_list)
-       __THROW;
-extern int _IO_obstack_printf (struct obstack *, const char *, ...) __THROW;
 #define _IO_clearerr(FP) ((FP)->_flags &= ~(_IO_ERR_SEEN|_IO_EOF_SEEN))
 #define _IO_fseek(__fp, __offset, __whence) \
   (_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT) \
diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c
index 78a3a2bd15..afdeff056d 100644
--- a/libio/iovdprintf.c
+++ b/libio/iovdprintf.c
@@ -28,7 +28,8 @@
 #include <stdio_ext.h>
 
 int
-_IO_vdprintf (int d, const char *format, va_list arg)
+__vdprintf_internal (int d, const char *format, va_list arg,
+                     unsigned int mode_flags)
 {
   struct _IO_FILE_plus tmpfil;
   struct _IO_wide_data wd;
@@ -50,7 +51,7 @@ _IO_vdprintf (int d, const char *format, va_list arg)
   _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
 		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
 
-  done = _IO_vfprintf (&tmpfil.file, format, arg);
+  done = __vfprintf_internal (&tmpfil.file, format, arg, mode_flags);
 
   if (done != EOF && _IO_do_flush (&tmpfil.file) == EOF)
     done = EOF;
@@ -59,4 +60,10 @@ _IO_vdprintf (int d, const char *format, va_list arg)
 
   return done;
 }
-ldbl_weak_alias (_IO_vdprintf, vdprintf)
+
+int
+__vdprintf (int d, const char *format, va_list arg)
+{
+  return __vdprintf_internal (d, format, arg, 0);
+}
+ldbl_weak_alias (__vdprintf, vdprintf)
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 4def251701..cf4b9973a7 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -28,7 +28,8 @@
 #include "strfile.h"
 
 int
-__IO_vsprintf (char *string, const char *format, va_list args)
+__vsprintf_internal (char *string, const char *format, va_list args,
+                     unsigned int mode_flags)
 {
   _IO_strfile sf;
   int ret;
@@ -39,11 +40,16 @@ __IO_vsprintf (char *string, const char *format, va_list args)
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
   _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
   _IO_str_init_static_internal (&sf, string, -1, string);
-  ret = _IO_vfprintf (&sf._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
   _IO_putc_unlocked ('\0', &sf._sbf._f);
   return ret;
 }
-ldbl_hidden_def (__IO_vsprintf, _IO_vsprintf)
 
-ldbl_strong_alias (__IO_vsprintf, _IO_vsprintf)
-ldbl_weak_alias (__IO_vsprintf, vsprintf)
+int
+__vsprintf (char *string, const char *format, va_list args)
+{
+  return __vsprintf_internal (string, format, args, 0);
+}
+
+ldbl_strong_alias (__vsprintf, _IO_vsprintf)
+ldbl_weak_alias (__vsprintf, vsprintf)
diff --git a/libio/libio.h b/libio/libio.h
index 30cb7d784f..1025f3343e 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -298,8 +298,6 @@ weak_extern (_IO_stdin_used);
 
 extern int _IO_vfwscanf (FILE * __restrict, const wchar_t * __restrict,
 			 __gnuc_va_list, int *__restrict);
-extern int _IO_vfwprintf (FILE *__restrict, const wchar_t *__restrict,
-			  __gnuc_va_list);
 extern __ssize_t _IO_wpadn (FILE *, wint_t, __ssize_t);
 extern void _IO_free_wbackup_area (FILE *) __THROW;
 
@@ -319,7 +317,6 @@ libc_hidden_proto (_IO_free_wbackup_area)
 libc_hidden_proto (_IO_padn)
 libc_hidden_proto (_IO_putc)
 libc_hidden_proto (_IO_sgetn)
-libc_hidden_proto (_IO_vfprintf)
 
 #ifdef _IO_MTSAFE_IO
 # undef _IO_peekc
diff --git a/libio/libioP.h b/libio/libioP.h
index 0772fb1431..17eda383d3 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -658,12 +658,32 @@ extern off64_t _IO_wstr_seekoff (FILE *, off64_t, int, int)
 extern wint_t _IO_wstr_pbackfail (FILE *, wint_t) __THROW;
 extern void _IO_wstr_finish (FILE *, int) __THROW;
 
-extern int _IO_vasprintf (char **result_ptr, const char *format,
-			  va_list args) __THROW;
-extern int _IO_vdprintf (int d, const char *format, va_list arg);
-extern int _IO_vsnprintf (char *string, size_t maxlen,
-			  const char *format, va_list args) __THROW;
-
+/* Internal versions of v*printf that take an additional flags
+   parameter.  */
+extern int __vfprintf_internal (FILE *fp, const char *format, va_list ap,
+                                unsigned int mode_flags);
+extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap,
+                                 unsigned int mode_flags);
+
+extern int __vasprintf_internal (char **result_ptr, const char *format,
+                                 va_list ap, unsigned int mode_flags);
+extern int __vdprintf_internal (int d, const char *format, va_list ap,
+                                unsigned int mode_flags);
+extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
+                                       va_list ap, unsigned int mode_flags);
+
+extern int __vsprintf_internal (char *string, const char *format, va_list ap,
+                                unsigned int mode_flags);
+extern int __vsnprintf_internal (char *string, size_t maxlen,
+                                 const char *format, va_list ap,
+                                 unsigned int mode_flags);
+extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
+                                 const wchar_t *format, va_list ap,
+                                 unsigned int mode_flags);
+
+/* Flags for __v*printf_internal.  */
+#define PRINTF_LDBL_IS_DBL 0x0001
+#define PRINTF_FORTIFY     0x0002
 
 extern size_t _IO_getline (FILE *,char *, size_t, int, int);
 libc_hidden_proto (_IO_getline)
diff --git a/libio/obprintf.c b/libio/obprintf.c
index a74f9467a2..6bb51a411a 100644
--- a/libio/obprintf.c
+++ b/libio/obprintf.c
@@ -117,7 +117,8 @@ const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden =
 
 
 int
-_IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
+__obstack_vprintf_internal (struct obstack *obstack, const char *format,
+                            va_list args, unsigned int mode_flags)
 {
   struct obstack_FILE
     {
@@ -164,7 +165,8 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
 
   new_f.ofile.obstack = obstack;
 
-  result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
+  result = __vfprintf_internal (&new_f.ofile.file.file, format, args,
+                                mode_flags);
 
   /* Shrink the buffer to the space we really currently need.  */
   obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
@@ -172,17 +174,22 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
 
   return result;
 }
-ldbl_weak_alias (_IO_obstack_vprintf, obstack_vprintf)
 
+int
+__obstack_vprintf (struct obstack *obstack, const char *format, va_list ap)
+{
+  return __obstack_vprintf_internal (obstack, format, ap, 0);
+}
+ldbl_weak_alias (__obstack_vprintf, obstack_vprintf)
 
 int
-_IO_obstack_printf (struct obstack *obstack, const char *format, ...)
+__obstack_printf (struct obstack *obstack, const char *format, ...)
 {
   int result;
   va_list ap;
   va_start (ap, format);
-  result = _IO_obstack_vprintf (obstack, format, ap);
+  result = __obstack_vprintf_internal (obstack, format, ap, 0);
   va_end (ap);
   return result;
 }
-ldbl_weak_alias (_IO_obstack_printf, obstack_printf)
+ldbl_weak_alias (__obstack_printf, obstack_printf)
diff --git a/libio/swprintf.c b/libio/swprintf.c
index 10f722d035..19b3f33198 100644
--- a/libio/swprintf.c
+++ b/libio/swprintf.c
@@ -28,7 +28,7 @@ __swprintf (wchar_t *s, size_t n, const wchar_t *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vswprintf (s, n, format, arg);
+  done = __vswprintf_internal (s, n, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/libio/vasprintf.c b/libio/vasprintf.c
index 08218ddbe7..5307f95fd5 100644
--- a/libio/vasprintf.c
+++ b/libio/vasprintf.c
@@ -24,15 +24,13 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <malloc.h>
 #include <string.h>
-#include "libioP.h"
-#include "stdio.h"
-#include <stdio_ext.h>
-#include "strfile.h"
+#include <stdlib.h>
+#include <strfile.h>
 
 int
-_IO_vasprintf (char **result_ptr, const char *format, va_list args)
+__vasprintf_internal (char **result_ptr, const char *format, va_list args,
+                      unsigned int mode_flags)
 {
   /* Initial size of the buffer to be used.  Will be doubled each time an
      overflow occurs.  */
@@ -56,7 +54,7 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
   sf._sbf._f._flags &= ~_IO_USER_BUF;
   sf._s._allocate_buffer = (_IO_alloc_type) malloc;
   sf._s._free_buffer = (_IO_free_type) free;
-  ret = _IO_vfprintf (&sf._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
   if (ret < 0)
     {
       free (sf._sbf._f._IO_buf_base);
@@ -85,4 +83,10 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
   (*result_ptr)[needed - 1] = '\0';
   return ret;
 }
-ldbl_weak_alias (_IO_vasprintf, vasprintf)
+
+int
+__vasprintf (char **result_ptr, const char *format, va_list args)
+{
+  return __vasprintf_internal (result_ptr, format, args, 0);
+}
+ldbl_weak_alias (__vasprintf, vasprintf)
diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
index 39b5500528..8a5d0bacf3 100644
--- a/libio/vsnprintf.c
+++ b/libio/vsnprintf.c
@@ -90,8 +90,8 @@ const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden =
 
 
 int
-_IO_vsnprintf (char *string, size_t maxlen, const char *format,
-	       va_list args)
+__vsnprintf_internal (char *string, size_t maxlen, const char *format,
+                      va_list args, unsigned int mode_flags)
 {
   _IO_strnfile sf;
   int ret;
@@ -111,11 +111,18 @@ _IO_vsnprintf (char *string, size_t maxlen, const char *format,
   _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
   string[0] = '\0';
   _IO_str_init_static_internal (&sf.f, string, maxlen - 1, string);
-  ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, mode_flags);
 
   if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
     *sf.f._sbf._f._IO_write_ptr = '\0';
   return ret;
 }
-ldbl_weak_alias (_IO_vsnprintf, __vsnprintf)
-ldbl_weak_alias (_IO_vsnprintf, vsnprintf)
+
+int
+___vsnprintf (char *string, size_t maxlen, const char *format, va_list args)
+{
+  return __vsnprintf_internal (string, maxlen, format, args, 0);
+}
+ldbl_weak_alias (___vsnprintf, __vsnprintf)
+ldbl_hidden_def (___vsnprintf, __vsnprintf)
+ldbl_weak_alias (___vsnprintf, vsnprintf)
diff --git a/libio/vswprintf.c b/libio/vswprintf.c
index bcc473d115..71d4e6ccd4 100644
--- a/libio/vswprintf.c
+++ b/libio/vswprintf.c
@@ -89,8 +89,8 @@ const struct _IO_jump_t _IO_wstrn_jumps libio_vtable attribute_hidden =
 
 
 int
-_IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
-	       va_list args)
+__vswprintf_internal (wchar_t *string, size_t maxlen, const wchar_t *format,
+                      va_list args, unsigned int mode_flags)
 {
   _IO_wstrnfile sf;
   int ret;
@@ -108,7 +108,7 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
   _IO_fwide (&sf.f._sbf._f, 1);
   string[0] = L'\0';
   _IO_wstr_init_static (&sf.f._sbf._f, string, maxlen - 1, string);
-  ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
+  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, mode_flags);
 
   if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
     /* ISO C99 requires swprintf/vswprintf to return an error if the
@@ -120,5 +120,11 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
 
   return ret;
 }
-weak_alias (_IO_vswprintf, __vswprintf)
-ldbl_weak_alias (_IO_vswprintf, vswprintf)
+
+int
+__vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
+             va_list args)
+{
+  return __vswprintf_internal (string, maxlen, format, args, 0);
+}
+ldbl_weak_alias (__vswprintf, vswprintf)
diff --git a/libio/vwprintf.c b/libio/vwprintf.c
index 72ebfec92d..e8a529afff 100644
--- a/libio/vwprintf.c
+++ b/libio/vwprintf.c
@@ -25,6 +25,6 @@
 int
 __vwprintf (const wchar_t *format, __gnuc_va_list arg)
 {
-  return __vfwprintf (stdout, format, arg);
+  return __vfwprintf_internal (stdout, format, arg, 0);
 }
 ldbl_strong_alias (__vwprintf, vwprintf)
diff --git a/libio/wprintf.c b/libio/wprintf.c
index 5945f651fc..361cd40a1b 100644
--- a/libio/wprintf.c
+++ b/libio/wprintf.c
@@ -29,7 +29,7 @@ __wprintf (const wchar_t *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vfwprintf (stdout, format, arg);
+  done = __vfwprintf_internal (stdout, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index b7b1f01bdd..1c657efa86 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -40,7 +40,8 @@ routines	:=							      \
 	isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
 	isoc99_vsscanf							      \
 	psiginfo gentempfd						      \
-	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
+	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf		      \
+	vfprintf-internal vfwprintf-internal
 
 aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
 
diff --git a/stdio-common/asprintf.c b/stdio-common/asprintf.c
index bff858e657..5f5ca6c4a6 100644
--- a/stdio-common/asprintf.c
+++ b/stdio-common/asprintf.c
@@ -16,11 +16,8 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-
 #include <libioP.h>
-#define vasprintf(s, f, a) _IO_vasprintf (s, f, a)
-#undef __asprintf
+
 
 /* Write formatted output from FORMAT to a string which is
    allocated with malloc and stored in *STRING_PTR.  */
@@ -32,7 +29,7 @@ ___asprintf (char **string_ptr, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vasprintf (string_ptr, format, arg);
+  done = __vasprintf_internal (string_ptr, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/dprintf.c b/stdio-common/dprintf.c
index 11bd12b838..9adc8ae4c7 100644
--- a/stdio-common/dprintf.c
+++ b/stdio-common/dprintf.c
@@ -16,10 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-
 #include <libioP.h>
-#define vdprintf(d, f, a) _IO_vdprintf (d, f, a)
 
 /* Write formatted output to D, according to the format string FORMAT.  */
 /* VARARGS2 */
@@ -30,7 +27,7 @@ __dprintf (int d, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vdprintf (d, format, arg);
+  done = __vdprintf_internal (d, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/fprintf.c b/stdio-common/fprintf.c
index 2bbf14bf5d..c8f8ac4faf 100644
--- a/stdio-common/fprintf.c
+++ b/stdio-common/fprintf.c
@@ -29,7 +29,7 @@ __fprintf (FILE *stream, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vfprintf (stream, format, arg);
+  done = __vfprintf_internal (stream, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c
index c4a1146b20..d74364c7f5 100644
--- a/stdio-common/fxprintf.c
+++ b/stdio-common/fxprintf.c
@@ -27,7 +27,7 @@ static int
 locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
 {
   if (_IO_fwide (fp, 0) <= 0)
-    return _IO_vfprintf (fp, fmt, ap);
+    return __vfprintf_internal (fp, fmt, ap, 0);
 
   /* We must convert the narrow format string to a wide one.
      Each byte can produce at most one wide character.  */
@@ -53,7 +53,7 @@ locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
   res = __mbsrtowcs (wfmt, &fmt, len, &mbstate);
 
   if (res != -1)
-    res = _IO_vfwprintf (fp, wfmt, ap);
+    res = __vfwprintf_internal (fp, wfmt, ap, 0);
 
   if (used_malloc)
     free (wfmt);
diff --git a/stdio-common/printf.c b/stdio-common/printf.c
index 205b5e42df..ea41dd557c 100644
--- a/stdio-common/printf.c
+++ b/stdio-common/printf.c
@@ -30,7 +30,7 @@ __printf (const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vfprintf (stdout, format, arg);
+  done = __vfprintf_internal (stdout, format, arg, 0);
   va_end (arg);
 
   return done;
@@ -38,5 +38,4 @@ __printf (const char *format, ...)
 
 #undef _IO_printf
 ldbl_strong_alias (__printf, printf);
-/* This is for libg++.  */
 ldbl_strong_alias (__printf, _IO_printf);
diff --git a/stdio-common/snprintf.c b/stdio-common/snprintf.c
index 29a169b08b..b75e160ea3 100644
--- a/stdio-common/snprintf.c
+++ b/stdio-common/snprintf.c
@@ -16,9 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
 #include <libioP.h>
-#define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
@@ -30,7 +28,7 @@ __snprintf (char *s, size_t maxlen, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vsnprintf (s, maxlen, format, arg);
+  done = __vsnprintf_internal (s, maxlen, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
index bf5671dde9..77423b292f 100644
--- a/stdio-common/sprintf.c
+++ b/stdio-common/sprintf.c
@@ -16,9 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
 #include <libioP.h>
-#define vsprintf(s, f, a) _IO_vsprintf (s, f, a)
 
 /* Write formatted output into S, according to the format string FORMAT.  */
 /* VARARGS2 */
@@ -29,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vsprintf (s, format, arg);
+  done = __vsprintf_internal (s, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf-internal.c
similarity index 98%
rename from stdio-common/vfprintf.c
rename to stdio-common/vfprintf-internal.c
index ae412e4b84..d8716f4f07 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf-internal.c
@@ -41,6 +41,10 @@
 
 #include <libioP.h>
 
+#ifdef COMPILE_WPRINTF
+#include <wctype.h>
+#endif
+
 /* In some cases we need extra space for all the output which is not
    counted in the width of the string. We assume 32 characters is
    enough.  */
@@ -63,6 +67,8 @@
 	}								      \
     } while (0)
 #define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
+#define LDBL_IS_DBL (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
+#define DO_FORTIFY  ((mode_flags & PRINTF_FORTIFY) != 0)
 
 #define done_add(val) \
   do {									      \
@@ -78,7 +84,7 @@
   } while (0)
 
 #ifndef COMPILE_WPRINTF
-# define vfprintf	_IO_vfprintf_internal
+# define vfprintf	__vfprintf_internal
 # define CHAR_T		char
 # define UCHAR_T	unsigned char
 # define INT_T		int
@@ -105,7 +111,7 @@ typedef const char *THOUSANDS_SEP_T;
 # define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
 			  return -1
 #else
-# define vfprintf	_IO_vfwprintf
+# define vfprintf	__vfwprintf_internal
 # define CHAR_T		wchar_t
 /* This is a hack!!!  There should be a type uwchar_t.  */
 # define UCHAR_T	unsigned int /* uwchar_t */
@@ -747,7 +753,7 @@ static const uint8_t jump_table[] =
 									      \
 	if (fspec == NULL)						      \
 	  {								      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      is_long_double = 0;					      \
 									      \
 	    struct printf_info info = { .prec = prec,			      \
@@ -778,7 +784,7 @@ static const uint8_t jump_table[] =
 	else								      \
 	  {								      \
 	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      {								      \
 		fspec->data_arg_type = PA_DOUBLE;			      \
 		fspec->info.is_long_double = 0;				      \
@@ -808,7 +814,7 @@ static const uint8_t jump_table[] =
 									      \
 	if (fspec == NULL)						      \
 	  {								      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      is_long_double = 0;					      \
 									      \
 	    struct printf_info info = { .prec = prec,			      \
@@ -838,7 +844,7 @@ static const uint8_t jump_table[] =
 	else								      \
 	  {								      \
 	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)                                            \
 	      fspec->info.is_long_double = 0;				      \
 	    /* Not supported by *printf functions.  */			      \
 	    fspec->info.is_binary128 = 0;				      \
@@ -891,7 +897,7 @@ static const uint8_t jump_table[] =
       /* NOTREACHED */							      \
 									      \
     LABEL (form_number):						      \
-      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
+      if (DO_FORTIFY)							      \
 	{								      \
 	  if (! readonly_format)					      \
 	    {								      \
@@ -1214,7 +1220,8 @@ static const uint8_t jump_table[] =
 #endif
 
 /* Helper function to provide temporary buffering for unbuffered streams.  */
-static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
+static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list,
+                              unsigned int)
      __THROW __attribute__ ((noinline));
 
 /* Handle positional format specifiers.  */
@@ -1223,7 +1230,9 @@ static int printf_positional (FILE *s,
 			      va_list ap, va_list *ap_savep, int done,
 			      int nspecs_done, const UCHAR_T *lead_str_end,
 			      CHAR_T *work_buffer, int save_errno,
-			      const char *grouping, THOUSANDS_SEP_T);
+			      const char *grouping,
+                              THOUSANDS_SEP_T thousands_sep,
+                              unsigned int mode_flags);
 
 /* Handle unknown format specifier.  */
 static int printf_unknown (FILE *, const struct printf_info *,
@@ -1235,7 +1244,7 @@ static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
 
 /* The function itself.  */
 int
-vfprintf (FILE *s, const CHAR_T *format, va_list ap)
+vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
 {
   /* The character used as thousands separator.  */
   THOUSANDS_SEP_T thousands_sep = 0;
@@ -1273,6 +1282,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
      0 if unknown.  */
   int readonly_format = 0;
 
+  /* Temporarily honor environmental settings.  */
+  if (__ldbl_is_dbl)
+    mode_flags |= PRINTF_LDBL_IS_DBL;
+  if (s->_flags2 & _IO_FLAGS2_FORTIFY)
+    mode_flags |= PRINTF_FORTIFY;
+
   /* Orient the stream.  */
 #ifdef ORIENT
   ORIENT;
@@ -1293,7 +1308,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
   if (UNBUFFERED_P (s))
     /* Use a helper function which will allocate a local temporary buffer
        for the stream and then call us again.  */
-    return buffered_vfprintf (s, format, ap);
+    return buffered_vfprintf (s, format, ap, mode_flags);
 
   /* Initialize local variables.  */
   done = 0;
@@ -1682,7 +1697,7 @@ do_positional:
     }
   done = printf_positional (s, format, readonly_format, ap, &ap_save,
 			    done, nspecs_done, lead_str_end, work_buffer,
-			    save_errno, grouping, thousands_sep);
+			    save_errno, grouping, thousands_sep, mode_flags);
 
  all_done:
   if (__glibc_unlikely (workstart != NULL))
@@ -1699,7 +1714,8 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
 		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
 		   const UCHAR_T *lead_str_end,
 		   CHAR_T *work_buffer, int save_errno,
-		   const char *grouping, THOUSANDS_SEP_T thousands_sep)
+		   const char *grouping, THOUSANDS_SEP_T thousands_sep,
+                   unsigned int mode_flags)
 {
   /* For positional argument handling.  */
   struct scratch_buffer specsbuf;
@@ -1789,7 +1805,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
        now.  */
     args_size = &args_value[nargs].pa_int;
     args_type = &args_size[nargs];
-    memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
+    memset (args_type, DO_FORTIFY ? '\xff' : '\0',
 	    nargs * sizeof (*args_type));
   }
 
@@ -1856,7 +1872,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
       case PA_FLOAT:				/* Promoted.  */
 	T (PA_DOUBLE, pa_double, double);
       case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
-	if (__ldbl_is_dbl)
+	if (LDBL_IS_DBL)
 	  {
 	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
 	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
@@ -1884,7 +1900,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
       case -1:
 	/* Error case.  Not all parameters appear in N$ format
 	   strings.  We have no way to determine their type.  */
-	assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
+	assert (DO_FORTIFY);
 	__libc_fatal ("*** invalid %N$ use detected ***\n");
       }
 
@@ -2285,7 +2301,8 @@ static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
 #endif
 
 static int
-buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
+buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
+                   unsigned int mode_flags)
 {
   CHAR_T buf[BUFSIZ];
   struct helper_file helper;
@@ -2318,11 +2335,7 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
   _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
 
   /* Now print to helper instead.  */
-#ifndef COMPILE_WPRINTF
-  result = _IO_vfprintf (hp, format, args);
-#else
-  result = vfprintf (hp, format, args);
-#endif
+  result = vfprintf (hp, format, args, mode_flags);
 
   /* Lock stream.  */
   __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
@@ -2351,14 +2364,3 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
 
   return result;
 }
-
-#undef vfprintf
-#ifdef COMPILE_WPRINTF
-strong_alias (_IO_vfwprintf, __vfwprintf);
-ldbl_weak_alias (_IO_vfwprintf, vfwprintf);
-#else
-ldbl_strong_alias (_IO_vfprintf_internal, vfprintf);
-ldbl_hidden_def (_IO_vfprintf_internal, vfprintf)
-ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf);
-ldbl_hidden_def (_IO_vfprintf_internal, _IO_vfprintf)
-#endif
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
new file mode 100644
index 0000000000..13a10db99b
--- /dev/null
+++ b/stdio-common/vfprintf.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1991-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 <libio/libioP.h>
+
+extern int
+__vfprintf (FILE *fp, const char *format, va_list ap)
+{
+  return __vfprintf_internal (fp, format, ap, 0);
+}
+ldbl_strong_alias (__vfprintf, _IO_vfprintf);
+ldbl_strong_alias (__vfprintf, vfprintf);
+ldbl_hidden_def (__vfprintf, vfprintf)
diff --git a/stdio-common/vfwprintf.c b/stdio-common/vfwprintf-internal.c
similarity index 33%
rename from stdio-common/vfwprintf.c
rename to stdio-common/vfwprintf-internal.c
index 2c3cd06fad..cefaf2fafe 100644
--- /dev/null
+++ b/stdio-common/vfwprintf-internal.c
@@ -1,3 +1,2 @@
-#include <wctype.h>
 #define COMPILE_WPRINTF	1
-#include "vfprintf.c"
+#include "vfprintf-internal.c"
diff --git a/stdio-common/vfwprintf.c b/stdio-common/vfwprintf.c
new file mode 100644
index 0000000000..5d65eb7697
--- /dev/null
+++ b/stdio-common/vfwprintf.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 1991-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 <libio/libioP.h>
+
+extern int
+__vfwprintf (FILE *fp, const wchar_t *format, va_list ap)
+{
+  return __vfwprintf_internal (fp, format, ap, 0);
+}
+ldbl_weak_alias (__vfwprintf, vfwprintf);
diff --git a/stdio-common/vprintf.c b/stdio-common/vprintf.c
index d459642dc8..0da8ba761e 100644
--- a/stdio-common/vprintf.c
+++ b/stdio-common/vprintf.c
@@ -25,9 +25,9 @@
 /* Write formatted output to stdout according to the
    format string FORMAT, using the argument list in ARG.  */
 int
-__vprintf (const char *format, __gnuc_va_list arg)
+__vprintf (const char *format, va_list ap)
 {
-  return vfprintf (stdout, format, arg);
+  return __vfprintf_internal (stdout, format, ap, 0);
 }
 
 ldbl_strong_alias (__vprintf, vprintf)
diff --git a/stdlib/strfrom-skeleton.c b/stdlib/strfrom-skeleton.c
index 2840512cae..c178780f08 100644
--- a/stdlib/strfrom-skeleton.c
+++ b/stdlib/strfrom-skeleton.c
@@ -106,7 +106,7 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
     }
 
   /* The following code to prepare the virtual file has been adapted from the
-     function _IO_vsnprintf from libio.  */
+     function __vsnprintf from libio.  */
 
   if (size == 0)
     {
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 15f212ffce..7e8af80d63 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -165,7 +165,7 @@ __nldbl_vfprintf (FILE *s, const char *fmt, va_list ap)
 {
   int done;
   set_no_long_double ();
-  done = _IO_vfprintf (s, fmt, ap);
+  done = __vfprintf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return done;
 }
@@ -174,15 +174,16 @@ strong_alias (__nldbl_vfprintf, __nldbl__IO_vfprintf)
 
 int
 attribute_compat_text_section
-__nldbl__IO_vsprintf (char *string, const char *fmt, va_list ap)
+__nldbl___vsprintf (char *string, const char *fmt, va_list ap)
 {
   int done;
   __no_long_double = 1;
-  done = _IO_vsprintf (string, fmt, ap);
+  done = __vsprintf_internal (string, fmt, ap, 0);
   __no_long_double = 0;
   return done;
 }
-weak_alias (__nldbl__IO_vsprintf, __nldbl_vsprintf)
+strong_alias (__nldbl___vsprintf, __nldbl__IO_vsprintf)
+weak_alias (__nldbl___vsprintf, __nldbl_vsprintf)
 libc_hidden_def (__nldbl_vsprintf)
 
 int
@@ -192,7 +193,7 @@ __nldbl_obstack_vprintf (struct obstack *obstack, const char *fmt,
 {
   int done;
   __no_long_double = 1;
-  done = _IO_obstack_vprintf (obstack, fmt, ap);
+  done = __obstack_vprintf_internal (obstack, fmt, ap, 0);
   __no_long_double = 0;
   return done;
 }
@@ -244,7 +245,7 @@ __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
 {
   int res;
   __no_long_double = 1;
-  res = _IO_vasprintf (result_ptr, fmt, ap);
+  res = __vasprintf_internal (result_ptr, fmt, ap, 0);
   __no_long_double = 0;
   return res;
 }
@@ -256,7 +257,7 @@ __nldbl_vdprintf (int d, const char *fmt, va_list arg)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vdprintf (d, fmt, arg);
+  res = __vdprintf_internal (d, fmt, arg, 0);
   clear_no_long_double ();
   return res;
 }
@@ -268,7 +269,7 @@ __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfwprintf (s, fmt, ap);
+  res = __vfwprintf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return res;
 }
@@ -288,7 +289,7 @@ __nldbl_vsnprintf (char *string, size_t maxlen, const char *fmt,
 {
   int res;
   __no_long_double = 1;
-  res = _IO_vsnprintf (string, maxlen, fmt, ap);
+  res = __vsnprintf_internal (string, maxlen, fmt, ap, 0);
   __no_long_double = 0;
   return res;
 }
@@ -302,7 +303,7 @@ __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
 {
   int res;
   __no_long_double = 1;
-  res = _IO_vswprintf (string, maxlen, fmt, ap);
+  res = __vswprintf_internal (string, maxlen, fmt, ap, 0);
   __no_long_double = 0;
   return res;
 }
-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 0/9] Use more flags parameters instead of global bits in stdio
@ 2018-03-07 19:32 Zack Weinberg
  2018-03-07 19:32 ` [PATCH 8/9] Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl Zack Weinberg
                   ` (11 more replies)
  0 siblings, 12 replies; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:32 UTC (permalink / raw)
  To: libc-alpha

I got stuck on the patch to use C99-compliant scanf in _GNU_SOURCE
mode because the interaction with ldbl-is-dbl was too confusing.  The
reason it's too confusing is that C99 compliance in scanf, ldbl-is-dbl
mode in scanf, printf, and strfmon, and fortify mode in printf are
handled with mode bits on the FILE and thread-global flags that must
be set and reset at just the right times.  Correct behavior is
invariably to set and then reset around just one call to a lower-level
function, and there's a better way to do that: flags parameters.

This patch series implements _internal variants of scanf, printf,
strfmon, and syslog that take flag parameters that control C99
compliance, ldbl-is-dbl mode, and fortification.  I regret the length
and the messiness, and it might make sense to squash it on landing.
I have manually hacked the patches that introduce vfprintf-internal.c
and vfscanf-internal.c so the diffs are actually readable -- git doesn't
handle "rename this file and then create a new file in its place" very
well.

(N.B. It does not make sense to do the same thing to _IO_FLAGS2_NOTCANCEL,
even though we do occasionally want to turn that mode on temporarily.
It is also used for extended fopen mode "c", and the places where we
turn it on temporarily often want to do a whole string of printfs.
What would make sense is _IO_acquire_lock_disable_cancellation, but
this patch series is already quite long enough, and if we were going
to do that we should probably also make it easier to write to a stream
whose narrow/wide orientation is unknown.)

zw

-- 
Zack Weinberg (9):
  Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.
  Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD.
  Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  Add __v*printf_internal with flags arguments.
  Add __vsyslog_internal, with same flags as __v*printf_internal.
  Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY.
  Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  Post-cleanup: don't include math.h/math_private.h in math_ldbl_opt.h.

 argp/argp-fmtstream.c                              |    1 -
 argp/argp-help.c                                   |    4 +-
 argp/argp-namefrob.h                               |    2 +
 debug/Makefile                                     |    2 +-
 debug/asprintf_chk.c                               |   20 +-
 debug/dprintf_chk.c                                |   20 +-
 debug/fprintf_chk.c                                |   20 +-
 debug/fwprintf_chk.c                               |   20 +-
 debug/obprintf_chk.c                               |   96 +-
 debug/printf_chk.c                                 |   20 +-
 debug/snprintf_chk.c                               |   24 +-
 debug/sprintf_chk.c                                |   25 +-
 debug/swprintf_chk.c                               |   27 +-
 debug/vasprintf_chk.c                              |   68 +-
 debug/vdprintf_chk.c                               |   37 +-
 debug/vfprintf_chk.c                               |   21 +-
 debug/vfwprintf_chk.c                              |   21 +-
 debug/vobprintf_chk.c                              |   32 +
 debug/vprintf_chk.c                                |   20 +-
 debug/vsnprintf_chk.c                              |   46 +-
 debug/vsprintf_chk.c                               |   69 +-
 debug/vswprintf_chk.c                              |   51 +-
 debug/vwprintf_chk.c                               |   21 +-
 debug/wprintf_chk.c                                |   21 +-
 hurd/vpprintf.c                                    |    2 +-
 include/monetary.h                                 |   10 +-
 include/stdio.h                                    |    9 +-
 include/sys/syslog.h                               |   15 +-
 include/wchar.h                                    |    2 -
 libio/fwprintf.c                                   |    2 +-
 libio/iolibio.h                                    |    7 -
 libio/iovdprintf.c                                 |   13 +-
 libio/iovsprintf.c                                 |   66 +-
 libio/iovsscanf.c                                  |   12 +-
 libio/iovswscanf.c                                 |   14 +-
 libio/libio.h                                      |    6 -
 libio/libioP.h                                     |   65 +-
 libio/obprintf.c                                   |   19 +-
 libio/strfile.h                                    |   33 +-
 libio/swprintf.c                                   |    2 +-
 libio/swscanf.c                                    |   10 +-
 libio/vasprintf.c                                  |   20 +-
 libio/vscanf.c                                     |    2 +-
 libio/vsnprintf.c                                  |   17 +-
 libio/vswprintf.c                                  |   16 +-
 libio/vwprintf.c                                   |    2 +-
 libio/vwscanf.c                                    |    2 +-
 libio/wprintf.c                                    |    2 +-
 libio/wscanf.c                                     |    2 +-
 manual/locale.texi                                 |    9 +-
 misc/syslog.c                                      |   35 +-
 stdio-common/Makefile                              |    4 +-
 stdio-common/Versions                              |    3 +
 stdio-common/asprintf.c                            |    7 +-
 stdio-common/dprintf.c                             |    5 +-
 stdio-common/fprintf.c                             |    2 +-
 stdio-common/fxprintf.c                            |    4 +-
 stdio-common/iovfscanf.c                           |   34 +
 stdio-common/iovfwscanf.c                          |   34 +
 stdio-common/isoc99_fscanf.c                       |    6 +-
 stdio-common/isoc99_scanf.c                        |   13 +-
 stdio-common/isoc99_sscanf.c                       |    7 +-
 stdio-common/isoc99_vfscanf.c                      |    8 +-
 stdio-common/isoc99_vscanf.c                       |    8 +-
 stdio-common/isoc99_vsscanf.c                      |   16 +-
 stdio-common/printf.c                              |    3 +-
 stdio-common/scanf.c                               |    2 +-
 stdio-common/snprintf.c                            |    4 +-
 stdio-common/sprintf.c                             |    4 +-
 stdio-common/sscanf.c                              |   12 +-
 stdio-common/vfprintf-internal.c                   | 2360 +++++++++++++++
 stdio-common/vfprintf.c                            | 2351 +--------------
 stdio-common/vfscanf-internal.c                    | 3043 ++++++++++++++++++++
 stdio-common/vfscanf.c                             | 3041 +------------------
 stdio-common/vfwprintf-internal.c                  |    2 +
 stdio-common/vfwprintf.c                           |   28 +-
 stdio-common/vfwscanf-internal.c                   |    2 +
 stdio-common/vfwscanf.c                            |   27 +-
 stdio-common/vprintf.c                             |    4 +-
 stdlib/strfmon.c                                   |    3 +-
 stdlib/strfmon_l.c                                 |    8 +-
 stdlib/strfrom-skeleton.c                          |    2 +-
 sysdeps/generic/math_ldbl_opt.h                    |    5 +-
 sysdeps/generic/stdio-lock.h                       |    7 -
 sysdeps/ieee754/ldbl-128ibm/s_ceill.c              |    1 +
 sysdeps/ieee754/ldbl-128ibm/s_floorl.c             |    1 +
 sysdeps/ieee754/ldbl-128ibm/s_llrintl.c            |    1 +
 sysdeps/ieee754/ldbl-128ibm/s_llroundl.c           |    1 +
 sysdeps/ieee754/ldbl-128ibm/s_lrintl.c             |    1 +
 sysdeps/ieee754/ldbl-128ibm/s_lroundl.c            |    1 +
 sysdeps/ieee754/ldbl-128ibm/s_rintl.c              |    1 +
 sysdeps/ieee754/ldbl-128ibm/s_roundl.c             |    1 +
 sysdeps/ieee754/ldbl-128ibm/s_truncl.c             |    1 +
 sysdeps/ieee754/ldbl-opt/Makefile                  |    2 +-
 sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h           |   14 +-
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c            |  764 ++---
 sysdeps/ieee754/ldbl-opt/nldbl-compat.h            |    8 +-
 sysdeps/nptl/stdio-lock.h                          |    7 -
 sysdeps/powerpc/power7/fpu/s_logb.c                |    2 +
 sysdeps/powerpc/powerpc64/fpu/multiarch/e_expf.c   |    1 +
 sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypot.c  |    1 +
 sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypotf.c |    1 +
 wcsmbs/isoc99_fwscanf.c                            |    6 +-
 wcsmbs/isoc99_swscanf.c                            |   11 +-
 wcsmbs/isoc99_vfwscanf.c                           |    8 +-
 wcsmbs/isoc99_vswscanf.c                           |   15 +-
 wcsmbs/isoc99_vwscanf.c                            |    8 +-
 wcsmbs/isoc99_wscanf.c                             |    6 +-
 108 files changed, 6445 insertions(+), 6559 deletions(-)
 create mode 100644 debug/vobprintf_chk.c
 create mode 100644 stdio-common/iovfscanf.c
 create mode 100644 stdio-common/iovfwscanf.c
 create mode 100644 stdio-common/vfprintf-internal.c
 create mode 100644 stdio-common/vfscanf-internal.c
 create mode 100644 stdio-common/vfwprintf-internal.c
 create mode 100644 stdio-common/vfwscanf-internal.c

-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 3/9] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD.
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
  2018-03-07 19:32 ` [PATCH 8/9] Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl Zack Weinberg
@ 2018-03-07 19:32 ` Zack Weinberg
  2018-03-26 15:35   ` Gabriel F. T. Gomes
  2018-03-07 19:32 ` [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments Zack Weinberg
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:32 UTC (permalink / raw)
  To: libc-alpha

Change the callers of __vfscanf_internal and __vfwscanf_internal that
want C99-compliant behavior to communicate this via the new flags
argument, rather than setting bits on the FILE object.  This also
means these functions do not need to do their own locking.

	* stdio-common/isoc99_scanf.c
	* stdio-common/isoc99_fscanf.c
	* stdio-common/isoc99_sscanf.c
	* stdio-common/isoc99_vscanf.c
	* stdio-common/isoc99_vfscanf.c
	* stdio-common/isoc99_vsscanf.c
	* wcsmbs/isoc99_wscanf.c
	* wcsmbs/isoc99_fwscanf.c
	* wcsmbs/isoc99_swscanf.c
	* wcsmbs/isoc99_vwscanf.c
	* wcsmbs/isoc99_vfwscanf.c
	* wcsmbs/isoc99_vswscanf.c:
	Pass SCANF_ISOC99_A to __vfscanf_internal and/or __vfwscanf_internal.
	Do not set _IO_FLAGS2_SCANF_STD on the FILE passed to that function.
	No need to lock and unlock the FILE passed to that function.

	* stdio-common/vfscanf-internal.c
	(__vfscanf_internal, __vfwscanf_internal):
	Don't look at _IO_FLAGS2_SCANF_STD.
	* libio/libioP.h (_IO_acquire_lock_clear_flags2_fct)
	(_IO_release_lock): Don't clear _IO_FLAGS2_SCANF_STD.
	* libio/libio.h (_IO_FLAGS2_SCANF_STD): Delete.
---
 libio/libio.h                   |  1 -
 libio/libioP.h                  |  5 ++---
 stdio-common/isoc99_fscanf.c    |  6 +-----
 stdio-common/isoc99_scanf.c     | 13 ++-----------
 stdio-common/isoc99_sscanf.c    |  3 +--
 stdio-common/isoc99_vfscanf.c   |  8 +-------
 stdio-common/isoc99_vscanf.c    |  8 +-------
 stdio-common/isoc99_vsscanf.c   |  3 +--
 stdio-common/vfscanf-internal.c |  2 --
 wcsmbs/isoc99_fwscanf.c         |  6 +-----
 wcsmbs/isoc99_swscanf.c         |  3 +--
 wcsmbs/isoc99_vfwscanf.c        |  8 +-------
 wcsmbs/isoc99_vswscanf.c        |  3 +--
 wcsmbs/isoc99_vwscanf.c         |  8 +-------
 wcsmbs/isoc99_wscanf.c          |  6 +-----
 15 files changed, 15 insertions(+), 68 deletions(-)

diff --git a/libio/libio.h b/libio/libio.h
index d4eba2df54..30cb7d784f 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -92,7 +92,6 @@ typedef union
 #define _IO_FLAGS2_NOTCANCEL 2
 #define _IO_FLAGS2_FORTIFY 4
 #define _IO_FLAGS2_USER_WBUF 8
-#define _IO_FLAGS2_SCANF_STD 16
 #define _IO_FLAGS2_NOCLOSE 32
 #define _IO_FLAGS2_CLOEXEC 64
 #define _IO_FLAGS2_NEED_LOCK 128
diff --git a/libio/libioP.h b/libio/libioP.h
index a471c90be8..0772fb1431 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -773,7 +773,7 @@ __attribute__ ((__always_inline__))
 _IO_acquire_lock_clear_flags2_fct (FILE **p)
 {
   FILE *fp = *p;
-  fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY | _IO_FLAGS2_SCANF_STD);
+  fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY);
   if ((fp->_flags & _IO_USER_LOCK) == 0)
     _IO_funlockfile (fp);
 }
@@ -787,8 +787,7 @@ _IO_acquire_lock_clear_flags2_fct (FILE **p)
     FILE *_IO_acquire_lock_file = (_fp)
 # define _IO_release_lock(_fp)						      \
     if (_IO_acquire_lock_file != NULL)					      \
-      _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY		      \
-                                          | _IO_FLAGS2_SCANF_STD);	      \
+      _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY);		      \
   } while (0)
 #endif
 
diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
index 4210d11f2b..e788ac47bb 100644
--- a/stdio-common/isoc99_fscanf.c
+++ b/stdio-common/isoc99_fscanf.c
@@ -27,13 +27,9 @@ __isoc99_fscanf (FILE *stream, const char *format, ...)
   va_list arg;
   int done;
 
-  _IO_acquire_lock_clear_flags2 (stream);
-  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
   va_start (arg, format);
-  done = __vfscanf_internal (stream, format, arg, 0);
+  done = __vfscanf_internal (stream, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
-  _IO_release_lock (stream);
   return done;
 }
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
index 64c873eed9..98b0a19e89 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/isoc99_scanf.c
@@ -19,26 +19,17 @@
 #include <stdio.h>
 #include <libioP.h>
 
-
 /* Read formatted input from stdin according to the format string FORMAT.  */
-/* VARARGS1 */
+
 int
 __isoc99_scanf (const char *format, ...)
 {
   va_list arg;
   int done;
 
-#ifdef _IO_MTSAFE_IO
-  _IO_acquire_lock_clear_flags2 (stdin);
-#endif
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
   va_start (arg, format);
-  done = __vfscanf_internal (stdin, format, arg, 0);
+  done = __vfscanf_internal (stdin, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
-#ifdef _IO_MTSAFE_IO
-  _IO_release_lock (stdin);
-#endif
   return done;
 }
diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
index 95b94a68b5..c53130e4ff 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -27,10 +27,9 @@ __isoc99_sscanf (const char *s, const char *format, ...)
   int done;
   _IO_strfile sf;
   FILE *f = _IO_strfile_read (&sf, s);
-  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __vfscanf_internal (f, format, arg, 0);
+  done = __vfscanf_internal (f, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
index c96ca831ae..0bc2ad911e 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -23,12 +23,6 @@
 int
 __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
 {
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stream);
-  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = __vfscanf_internal (stream, format, args, 0);
-  _IO_release_lock (stream);
-  return done;
+  return __vfscanf_internal (stream, format, args, SCANF_ISOC99_A);
 }
 libc_hidden_def (__isoc99_vfscanf)
diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
index 72ae72ddee..1a270b0e0c 100644
--- a/stdio-common/isoc99_vscanf.c
+++ b/stdio-common/isoc99_vscanf.c
@@ -23,11 +23,5 @@
 int
 __isoc99_vscanf (const char *format, va_list args)
 {
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stdin);
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = __vfscanf_internal (stdin, format, args, 0);
-  _IO_release_lock (stdin);
-  return done;
+  return __vfscanf_internal (stdin, format, args, SCANF_ISOC99_A);
 }
diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
index 02bc0f50e6..dfc394bb51 100644
--- a/stdio-common/isoc99_vsscanf.c
+++ b/stdio-common/isoc99_vsscanf.c
@@ -31,7 +31,6 @@ __isoc99_vsscanf (const char *string, const char *format, va_list args)
 {
   _IO_strfile sf;
   FILE *f = _IO_strfile_read (&sf, string);
-  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  return __vfscanf_internal (f, format, args, 0);
+  return __vfscanf_internal (f, format, args, SCANF_ISOC99_A);
 }
 libc_hidden_def (__isoc99_vsscanf)
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 93b07ad4bc..9f99d237d2 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -336,8 +336,6 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
   /* Temporarily honor the environmental mode bits.  */
   if (__ldbl_is_dbl)
     mode_flags |= SCANF_LDBL_IS_DBL;
-  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
-    mode_flags |= SCANF_ISOC99_A;
 
 #ifdef __va_copy
   __va_copy (arg, argptr);
diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
index 00b07dd48e..b01826e5ac 100644
--- a/wcsmbs/isoc99_fwscanf.c
+++ b/wcsmbs/isoc99_fwscanf.c
@@ -28,13 +28,9 @@ __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
   va_list arg;
   int done;
 
-  _IO_acquire_lock_clear_flags2 (stream);
-  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
   va_start (arg, format);
-  done = __vfwscanf_internal (stream, format, arg, 0);
+  done = __vfwscanf_internal (stream, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
-  _IO_release_lock (stream);
   return done;
 }
diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
index 40401d0aa1..f90e56d97f 100644
--- a/wcsmbs/isoc99_swscanf.c
+++ b/wcsmbs/isoc99_swscanf.c
@@ -28,10 +28,9 @@ __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
   _IO_strfile sf;
   struct _IO_wide_data wd;
   FILE *f = _IO_strfile_readw (&sf, &wd, s);
-  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __vfwscanf_internal (f, format, arg, 0);
+  done = __vfwscanf_internal (f, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
   return done;
diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
index f70c6b596d..f9d0a384f5 100644
--- a/wcsmbs/isoc99_vfwscanf.c
+++ b/wcsmbs/isoc99_vfwscanf.c
@@ -24,12 +24,6 @@
 int
 __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
 {
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stream);
-  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = __vfwscanf_internal (stream, format, args, 0);
-  _IO_release_lock (stream);
-  return done;
+  return __vfwscanf_internal (stream, format, args, SCANF_ISOC99_A);
 }
 libc_hidden_def (__isoc99_vfwscanf)
diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
index b91eb651a3..0d8ef7611a 100644
--- a/wcsmbs/isoc99_vswscanf.c
+++ b/wcsmbs/isoc99_vswscanf.c
@@ -33,7 +33,6 @@ __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
   _IO_strfile sf;
   struct _IO_wide_data wd;
   FILE *f = _IO_strfile_readw (&sf, &wd, string);
-  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  return __vfwscanf_internal (f, format, args, 0);
+  return __vfwscanf_internal (f, format, args, SCANF_ISOC99_A);
 }
 libc_hidden_def (__isoc99_vswscanf)
diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
index eb22c8acae..5e4f44d794 100644
--- a/wcsmbs/isoc99_vwscanf.c
+++ b/wcsmbs/isoc99_vwscanf.c
@@ -24,11 +24,5 @@
 int
 __isoc99_vwscanf (const wchar_t *format, va_list args)
 {
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stdin);
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = __vfwscanf_internal (stdin, format, args, 0);
-  _IO_release_lock (stdin);
-  return done;
+  return __vfwscanf_internal (stdin, format, args, SCANF_ISOC99_A);
 }
diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
index 59f80d78fb..a0f24e1f49 100644
--- a/wcsmbs/isoc99_wscanf.c
+++ b/wcsmbs/isoc99_wscanf.c
@@ -29,13 +29,9 @@ __isoc99_wscanf (const wchar_t *format, ...)
   va_list arg;
   int done;
 
-  _IO_acquire_lock_clear_flags2 (stdin);
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
   va_start (arg, format);
-  done = __vfwscanf_internal (stdin, format, arg, 0);
+  done = __vfwscanf_internal (stdin, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
-  _IO_release_lock (stdin);
   return done;
 }
-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 7/9] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY.
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (7 preceding siblings ...)
  2018-03-07 19:51 ` [PATCH 9/9] Post-cleanup: don't include math.h/math_private.h in math_ldbl_opt.h Zack Weinberg
@ 2018-03-07 19:51 ` Zack Weinberg
  2018-03-12 15:29 ` [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:51 UTC (permalink / raw)
  To: libc-alpha

The _chk variants of all of the printf functions become much simpler.
This is the last thing that we needed _IO_acquire_lock_clear_flags2
for, so it can go as well.  I took the opportunity to make the headers
included and the names of all local variables consistent across all the
affected files.

Since we ultimately want to get rid of __no_long_double as well, it
must be possible to get all of the nontrivial effects of the _chk
functions by calling the _internal functions with appropriate flags.
For most of the __(v)xprintf_chk functions, this is covered by
PRINTF_FORTIFY plus some up-front argument checks that can be
duplicated.  However, __(v)sprintf_chk installs a custom jump table so
that it can crash instead of overflowing the output buffer.  This
functionality is moved to __vsprintf_internal, which now has a
'maxlen' argument like __vsnprintf_internal; to get the unsafe
behavior of ordinary (v)sprintf, pass -1 for that argument.

obstack_printf_chk and obstack_vprintf_chk are no longer in the same
file.

	* libio/iovsprintf.c (_IO_str_chk_overflow, _IO_str_chk_jumps):
	Moved here from debug/vsprintf_chk.c.
	(__vsprintf_internal): Add 'maxlen' argument.  Change the setup
	and completion logic for the strfile to match exactly what
	__vsprintf_chk used to do, except, when maxlen is -1, pass -1 to
	_IO_str_init_static_internal instead of maxlen-1.
	(__vsprintf): Pass -1 as maxlen to __vsprintf_internal.
	* stdio-common/sprintf.c (__sprintf): Pass -1 as maxlen to
	__vsprintf_internal.
	* libio/libioP.h: Update prototype of __vsprintf_internal and add
	a comment explaining why it has the maxlen argument.

	* debug/vsprintf_chk.c (__vsprintf_chk)
	* debug/sprintf_chk.c (__sprintf_chk):
	Directly call __vsprintf_internal, passing PRINTF_FORTIFY if
	'flags' argument is positive, and slen as maxlen.  No need to lock
	the FILE and/or construct a temporary FILE.  Minimize and normalize
	header inclusions and variable names.  Do not libc_hidden_def anything.

	* debug/asprintf_chk.c (__asprintf_chk)
	* debug/dprintf_chk.c (__dprintf_chk)
	* debug/fprintf_chk.c (__fprintf_chk)
	* debug/fwprintf_chk.c (__fwprintf_chk)
	* debug/obprintf_chk.c (__obstack_printf_chk, __obstack_vprintf_chk)
	* debug/printf_chk.c (__printf_chk)
	* debug/snprintf_chk.c (__snprintf_chk)
	* debug/swprintf_chk.c (__swprintf_chk)
	* debug/vasprintf_chk.c (__vasprintf_chk)
	* debug/vdprintf_chk.c (__vdprintf_chk)
	* debug/vfprintf_chk.c (__vfprintf_chk)
	* debug/vfwprintf_chk.c (__vfwprintf_chk)
	* debug/vprintf_chk.c (__vprintf_chk)
	* debug/vsnprintf_chk.c (__vsnprintf_chk)
	* debug/vswprintf_chk.c (__vswprintf_chk)
	* debug/vwprintf_chk.c (__vwprintf_chk)
	* debug/wprintf_chk.c (__wprintf_chk):
	Directly call the corresponding vxxprintf_internal function, passing
	PRINTF_FORTIFY if 'flag' argument is positive.	No need to lock
	the FILE and/or construct a temporary FILE.  Minimize and normalize
	header inclusions and variable names.  Do not libc_hidden_def anything.

	* debug/obprintf_chk.c (__obstack_vprintf_chk): Move to new file...
	* debug/vobprintf_chk.c: ... here.
	* debug/Makefile (routines): Add vobprintf_chk.

	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
	(__nldbl___vsprintf): Pass -1 as maxlen to __vsprintf_internal.
	(__nldbl___vfprintf_chk, __nldbl___vsnprintf_chk)
	(__nldbl___vsprintf_chk, __nldbl___vswprintf_chk)
	(__nldbl___vasprintf_chk, __nldbl___vdprintf_chk)
	(__nldbl___obstack_vfprintf_chk):
	Directly call the corresponding vxxprintf_internal function,
	passing PRINTF_FORTIFY if 'flag' argument is positive.  If necessary,
	duplicate comparison of slen with 0 or maxlen from the corresponding
	non-__nldbl function.

	* include/stdio.h (__vsnprintf_chk, __vfprintf_chk, __vasprintf_chk)
	(__vdprintf_chk, __obstack_vfprintf_chk): Remove libc_hidden_proto.
	* include/wchar.h (__vfwprintf_chk, __vswprintf_chk):
	Remove libc_hidden_proto.

	* stdio-common/vfprintf-internal.c
	(__vfprintf_internal, __vfwprintf_internal):
	Do not check _IO_FLAGS2_FORTIFY.
	* libio/libio.h (_IO_FLAGS2_FORTIFY): Remove.
	* libio/libioP.h (_IO_acquire_lock_clear_flags2_fct): Remove.
	(_IO_acquire_lock_clear_flags2): Remove.
	(_IO_release_lock): Remove conditional statement which will
	now never execute.
	(_IO_acquire_lock): Remove variable which is now unused.
	* sysdeps/generic/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove.
	* sysdeps/nptl/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove.
---
 debug/Makefile                          |  2 +-
 debug/asprintf_chk.c                    | 20 +++----
 debug/dprintf_chk.c                     | 20 +++----
 debug/fprintf_chk.c                     | 20 +++----
 debug/fwprintf_chk.c                    | 20 +++----
 debug/obprintf_chk.c                    | 96 ++++-----------------------------
 debug/printf_chk.c                      | 20 +++----
 debug/snprintf_chk.c                    | 24 +++++----
 debug/sprintf_chk.c                     | 25 +++++----
 debug/swprintf_chk.c                    | 27 ++++++----
 debug/vasprintf_chk.c                   | 68 ++---------------------
 debug/vdprintf_chk.c                    | 37 ++-----------
 debug/vfprintf_chk.c                    | 21 ++------
 debug/vfwprintf_chk.c                   | 21 ++------
 debug/vobprintf_chk.c                   | 32 +++++++++++
 debug/vprintf_chk.c                     | 20 ++-----
 debug/vsnprintf_chk.c                   | 46 +++-------------
 debug/vsprintf_chk.c                    | 69 +++---------------------
 debug/vswprintf_chk.c                   | 51 +++---------------
 debug/vwprintf_chk.c                    | 21 ++------
 debug/wprintf_chk.c                     | 21 +++-----
 include/stdio.h                         |  5 --
 include/wchar.h                         |  2 -
 libio/iovsprintf.c                      | 54 +++++++++++++++++--
 libio/libio.h                           |  1 -
 libio/libioP.h                          | 25 +++------
 stdio-common/sprintf.c                  |  2 +-
 stdio-common/vfprintf-internal.c        |  2 -
 sysdeps/generic/stdio-lock.h            |  7 ---
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 32 +++++++----
 sysdeps/nptl/stdio-lock.h               |  7 ---
 31 files changed, 268 insertions(+), 550 deletions(-)
 create mode 100644 debug/vobprintf_chk.c

diff --git a/debug/Makefile b/debug/Makefile
index c6f6feb0ec..f4153bb98d 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -45,7 +45,7 @@ routines  = backtrace backtracesyms backtracesymsfd noophooks \
 	    gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \
 	    wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
 	    wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
-	    vdprintf_chk obprintf_chk \
+	    vdprintf_chk obprintf_chk vobprintf_chk \
 	    longjmp_chk ____longjmp_chk \
 	    fdelt_chk poll_chk ppoll_chk \
 	    explicit_bzero_chk \
diff --git a/debug/asprintf_chk.c b/debug/asprintf_chk.c
index 9cd4143f2e..eb885c35ca 100644
--- a/debug/asprintf_chk.c
+++ b/debug/asprintf_chk.c
@@ -15,22 +15,24 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
 
 
 /* Write formatted output from FORMAT to a string which is
    allocated with malloc and stored in *STRING_PTR.  */
 int
-__asprintf_chk (char **result_ptr, int flags, const char *format, ...)
+__asprintf_chk (char **result_ptr, int flag, const char *format, ...)
 {
-  va_list arg;
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
 
-  va_start (arg, format);
-  done = __vasprintf_chk (result_ptr, flags, format, arg);
-  va_end (arg);
+  va_start (ap, format);
+  ret = __vasprintf_internal (result_ptr, format, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
diff --git a/debug/dprintf_chk.c b/debug/dprintf_chk.c
index df3867c61c..b5c62827c0 100644
--- a/debug/dprintf_chk.c
+++ b/debug/dprintf_chk.c
@@ -15,21 +15,23 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
 
 
 /* Write formatted output to D, according to the format string FORMAT.  */
 int
-__dprintf_chk (int d, int flags, const char *format, ...)
+__dprintf_chk (int d, int flag, const char *format, ...)
 {
-  va_list arg;
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
 
-  va_start (arg, format);
-  done = __vdprintf_chk (d, flags, format, arg);
-  va_end (arg);
+  va_start (ap, format);
+  ret = __vdprintf_internal (d, format, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
diff --git a/debug/fprintf_chk.c b/debug/fprintf_chk.c
index cff4438afb..14afc073b2 100644
--- a/debug/fprintf_chk.c
+++ b/debug/fprintf_chk.c
@@ -16,29 +16,23 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to FP from the format string FORMAT.  */
 int
 ___fprintf_chk (FILE *fp, int flag, const char *format, ...)
 {
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (fp);
-  if (flag > 0)
-    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
+  int ret;
 
   va_start (ap, format);
-  done = vfprintf (fp, format, ap);
+  ret = __vfprintf_internal (fp, format, ap, mode);
   va_end (ap);
 
-  if (flag > 0)
-    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (fp);
-
-  return done;
+  return ret;
 }
 ldbl_strong_alias (___fprintf_chk, __fprintf_chk)
diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
index 63167c1839..10d84ce98b 100644
--- a/debug/fwprintf_chk.c
+++ b/debug/fwprintf_chk.c
@@ -16,28 +16,22 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to FP from the format string FORMAT.  */
 int
 __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
 {
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (fp);
-  if (flag > 0)
-    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
+  int ret;
 
   va_start (ap, format);
-  done = __vfwprintf_internal (fp, format, ap, 0);
+  ret = __vfwprintf_internal (fp, format, ap, mode);
   va_end (ap);
 
-  if (flag > 0)
-    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (fp);
-
-  return done;
+  return ret;
 }
diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index 41dd481c34..c1a8f9e9a9 100644
--- a/debug/obprintf_chk.c
+++ b/debug/obprintf_chk.c
@@ -17,99 +17,23 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-
-#include <stdlib.h>
-#include <libioP.h>
-#include "../libio/strfile.h"
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-#include <obstack.h>
+#include <libio/libioP.h>
 #include <stdarg.h>
-#include <stdio_ext.h>
-
-
-struct _IO_obstack_file
-{
-  struct _IO_FILE_plus file;
-  struct obstack *obstack;
-};
-
-extern const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden;
-
-int
-__obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
-		       va_list args)
-{
-  struct obstack_FILE
-    {
-      struct _IO_obstack_file ofile;
-    } new_f;
-  int result;
-  int size;
-  int room;
-
-#ifdef _IO_MTSAFE_IO
-  new_f.ofile.file.file._lock = NULL;
-#endif
-
-  _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
-  room = obstack_room (obstack);
-  size = obstack_object_size (obstack) + room;
-  if (size == 0)
-    {
-      /* We have to handle the allocation a bit different since the
-	 `_IO_str_init_static' function would handle a size of zero
-	 different from what we expect.  */
-
-      /* Get more memory.  */
-      obstack_make_room (obstack, 64);
-
-      /* Recompute how much room we have.  */
-      room = obstack_room (obstack);
-      size = room;
-
-      assert (size != 0);
-    }
-
-  _IO_str_init_static_internal ((struct _IO_strfile_ *) &new_f.ofile,
-				obstack_base (obstack),
-				size, obstack_next_free (obstack));
-  /* Now allocate the rest of the current chunk.  */
-  assert (size == (new_f.ofile.file.file._IO_write_end
-		   - new_f.ofile.file.file._IO_write_base));
-  assert (new_f.ofile.file.file._IO_write_ptr
-	  == (new_f.ofile.file.file._IO_write_base
-	      + obstack_object_size (obstack)));
-  obstack_blank_fast (obstack, room);
-
-  new_f.ofile.obstack = obstack;
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
-     can only come from read-only format strings.  */
-  if (flags > 0)
-    new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);
-
-  /* Shrink the buffer to the space we really currently need.  */
-  obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
-				- new_f.ofile.file.file._IO_write_end));
-
-  return result;
-}
-libc_hidden_def (__obstack_vprintf_chk)
 
 
 int
-__obstack_printf_chk (struct obstack *obstack, int flags, const char *format,
+__obstack_printf_chk (struct obstack *obstack, int flag, const char *format,
 		      ...)
 {
-  int result;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
+  int ret;
+
   va_start (ap, format);
-  result = __obstack_vprintf_chk (obstack, flags, format, ap);
+  ret = __obstack_vprintf_internal (obstack, format, ap, mode);
   va_end (ap);
-  return result;
+
+  return ret;
 }
diff --git a/debug/printf_chk.c b/debug/printf_chk.c
index 426dc78386..e035b42590 100644
--- a/debug/printf_chk.c
+++ b/debug/printf_chk.c
@@ -16,29 +16,23 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 ___printf_chk (int flag, const char *format, ...)
 {
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
+  int ret;
 
   va_start (ap, format);
-  done = vfprintf (stdout, format, ap);
+  ret = __vfprintf_internal (stdout, format, ap, mode);
   va_end (ap);
 
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return ret;
 }
 ldbl_strong_alias (___printf_chk, __printf_chk)
diff --git a/debug/snprintf_chk.c b/debug/snprintf_chk.c
index cddba37109..984b5e8932 100644
--- a/debug/snprintf_chk.c
+++ b/debug/snprintf_chk.c
@@ -15,25 +15,29 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
 
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
-/* VARARGS5 */
 int
-___snprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
+___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
 		 const char *format, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
 
-  va_start (arg, format);
-  done = __vsnprintf_chk (s, maxlen, flags, slen, format, arg);
-  va_end (arg);
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
 
-  return done;
+  va_start (ap, format);
+  ret = __vsnprintf_internal (s, maxlen, format, ap, mode);
+  va_end (ap);
+
+  return ret;
 }
 ldbl_strong_alias (___snprintf_chk, __snprintf_chk)
diff --git a/debug/sprintf_chk.c b/debug/sprintf_chk.c
index 78214563dd..649e8ab4d5 100644
--- a/debug/sprintf_chk.c
+++ b/debug/sprintf_chk.c
@@ -15,22 +15,27 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
+
 
 /* Write formatted output into S, according to the format string FORMAT.  */
-/* VARARGS4 */
 int
-___sprintf_chk (char *s, int flags, size_t slen, const char *format, ...)
+___sprintf_chk (char *s, int flag, size_t slen, const char *format, ...)
 {
-  va_list arg;
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
+
+  if (slen == 0)
+    __chk_fail ();
 
-  va_start (arg, format);
-  done = __vsprintf_chk (s, flags, slen, format, arg);
-  va_end (arg);
+  va_start (ap, format);
+  ret = __vsprintf_internal (s, slen, format, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 ldbl_strong_alias (___sprintf_chk, __sprintf_chk)
diff --git a/debug/swprintf_chk.c b/debug/swprintf_chk.c
index 35887e48e2..186c17751c 100644
--- a/debug/swprintf_chk.c
+++ b/debug/swprintf_chk.c
@@ -16,20 +16,27 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <wchar.h>
+#include <libio/libioP.h>
 
-/* Write formatted output into S, according to the format string FORMAT.  */
-/* VARARGS5 */
+
+/* Write formatted output into S, according to the format string FORMAT,
+   writing no more than MAXLEN characters.  */
 int
-__swprintf_chk (wchar_t *s, size_t n, int flag, size_t s_len,
+__swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
 		const wchar_t *format, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
 
-  va_start (arg, format);
-  done = __vswprintf_chk (s, n, flag, s_len, format, arg);
-  va_end (arg);
+  va_start (ap, format);
+  ret = __vswprintf_internal (s, maxlen, format, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
index 6136694431..f5975ea02a 100644
--- a/debug/vasprintf_chk.c
+++ b/debug/vasprintf_chk.c
@@ -24,72 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <malloc.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdio_ext.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
 
 int
-__vasprintf_chk (char **result_ptr, int flags, const char *format,
-		 va_list args)
+__vasprintf_chk (char **result_ptr, int flag, const char *format, va_list ap)
 {
-  /* Initial size of the buffer to be used.  Will be doubled each time an
-     overflow occurs.  */
-  const size_t init_string_size = 100;
-  char *string;
-  _IO_strfile sf;
-  int ret;
-  size_t needed;
-  size_t allocated;
-  /* No need to clear the memory here (unlike for open_memstream) since
-     we know we will never seek on the stream.  */
-  string = (char *) malloc (init_string_size);
-  if (string == NULL)
-    return -1;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, string, init_string_size, string);
-  sf._sbf._f._flags &= ~_IO_USER_BUF;
-  sf._s._allocate_buffer = (_IO_alloc_type) malloc;
-  sf._s._free_buffer = (_IO_free_type) free;
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  ret = __vfprintf_internal (&sf._sbf._f, format, args, 0);
-  if (ret < 0)
-    {
-      free (sf._sbf._f._IO_buf_base);
-      return ret;
-    }
-  /* Only use realloc if the size we need is of the same (binary)
-     order of magnitude then the memory we allocated.  */
-  needed = sf._sbf._f._IO_write_ptr - sf._sbf._f._IO_write_base + 1;
-  allocated = sf._sbf._f._IO_write_end - sf._sbf._f._IO_write_base;
-  if ((allocated >> 1) <= needed)
-    *result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
-  else
-    {
-      *result_ptr = (char *) malloc (needed);
-      if (*result_ptr != NULL)
-	{
-	  memcpy (*result_ptr, sf._sbf._f._IO_buf_base, needed - 1);
-	  free (sf._sbf._f._IO_buf_base);
-	}
-      else
-	/* We have no choice, use the buffer we already have.  */
-	*result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
-    }
-  if (*result_ptr == NULL)
-    *result_ptr = sf._sbf._f._IO_buf_base;
-  (*result_ptr)[needed - 1] = '\0';
-  return ret;
+  return __vasprintf_internal (result_ptr, format, ap, mode);
 }
-libc_hidden_def (__vasprintf_chk)
diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
index 4386127cfe..e04514e355 100644
--- a/debug/vdprintf_chk.c
+++ b/debug/vdprintf_chk.c
@@ -24,41 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <libioP.h>
-#include <stdio_ext.h>
+#include <libio/libioP.h>
 
 int
-__vdprintf_chk (int d, int flags, const char *format, va_list arg)
+__vdprintf_chk (int d, int flag, const char *format, va_list ap)
 {
-  struct _IO_FILE_plus tmpfil;
-  struct _IO_wide_data wd;
-  int done;
-
-#ifdef _IO_MTSAFE_IO
-  tmpfil.file._lock = NULL;
-#endif
-  _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
-  _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
-  _IO_new_file_init_internal (&tmpfil);
-  if (_IO_file_attach (&tmpfil.file, d) == NULL)
-    {
-      _IO_un_link (&tmpfil);
-      return EOF;
-    }
-  tmpfil.file._flags |= _IO_DELETE_DONT_CLOSE;
-
-  _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
-		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
-
-  _IO_FINISH (&tmpfil.file);
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  return done;
+  return __vdprintf_internal (d, format, ap, mode);
 }
-libc_hidden_def (__vdprintf_chk)
diff --git a/debug/vfprintf_chk.c b/debug/vfprintf_chk.c
index 5babbf611e..44426e14fd 100644
--- a/debug/vfprintf_chk.c
+++ b/debug/vfprintf_chk.c
@@ -15,28 +15,17 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to FP from the format string FORMAT.  */
 int
 ___vfprintf_chk (FILE *fp, int flag, const char *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (fp);
-  if (flag > 0)
-    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = vfprintf (fp, format, ap);
-
-  if (flag > 0)
-    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (fp);
-
-  return done;
+  return __vfprintf_internal (fp, format, ap, mode);
 }
-ldbl_hidden_def (___vfprintf_chk, __vfprintf_chk)
 ldbl_strong_alias (___vfprintf_chk, __vfprintf_chk)
diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c
index abf2bd6517..3aed308156 100644
--- a/debug/vfwprintf_chk.c
+++ b/debug/vfwprintf_chk.c
@@ -15,27 +15,16 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to FP from the format string FORMAT.  */
 int
 __vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (fp);
-  if (flag > 0)
-    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = __vfwprintf_internal (fp, format, ap, 0);
-
-  if (flag > 0)
-    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (fp);
-
-  return done;
+  return __vfwprintf_internal (fp, format, ap, mode);
 }
-libc_hidden_def (__vfwprintf_chk)
diff --git a/debug/vobprintf_chk.c b/debug/vobprintf_chk.c
new file mode 100644
index 0000000000..edfbe8f00a
--- /dev/null
+++ b/debug/vobprintf_chk.c
@@ -0,0 +1,32 @@
+/* Print output of stream to given obstack.
+   Copyright (C) 1996-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   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 <libio/libioP.h>
+
+
+int
+__obstack_vprintf_chk (struct obstack *obstack, int flag, const char *format,
+		       va_list ap)
+{
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+
+  return __obstack_vprintf_internal (obstack, format, ap, mode);
+}
diff --git a/debug/vprintf_chk.c b/debug/vprintf_chk.c
index b3b2c53df2..69fcb721ac 100644
--- a/debug/vprintf_chk.c
+++ b/debug/vprintf_chk.c
@@ -15,27 +15,17 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 ___vprintf_chk (int flag, const char *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = vfprintf (stdout, format, ap);
-
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return __vfprintf_internal (stdout, format, ap, mode);
 }
 ldbl_strong_alias (___vprintf_chk, __vprintf_chk)
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index 95d286f416..666a83b701 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -15,56 +15,22 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
 
-extern const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden;
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
-/* VARARGS5 */
 int
-___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
-		  const char *format, va_list args)
+___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
+		  const char *format, va_list ap)
 {
-  /* XXX Maybe for less strict version do not fail immediately.
-     Though, maxlen is supposed to be the size of buffer pointed
-     to by s, so a conforming program can't pass such maxlen
-     to *snprintf.  */
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  _IO_strnfile sf;
-  int ret;
-#ifdef _IO_MTSAFE_IO
-  sf.f._sbf._f._lock = NULL;
-#endif
-
-  /* We need to handle the special case where MAXLEN is 0.  Use the
-     overflow buffer right from the start.  */
-  if (maxlen == 0)
-    {
-      s = sf.overflow_buf;
-      maxlen = sizeof (sf.overflow_buf);
-    }
-
-  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
-  s[0] = '\0';
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
-  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
-    *sf.f._sbf._f._IO_write_ptr = '\0';
-  return ret;
+  return __vsnprintf_internal (s, maxlen, format, ap, mode);
 }
-ldbl_hidden_def (___vsnprintf_chk, __vsnprintf_chk)
 ldbl_strong_alias (___vsnprintf_chk, __vsnprintf_chk)
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
index 53f07236ae..c1b1a8da4f 100644
--- a/debug/vsprintf_chk.c
+++ b/debug/vsprintf_chk.c
@@ -15,75 +15,20 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
-
-
-static int _IO_str_chk_overflow (FILE *fp, int c) __THROW;
-
-static int
-_IO_str_chk_overflow (FILE *fp, int c)
-{
-  /* When we come to here this means the user supplied buffer is
-     filled.  */
-  __chk_fail ();
-}
-
-
-static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_str_finish),
-  JUMP_INIT(overflow, _IO_str_chk_overflow),
-  JUMP_INIT(underflow, _IO_str_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_str_pbackfail),
-  JUMP_INIT(xsputn, _IO_default_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_str_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_default_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
+#include <libio/libioP.h>
 
 int
-___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
-		 va_list args)
+___vsprintf_chk (char *s, int flag, size_t slen, const char *format,
+		 va_list ap)
 {
-  _IO_strfile f;
-  int ret;
-#ifdef _IO_MTSAFE_IO
-  f._sbf._f._lock = NULL;
-#endif
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
   if (slen == 0)
     __chk_fail ();
 
-  _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&f._sbf) = &_IO_str_chk_jumps;
-  s[0] = '\0';
-  _IO_str_init_static_internal (&f, s, slen - 1, s);
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
-     can only come from read-only format strings.  */
-  if (flags > 0)
-    f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
-
-  *f._sbf._f._IO_write_ptr = '\0';
-  return ret;
+  return __vsprintf_internal (s, slen, format, ap, mode);
 }
 ldbl_hidden_def (___vsprintf_chk, __vsprintf_chk)
 ldbl_strong_alias (___vsprintf_chk, __vsprintf_chk)
diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
index 4d616f8835..2c6fadd463 100644
--- a/debug/vswprintf_chk.c
+++ b/debug/vswprintf_chk.c
@@ -15,60 +15,21 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
-/* VARARGS5 */
 int
-__vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
-		 const wchar_t *format, va_list args)
+__vswprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
+		 const wchar_t *format, va_list ap)
 {
-  /* XXX Maybe for less strict version do not fail immediately.
-     Though, maxlen is supposed to be the size of buffer pointed
-     to by s, so a conforming program can't pass such maxlen
-     to *snprintf.  */
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  _IO_wstrnfile sf;
-  struct _IO_wide_data wd;
-  int ret;
-#ifdef _IO_MTSAFE_IO
-  sf.f._sbf._f._lock = NULL;
-#endif
-
-  /* We need to handle the special case where MAXLEN is 0.  Use the
-     overflow buffer right from the start.  */
-  if (__glibc_unlikely (maxlen == 0))
-    /* Since we have to write at least the terminating L'\0' a buffer
-       length of zero always makes the function fail.  */
-    return -1;
-
-  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstrn_jumps);
-  _IO_fwide (&sf.f._sbf._f, 1);
-  s[0] = L'\0';
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
-  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
-
-  if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
-    /* ISO C99 requires swprintf/vswprintf to return an error if the
-       output does not fit int he provided buffer.  */
-    return -1;
-
-  /* Terminate the string.  */
-  *sf.f._sbf._f._wide_data->_IO_write_ptr = '\0';
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  return ret;
+  return __vswprintf_internal (s, maxlen, format, ap, mode);
 }
-libc_hidden_def (__vswprintf_chk)
diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
index fedc7a46bf..f1e8878a54 100644
--- a/debug/vwprintf_chk.c
+++ b/debug/vwprintf_chk.c
@@ -15,27 +15,16 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 __vwprintf_chk (int flag, const wchar_t *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = __vfwprintf_internal (stdout, format, ap, 0);
-
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return __vfwprintf_internal (stdout, format, ap, mode);
 }
diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
index 819050e5af..9f406e95f8 100644
--- a/debug/wprintf_chk.c
+++ b/debug/wprintf_chk.c
@@ -16,29 +16,22 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 __wprintf_chk (int flag, const wchar_t *format, ...)
 {
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
+  int ret;
 
   va_start (ap, format);
-  done = __vfwprintf_internal (stdout, format, ap, 0);
+  ret = __vfwprintf_internal (stdout, format, ap, mode);
   va_end (ap);
 
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return ret;
 }
diff --git a/include/stdio.h b/include/stdio.h
index 93b9385524..22fc916470 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -203,11 +203,6 @@ libc_hidden_proto (__open_memstream)
 libc_hidden_proto (__libc_fatal)
 rtld_hidden_proto (__libc_fatal)
 libc_hidden_proto (__vsprintf_chk)
-libc_hidden_proto (__vsnprintf_chk)
-libc_hidden_proto (__vfprintf_chk)
-libc_hidden_proto (__vasprintf_chk)
-libc_hidden_proto (__vdprintf_chk)
-libc_hidden_proto (__obstack_vprintf_chk)
 
 extern FILE * __fmemopen (void *buf, size_t len, const char *mode);
 libc_hidden_proto (__fmemopen)
diff --git a/include/wchar.h b/include/wchar.h
index 1db0ac8278..90b6e43f18 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -226,8 +226,6 @@ extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
 			    const wchar_t *__restrict __format,
 			    __gnuc_va_list __arg)
      /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
-libc_hidden_proto (__vfwprintf_chk)
-libc_hidden_proto (__vswprintf_chk)
 
 extern int __isoc99_fwscanf (__FILE *__restrict __stream,
 			     const wchar_t *__restrict __format, ...);
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index cf4b9973a7..513ca03013 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -27,8 +27,47 @@
 #include "libioP.h"
 #include "strfile.h"
 
+static int __THROW
+_IO_str_chk_overflow (FILE *fp, int c)
+{
+  /* If we get here, the user-supplied buffer would be overrun by
+     further output.  */
+  __chk_fail ();
+}
+
+static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
+{
+  JUMP_INIT_DUMMY,
+  JUMP_INIT(finish, _IO_str_finish),
+  JUMP_INIT(overflow, _IO_str_chk_overflow),
+  JUMP_INIT(underflow, _IO_str_underflow),
+  JUMP_INIT(uflow, _IO_default_uflow),
+  JUMP_INIT(pbackfail, _IO_str_pbackfail),
+  JUMP_INIT(xsputn, _IO_default_xsputn),
+  JUMP_INIT(xsgetn, _IO_default_xsgetn),
+  JUMP_INIT(seekoff, _IO_str_seekoff),
+  JUMP_INIT(seekpos, _IO_default_seekpos),
+  JUMP_INIT(setbuf, _IO_default_setbuf),
+  JUMP_INIT(sync, _IO_default_sync),
+  JUMP_INIT(doallocate, _IO_default_doallocate),
+  JUMP_INIT(read, _IO_default_read),
+  JUMP_INIT(write, _IO_default_write),
+  JUMP_INIT(seek, _IO_default_seek),
+  JUMP_INIT(close, _IO_default_close),
+  JUMP_INIT(stat, _IO_default_stat),
+  JUMP_INIT(showmanyc, _IO_default_showmanyc),
+  JUMP_INIT(imbue, _IO_default_imbue)
+};
+
+/* This function is called by regular vsprintf with maxlen set to -1,
+   and by vsprintf_chk with maxlen set to the size of the output
+   string.  In the former case, _IO_str_chk_overflow will never be
+   called; in the latter case it will crash the program if the buffer
+   overflows.  */
+
 int
-__vsprintf_internal (char *string, const char *format, va_list args,
+__vsprintf_internal (char *string, size_t maxlen,
+                     const char *format, va_list args,
                      unsigned int mode_flags)
 {
   _IO_strfile sf;
@@ -38,17 +77,22 @@ __vsprintf_internal (char *string, const char *format, va_list args,
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, string, -1, string);
+  _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps;
+  string[0] = '\0';
+  _IO_str_init_static_internal (&sf, string,
+                                (maxlen == -1) ? -1 : maxlen - 1,
+                                string);
+
   ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
-  _IO_putc_unlocked ('\0', &sf._sbf._f);
+
+  *sf._sbf._f._IO_write_ptr = '\0';
   return ret;
 }
 
 int
 __vsprintf (char *string, const char *format, va_list args)
 {
-  return __vsprintf_internal (string, format, args, 0);
+  return __vsprintf_internal (string, -1, format, args, 0);
 }
 
 ldbl_strong_alias (__vsprintf, _IO_vsprintf)
diff --git a/libio/libio.h b/libio/libio.h
index 1025f3343e..68dac44635 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -90,7 +90,6 @@ typedef union
 /* Bits for the _flags2 field.  */
 #define _IO_FLAGS2_MMAP 1
 #define _IO_FLAGS2_NOTCANCEL 2
-#define _IO_FLAGS2_FORTIFY 4
 #define _IO_FLAGS2_USER_WBUF 8
 #define _IO_FLAGS2_NOCLOSE 32
 #define _IO_FLAGS2_CLOEXEC 64
diff --git a/libio/libioP.h b/libio/libioP.h
index 17eda383d3..07b60e3e26 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -672,8 +672,13 @@ extern int __vdprintf_internal (int d, const char *format, va_list ap,
 extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
                                        va_list ap, unsigned int mode_flags);
 
-extern int __vsprintf_internal (char *string, const char *format, va_list ap,
+/* Note: __vsprintf_internal, unlike vsprintf, does take a maxlen argument,
+   because it's called by both vsprintf and vsprintf_chk.  If maxlen is
+   not set to -1, overrunning the buffer will cause a prompt crash.  */
+extern int __vsprintf_internal (char *string, size_t maxlen,
+                                const char *format, va_list ap,
                                 unsigned int mode_flags);
+
 extern int __vsnprintf_internal (char *string, size_t maxlen,
                                  const char *format, va_list ap,
                                  unsigned int mode_flags);
@@ -788,26 +793,10 @@ _IO_acquire_lock_fct (FILE **p)
     _IO_funlockfile (fp);
 }
 
-static inline void
-__attribute__ ((__always_inline__))
-_IO_acquire_lock_clear_flags2_fct (FILE **p)
-{
-  FILE *fp = *p;
-  fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY);
-  if ((fp->_flags & _IO_USER_LOCK) == 0)
-    _IO_funlockfile (fp);
-}
-
 #if !defined _IO_MTSAFE_IO && IS_IN (libc)
 # define _IO_acquire_lock(_fp)						      \
-  do {									      \
-    FILE *_IO_acquire_lock_file = NULL
-# define _IO_acquire_lock_clear_flags2(_fp)				      \
-  do {									      \
-    FILE *_IO_acquire_lock_file = (_fp)
+  do {
 # define _IO_release_lock(_fp)						      \
-    if (_IO_acquire_lock_file != NULL)					      \
-      _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY);		      \
   } while (0)
 #endif
 
diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
index 77423b292f..447faa4e25 100644
--- a/stdio-common/sprintf.c
+++ b/stdio-common/sprintf.c
@@ -27,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vsprintf_internal (s, format, arg, 0);
+  done = __vsprintf_internal (s, -1, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index d8716f4f07..e2f44b74f3 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -1285,8 +1285,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
   /* Temporarily honor environmental settings.  */
   if (__ldbl_is_dbl)
     mode_flags |= PRINTF_LDBL_IS_DBL;
-  if (s->_flags2 & _IO_FLAGS2_FORTIFY)
-    mode_flags |= PRINTF_FORTIFY;
 
   /* Orient the stream.  */
 #ifdef ORIENT
diff --git a/sysdeps/generic/stdio-lock.h b/sysdeps/generic/stdio-lock.h
index 4a40618545..25ccd07f29 100644
--- a/sysdeps/generic/stdio-lock.h
+++ b/sysdeps/generic/stdio-lock.h
@@ -54,15 +54,8 @@ __libc_lock_define_recursive (typedef, _IO_lock_t)
 	__attribute__((cleanup (_IO_acquire_lock_fct)))			      \
 	= (_fp);							      \
     _IO_flockfile (_IO_acquire_lock_file);
-#  define _IO_acquire_lock_clear_flags2(_fp) \
-  do {									      \
-    FILE *_IO_acquire_lock_file						      \
-	__attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct)))	      \
-	= (_fp);							      \
-    _IO_flockfile (_IO_acquire_lock_file);
 # else
 #  define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
-#  define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
 # endif
 # define _IO_release_lock(_fp) ; } while (0)
 
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index f00eb55eb5..f29c28e888 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -178,7 +178,7 @@ __nldbl___vsprintf (char *string, const char *fmt, va_list ap)
 {
   int done;
   __no_long_double = 1;
-  done = __vsprintf_internal (string, fmt, ap, 0);
+  done = __vsprintf_internal (string, -1, fmt, ap, 0);
   __no_long_double = 0;
   return done;
 }
@@ -578,7 +578,7 @@ __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = __vfprintf_chk (s, flag, fmt, ap);
+  res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
   clear_no_long_double ();
   return res;
 }
@@ -590,7 +590,7 @@ __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = __vfwprintf_chk (s, flag, fmt, ap);
+  res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
   clear_no_long_double ();
   return res;
 }
@@ -608,9 +608,13 @@ attribute_compat_text_section
 __nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen,
 			 const char *fmt, va_list ap)
 {
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
   int res;
   __no_long_double = 1;
-  res = __vsnprintf_chk (string, maxlen, flag, slen, fmt, ap);
+  res = __vsnprintf_internal (string, maxlen, fmt, ap,
+			      (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
@@ -621,9 +625,13 @@ attribute_compat_text_section
 __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
 			va_list ap)
 {
+  if (slen == 0)
+    __chk_fail ();
+
   int res;
   __no_long_double = 1;
-  res = __vsprintf_chk (string, flag, slen, fmt, ap);
+  res = __vsprintf_internal (string, slen, fmt, ap,
+			     (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
@@ -634,9 +642,13 @@ attribute_compat_text_section
 __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
 			 const wchar_t *fmt, va_list ap)
 {
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
   int res;
   __no_long_double = 1;
-  res = __vswprintf_chk (string, maxlen, flag, slen, fmt, ap);
+  res = __vswprintf_internal (string, maxlen, fmt, ap,
+			      (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
@@ -669,7 +681,8 @@ __nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg)
 {
   int res;
   __no_long_double = 1;
-  res = __vasprintf_chk (ptr, flag, fmt, arg);
+  res = __vasprintf_internal (ptr, fmt, arg,
+			      (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
@@ -695,7 +708,7 @@ __nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg)
 {
   int res;
   set_no_long_double ();
-  res = __vdprintf_chk (d, flag, fmt, arg);
+  res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0);
   clear_no_long_double ();
   return res;
 }
@@ -722,7 +735,8 @@ __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag,
 {
   int res;
   __no_long_double = 1;
-  res = __obstack_vprintf_chk (obstack, flag, fmt, arg);
+  res = __obstack_vprintf_internal (obstack, fmt, arg,
+				    (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
diff --git a/sysdeps/nptl/stdio-lock.h b/sysdeps/nptl/stdio-lock.h
index 5b9782452f..1d6a81c5bf 100644
--- a/sysdeps/nptl/stdio-lock.h
+++ b/sysdeps/nptl/stdio-lock.h
@@ -94,15 +94,8 @@ typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
 	__attribute__((cleanup (_IO_acquire_lock_fct)))			      \
 	= (_fp);							      \
     _IO_flockfile (_IO_acquire_lock_file);
-#  define _IO_acquire_lock_clear_flags2(_fp) \
-  do {									      \
-    FILE *_IO_acquire_lock_file						      \
-	__attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct)))	      \
-	= (_fp);							      \
-    _IO_flockfile (_IO_acquire_lock_file);
 # else
 #  define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
-#  define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
 # endif
 # define _IO_release_lock(_fp) ; } while (0)
 
-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 9/9] Post-cleanup: don't include math.h/math_private.h in math_ldbl_opt.h.
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (6 preceding siblings ...)
  2018-03-07 19:32 ` [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal Zack Weinberg
@ 2018-03-07 19:51 ` Zack Weinberg
  2018-03-07 19:51 ` [PATCH 7/9] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY Zack Weinberg
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: Zack Weinberg @ 2018-03-07 19:51 UTC (permalink / raw)
  To: libc-alpha

One version of math_ldbl_opt.h includes math.h and math_private.h, the
other doesn't.  The _contents_ of math_ldbl_opt.h do not depend in any
way on the declarations in those headers, so this is just asking for
trouble down the road.  Indeed, about 15 files that don't necessarily
have to be used on an ldbl-opt platform are relying on that
math_ldbl_opt.h to include math.h and/or math_private.h.  And those
are just the ones I found by compiling on PPC64.  I plan to run
build-many-glibcs and add more fixes to this patch as necessary.


	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h: Don't include
	math.h or math_private.h.

	* sysdeps/ieee754/ldbl-128ibm/s_ceill.c
	* sysdeps/ieee754/ldbl-128ibm/s_floorl.c
	* sysdeps/ieee754/ldbl-128ibm/s_llrintl.c
	* sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
	* sysdeps/ieee754/ldbl-128ibm/s_lrintl.c
	* sysdeps/ieee754/ldbl-128ibm/s_lroundl.c
	* sysdeps/ieee754/ldbl-128ibm/s_rintl.c
	* sysdeps/ieee754/ldbl-128ibm/s_roundl.c
	* sysdeps/ieee754/ldbl-128ibm/s_truncl.c
	* sysdeps/powerpc/powerpc64/fpu/multiarch/e_expf.c
	* sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypot.c
	* sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypotf.c:
	Include math_private.h.

	* sysdeps/powerpc/power7/fpu/s_logb.c:
	Include math.h and math_private.h.
---
 sysdeps/ieee754/ldbl-128ibm/s_ceill.c              | 1 +
 sysdeps/ieee754/ldbl-128ibm/s_floorl.c             | 1 +
 sysdeps/ieee754/ldbl-128ibm/s_llrintl.c            | 1 +
 sysdeps/ieee754/ldbl-128ibm/s_llroundl.c           | 1 +
 sysdeps/ieee754/ldbl-128ibm/s_lrintl.c             | 1 +
 sysdeps/ieee754/ldbl-128ibm/s_lroundl.c            | 1 +
 sysdeps/ieee754/ldbl-128ibm/s_rintl.c              | 1 +
 sysdeps/ieee754/ldbl-128ibm/s_roundl.c             | 1 +
 sysdeps/ieee754/ldbl-128ibm/s_truncl.c             | 1 +
 sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h           | 5 -----
 sysdeps/powerpc/power7/fpu/s_logb.c                | 2 ++
 sysdeps/powerpc/powerpc64/fpu/multiarch/e_expf.c   | 1 +
 sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypot.c  | 1 +
 sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypotf.c | 1 +
 14 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/sysdeps/ieee754/ldbl-128ibm/s_ceill.c b/sysdeps/ieee754/ldbl-128ibm/s_ceill.c
index 22eddcfcd3..7dcff021c4 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_ceill.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_ceill.c
@@ -18,6 +18,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <math.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <float.h>
 #include <ieee754.h>
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_floorl.c b/sysdeps/ieee754/ldbl-128ibm/s_floorl.c
index 2131934cc1..4aae5ae608 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_floorl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_floorl.c
@@ -18,6 +18,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <math.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <float.h>
 #include <ieee754.h>
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_llrintl.c b/sysdeps/ieee754/ldbl-128ibm/s_llrintl.c
index f2f4c19b0e..9d4535103e 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_llrintl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_llrintl.c
@@ -19,6 +19,7 @@
 
 #include <math.h>
 #include <fenv.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <float.h>
 #include <ieee754.h>
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
index 5bfa83cee3..de6a7b5be2 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
@@ -19,6 +19,7 @@
 
 #include <math.h>
 #include <fenv.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <float.h>
 #include <ieee754.h>
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_lrintl.c b/sysdeps/ieee754/ldbl-128ibm/s_lrintl.c
index c2e2f68984..05fe7fefdf 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_lrintl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_lrintl.c
@@ -19,6 +19,7 @@
 
 #include <math.h>
 #include <fenv.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <float.h>
 #include <ieee754.h>
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_lroundl.c b/sysdeps/ieee754/ldbl-128ibm/s_lroundl.c
index 010e8e28a1..bc8dda4c1d 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_lroundl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_lroundl.c
@@ -19,6 +19,7 @@
 
 #include <math.h>
 #include <fenv.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <float.h>
 #include <ieee754.h>
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_rintl.c b/sysdeps/ieee754/ldbl-128ibm/s_rintl.c
index 9c4514eec3..73d2b4edfe 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_rintl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_rintl.c
@@ -22,6 +22,7 @@
 
 #include <math.h>
 #include <fenv.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <float.h>
 #include <ieee754.h>
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_roundl.c b/sysdeps/ieee754/ldbl-128ibm/s_roundl.c
index 5915d53a18..94a62dcd6c 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_roundl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_roundl.c
@@ -21,6 +21,7 @@
    when it's coded in C.  */
 
 #include <math.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <float.h>
 #include <ieee754.h>
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_truncl.c b/sysdeps/ieee754/ldbl-128ibm/s_truncl.c
index a4638b5da9..a915a01ac6 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_truncl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_truncl.c
@@ -18,6 +18,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <math.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <float.h>
 #include <ieee754.h>
diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
index 2b8f3e3c10..53e40af3e7 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -38,8 +38,3 @@
   weak_alias (local, symbol)
 # endif
 #endif
-
-#ifndef __ASSEMBLER__
-# include <math.h>
-# include <math_private.h>
-#endif
diff --git a/sysdeps/powerpc/power7/fpu/s_logb.c b/sysdeps/powerpc/power7/fpu/s_logb.c
index 160b9334de..f7eec8ff06 100644
--- a/sysdeps/powerpc/power7/fpu/s_logb.c
+++ b/sysdeps/powerpc/power7/fpu/s_logb.c
@@ -16,6 +16,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <math.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <libm-alias-double.h>
 
diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/e_expf.c b/sysdeps/powerpc/powerpc64/fpu/multiarch/e_expf.c
index af103e47b5..f752514efa 100644
--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/e_expf.c
+++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/e_expf.c
@@ -17,6 +17,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <math.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include "init-arch.h"
 
diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypot.c b/sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypot.c
index cb771a3fe4..8d05c430cc 100644
--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypot.c
+++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypot.c
@@ -17,6 +17,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <math.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
 #include "init-arch.h"
diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypotf.c b/sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypotf.c
index e46ef68bfe..9bef1fea3f 100644
--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypotf.c
+++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/e_hypotf.c
@@ -17,6 +17,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <math.h>
+#include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
 #include "init-arch.h"
-- 
2.16.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 0/9] Use more flags parameters instead of global bits in stdio
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (8 preceding siblings ...)
  2018-03-07 19:51 ` [PATCH 7/9] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY Zack Weinberg
@ 2018-03-12 15:29 ` Zack Weinberg
  2018-03-26 15:16 ` Gabriel F. T. Gomes
  2018-06-27 15:50 ` Florian Weimer
  11 siblings, 0 replies; 37+ messages in thread
From: Zack Weinberg @ 2018-03-12 15:29 UTC (permalink / raw)
  To: GNU C Library

On Wed, Mar 7, 2018 at 2:31 PM, Zack Weinberg <zackw@panix.com> wrote:
> I got stuck on the patch to use C99-compliant scanf in _GNU_SOURCE
> mode because the interaction with ldbl-is-dbl was too confusing.  The
> reason it's too confusing is that C99 compliance in scanf, ldbl-is-dbl
> mode in scanf, printf, and strfmon, and fortify mode in printf are
> handled with mode bits on the FILE and thread-global flags that must
> be set and reset at just the right times.  Correct behavior is
> invariably to set and then reset around just one call to a lower-level
> function, and there's a better way to do that: flags parameters.
>
> This patch series implements _internal variants of scanf, printf,
> strfmon, and syslog that take flag parameters that control C99
> compliance, ldbl-is-dbl mode, and fortification.

Ping?  These patches have now survived build-many-glibcs testing on
all supported platforms except the Hurd (I still can't successfully
build an i686-gnu cross compiler) and are waiting for review.  Note
that an expanded version of the "post-cleanup" has already been
committed.

zw

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 1/9] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-07 19:32 ` [PATCH 1/9] Use STRFMON_LDBL_IS_DBL " Zack Weinberg
@ 2018-03-12 20:36   ` Adhemerval Zanella
  2018-03-12 21:11     ` Zack Weinberg
  2018-03-26 15:17   ` Gabriel F. T. Gomes
  1 sibling, 1 reply; 37+ messages in thread
From: Adhemerval Zanella @ 2018-03-12 20:36 UTC (permalink / raw)
  To: libc-alpha



On 07/03/2018 16:31, Zack Weinberg wrote:
> This patch takes the first step toward removing the global flag
> __ldbl_is_dbl, creating a __vstrfmon_l_internal that takes a flags
> parameter instead.
> 
> This change arguably makes the generated code slightly worse on
> architectures where __ldbl_is_dbl is never true; right now, on those
> architectures, it's a compile-time constant; after this change, the
> compiler could theoretically prove that __vstrfmon_l_internal was
> never called with a nonzero flags argument, but it would probably need
> LTO to do it.  This is not performance critical code and I tend to
> think that the maintainability benefits of removing action at a
> distance are worth it.  However, we _could_ wrap the runtime flag
> check with a macro that was defined to ignore its argument and always
> return false on architectures where __ldbl_is_dbl is never true, if
> people think the codegen benefits are important.
> 
> 	* include/monetary.h (STRFMON_LDBL_IS_DBL): New constant.
> 	(__vstrfmon_l): Rename to __vstrfmon_l_internal and add flags
> 	argument.
> 	* stdlib/strfmon_l.c (__vstrfmon_l): Rename to __vstrfmon_l_internal
> 	and add flags argument.	 Check flags instead of __ldbl_is_dbl when
> 	deciding whether to set is_long_double.
> 	(__strfmon_l): Call __vstrfmon_l_internal instead of __vstrfmon_l,
> 	passing zero for flags argument.
> 	* stdlib/strfmon.c (strfmon): Same change as made to __strfmon_l.
> 
> 	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> 	(__nldbl___vstrfmon, __nldbl___vstrfmon_l)
> 	(__nldbl_strfmon, __nldbl___strfmon_l): Call __vstrfmon_l_internal
> 	directly, passing STRFMON_LDBL_IS_DBL for flags argument.  Normalize
> 	variable names.  Remove libc_hidden_def/libc_hidden_proto.
> 	* sysdeps/ieee754/ldbl-opt/nldbl-compat.h: Don't use NLDBL_DECL
> 	for __nldbl___vstrfmon_l.
> 
> 	* manual/locale.texi: Update a reference to vstrfmon_l in comments.

LGTM with a style remark below.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>

> ---
>  include/monetary.h                      | 10 +++++++---
>  manual/locale.texi                      |  9 +++++----
>  stdlib/strfmon.c                        |  3 ++-
>  stdlib/strfmon_l.c                      |  8 ++++----
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 34 ++++++++++++---------------------
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.h |  8 +++++---
>  6 files changed, 35 insertions(+), 37 deletions(-)
> 
> diff --git a/include/monetary.h b/include/monetary.h
> index c130ed56a3..d12ae03dd3 100644
> --- a/include/monetary.h
> +++ b/include/monetary.h
> @@ -2,7 +2,11 @@
>  #ifndef _ISOMAC
>  #include <stdarg.h>
>  
> -extern ssize_t __vstrfmon_l (char *s, size_t maxsize, locale_t loc,
> -			     const char *format, va_list ap)
> -     attribute_hidden;
> +extern ssize_t __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
> +                                      const char *format, va_list ap,
> +                                      unsigned int flags);
> +
> +/* Flags for __vstrfmon_l_internal.  */
> +#define STRFMON_LDBL_IS_DBL 0x0001
> +
>  #endif
> diff --git a/manual/locale.texi b/manual/locale.texi
> index dabb959f9e..720e0ca952 100644
> --- a/manual/locale.texi
> +++ b/manual/locale.texi
> @@ -1209,10 +1209,11 @@ numbers according to these rules.
>  
>  @deftypefun ssize_t strfmon (char *@var{s}, size_t @var{maxsize}, const char *@var{format}, @dots{})
>  @safety{@prelim{}@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}}
> -@c It (and strfmon_l) both call vstrfmon_l, which, besides accessing the
> -@c locale object passed to it, accesses the active locale through
> -@c isdigit (but to_digit assumes ASCII digits only).  It may call
> -@c __printf_fp (@mtslocale @ascuheap @acsmem) and guess_grouping (safe).
> +@c It (and strfmon_l) both call __vstrfmon_l_internal, which, besides
> +@c accessing the locale object passed to it, accesses the active
> +@c locale through isdigit (but to_digit assumes ASCII digits only).
> +@c It may call __printf_fp (@mtslocale @ascuheap @acsmem) and
> +@c guess_grouping (safe).
>  The @code{strfmon} function is similar to the @code{strftime} function
>  in that it takes a buffer, its size, a format string,
>  and values to write into the buffer as text in a form specified
> diff --git a/stdlib/strfmon.c b/stdlib/strfmon.c
> index 01980d3e15..2b742c7ad7 100644
> --- a/stdlib/strfmon.c
> +++ b/stdlib/strfmon.c
> @@ -30,7 +30,8 @@ __strfmon (char *s, size_t maxsize, const char *format, ...)
>  
>    va_start (ap, format);
>  
> -  ssize_t res = __vstrfmon_l (s, maxsize, _NL_CURRENT_LOCALE, format, ap);
> +  ssize_t res = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE,
> +                                       format, ap, 0);
>  
>    va_end (ap);
>  
> diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
> index cd3796ced9..f0ebd99bd3 100644
> --- a/stdlib/strfmon_l.c
> +++ b/stdlib/strfmon_l.c
> @@ -76,8 +76,8 @@
>     too.  Some of the information contradicts the information which can
>     be specified in format string.  */
>  ssize_t
> -__vstrfmon_l (char *s, size_t maxsize, locale_t loc, const char *format,
> -	      va_list ap)
> +__vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
> +                       const char *format, va_list ap, unsigned int flags)
>  {
>    struct __locale_data *current = loc->__locales[LC_MONETARY];
>    _IO_strfile f;
> @@ -268,7 +268,7 @@ __vstrfmon_l (char *s, size_t maxsize, locale_t loc, const char *format,
>        if (*fmt == 'L')
>  	{
>  	  ++fmt;
> -	  if (!__ldbl_is_dbl)
> +	  if (__glibc_likely ((flags & STRFMON_LDBL_IS_DBL) == 0))
>  	    is_long_double = 1;
>  	}
>  
> @@ -608,7 +608,7 @@ ___strfmon_l (char *s, size_t maxsize, locale_t loc, const char *format, ...)
>  
>    va_start (ap, format);
>  
> -  ssize_t res = __vstrfmon_l (s, maxsize, loc, format, ap);
> +  ssize_t res = __vstrfmon_l_internal (s, maxsize, loc, format, ap, 0);
>  
>    va_end (ap);
>  
> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index bf54090d4f..7d19eaba8d 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -50,8 +50,6 @@ libc_hidden_proto (__nldbl___vswprintf_chk)
>  libc_hidden_proto (__nldbl___vasprintf_chk)
>  libc_hidden_proto (__nldbl___vdprintf_chk)
>  libc_hidden_proto (__nldbl___obstack_vprintf_chk)
> -libc_hidden_proto (__nldbl___vstrfmon)
> -libc_hidden_proto (__nldbl___vstrfmon_l)
>  libc_hidden_proto (__nldbl___isoc99_vsscanf)
>  libc_hidden_proto (__nldbl___isoc99_vfscanf)
>  libc_hidden_proto (__nldbl___isoc99_vswscanf)
> @@ -779,12 +777,13 @@ attribute_compat_text_section
>  __nldbl_strfmon (char *s, size_t maxsize, const char *format, ...)
>  {
>    va_list ap;
> -  ssize_t res;
> +  ssize_t ret;
>  
>    va_start (ap, format);
> -  res = __nldbl___vstrfmon (s, maxsize, format, ap);
> +  ret = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE, format, ap,
> +                               STRFMON_LDBL_IS_DBL);
>    va_end (ap);
> -  return res;
> +  return ret;
>  }

I tend to frown at variable names changes such this case, it just add diff
lines without improvement in code readability.

>  
>  ssize_t
> @@ -793,12 +792,13 @@ __nldbl___strfmon_l (char *s, size_t maxsize, locale_t loc,
>  		     const char *format, ...)
>  {
>    va_list ap;
> -  ssize_t res;
> +  ssize_t ret;
>  
>    va_start (ap, format);
> -  res = __nldbl___vstrfmon_l (s, maxsize, loc, format, ap);
> +  ret = __vstrfmon_l_internal (s, maxsize, loc, format, ap,
> +                               STRFMON_LDBL_IS_DBL);
>    va_end (ap);
> -  return res;
> +  return ret;
>  }
>  weak_alias (__nldbl___strfmon_l, __nldbl_strfmon_l)
>  
> @@ -806,28 +806,18 @@ ssize_t
>  attribute_compat_text_section
>  __nldbl___vstrfmon (char *s, size_t maxsize, const char *format, va_list ap)
>  {
> -  ssize_t res;
> -  __no_long_double = 1;
> -  res = __vstrfmon_l (s, maxsize, _NL_CURRENT_LOCALE, format, ap);
> -  __no_long_double = 0;
> -  va_end (ap);
> -  return res;
> +  return __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE, format, ap,
> +				STRFMON_LDBL_IS_DBL);
>  }
> -libc_hidden_def (__nldbl___vstrfmon)
>  
>  ssize_t
>  attribute_compat_text_section
>  __nldbl___vstrfmon_l (char *s, size_t maxsize, locale_t loc,
>  		      const char *format, va_list ap)
>  {
> -  ssize_t res;
> -  __no_long_double = 1;
> -  res = __vstrfmon_l (s, maxsize, loc, format, ap);
> -  __no_long_double = 0;
> -  va_end (ap);
> -  return res;
> +  return __vstrfmon_l_internal (s, maxsize, loc, format, ap,
> +				STRFMON_LDBL_IS_DBL);
>  }
> -libc_hidden_def (__nldbl___vstrfmon_l)
>  
>  void
>  attribute_compat_text_section
> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
> index 74f0e459fa..a9a77dce99 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
> @@ -60,7 +60,6 @@ NLDBL_DECL (vsyslog);
>  NLDBL_DECL (qecvt);
>  NLDBL_DECL (qfcvt);
>  NLDBL_DECL (qgcvt);
> -NLDBL_DECL (__vstrfmon_l);
>  NLDBL_DECL (__isoc99_scanf);
>  NLDBL_DECL (__isoc99_fscanf);
>  NLDBL_DECL (__isoc99_sscanf);
> @@ -74,10 +73,13 @@ NLDBL_DECL (__isoc99_vwscanf);
>  NLDBL_DECL (__isoc99_vfwscanf);
>  NLDBL_DECL (__isoc99_vswscanf);
>  
> -/* This one does not exist in the normal interface, only
> -   __nldbl___vstrfmon really exists.  */
> +/* These do not exist in the normal interface, but must exist in the
> +   __nldbl interface so that they can be called from libnldbl.  */
>  extern ssize_t __nldbl___vstrfmon (char *, size_t, const char *, va_list)
>    __THROW;
> +extern ssize_t __nldbl___vstrfmon_l (char *, size_t, locale_t, const char *,
> +				     va_list)
> +  __THROW;
>  
>  /* These don't use __typeof because they were not declared by the headers,
>     since we don't compile with _FORTIFY_SOURCE.  */
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 1/9] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-12 20:36   ` Adhemerval Zanella
@ 2018-03-12 21:11     ` Zack Weinberg
  2018-03-13 11:45       ` Adhemerval Zanella
  0 siblings, 1 reply; 37+ messages in thread
From: Zack Weinberg @ 2018-03-12 21:11 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: GNU C Library

On Mon, Mar 12, 2018 at 4:36 PM, Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
>>    va_start (ap, format);
>> -  res = __nldbl___vstrfmon (s, maxsize, format, ap);
>> +  ret = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE, format, ap,
>> +                               STRFMON_LDBL_IS_DBL);
>>    va_end (ap);
>> -  return res;
>> +  return ret;
>>  }
>
> I tend to frown at variable names changes such this case, it just add diff
> lines without improvement in code readability.

This might look pointless by itself, but as you go through the other
patches you will see that many other functions in this file are using
_different_ conventions for their variable names, so making the whole
file be consistent is worthwhile IMHO.  I thought it was better to
touch each function as I was making other changes to it anyway.

zw

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 1/9] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-12 21:11     ` Zack Weinberg
@ 2018-03-13 11:45       ` Adhemerval Zanella
  0 siblings, 0 replies; 37+ messages in thread
From: Adhemerval Zanella @ 2018-03-13 11:45 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: GNU C Library



On 12/03/2018 18:10, Zack Weinberg wrote:
> On Mon, Mar 12, 2018 at 4:36 PM, Adhemerval Zanella
> <adhemerval.zanella@linaro.org> wrote:
>>>    va_start (ap, format);
>>> -  res = __nldbl___vstrfmon (s, maxsize, format, ap);
>>> +  ret = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE, format, ap,
>>> +                               STRFMON_LDBL_IS_DBL);
>>>    va_end (ap);
>>> -  return res;
>>> +  return ret;
>>>  }
>>
>> I tend to frown at variable names changes such this case, it just add diff
>> lines without improvement in code readability.
> 
> This might look pointless by itself, but as you go through the other
> patches you will see that many other functions in this file are using
> _different_ conventions for their variable names, so making the whole
> file be consistent is worthwhile IMHO.  I thought it was better to
> touch each function as I was making other changes to it anyway.
> 
> zw
> 

Fair enough, this is more a personal preference and this is not really 
a patch blocker (sorry if my ack showed this intention).

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-03-07 19:32 ` [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal Zack Weinberg
@ 2018-03-13 11:59   ` Florian Weimer
  2018-03-13 12:39     ` Zack Weinberg
  0 siblings, 1 reply; 37+ messages in thread
From: Florian Weimer @ 2018-03-13 11:59 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha

On 03/07/2018 08:32 PM, Zack Weinberg wrote:

> +/* __vsyslog_internal uses the same mode_flags bits as
> +   __v*printf_internal; see libio/libioP.h.  */
> +extern void __vsyslog_internal (int pri, const char *fmt, __gnuc_va_list ap,
> +                                unsigned int mode_flags)
> +     __attribute__ ((__format__ (__printf__, 2, 0)));

I'm surprised that this doesn't need attribute_hidden or 
libc_hidden_proto to avoid new PLT calls.

Rest looks okay.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-03-07 19:32 ` [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments Zack Weinberg
@ 2018-03-13 12:35   ` Adhemerval Zanella
  2018-06-29 14:04     ` Florian Weimer
  2018-03-26 15:28   ` Gabriel F. T. Gomes
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 37+ messages in thread
From: Adhemerval Zanella @ 2018-03-13 12:35 UTC (permalink / raw)
  To: libc-alpha



On 07/03/2018 16:31, Zack Weinberg wrote:
> There are two flags currently defined: SCANF_LDBL_IS_DBL is the mode
> used by __nldbl_ scanf variants, and SCANF_ISOC99_A is the mode used
> by __isoc99_ scanf variants.  In this patch, the new functions honor
> these flag bits if they're set, but they still also look at the
> corresponding bits of environmental state, and callers all pass zero.
> 
> The new functions do *not* have the "errp" argument possessed by
> _IO_vfscanf and _IO_vfwscanf.  All internal callers passed NULL for
> that argument.  External callers could theoretically exist, so I
> preserved wrappers, but they are flagged as compat symbols and they
> don't preserve the three-way distinction among types of errors that
> was formerly exposed.  These functions probably should have been in
> the list of deprecated _IO_ symbols in 2.27 NEWS -- they're not just
> aliases for vfscanf and vfwscanf.
> 
> (It was necessary to introduce ldbl_compat_symbol for _IO_vfscanf.
> Please check that part of the patch very carefully, I am still not
> confident I understand all of the details of ldbl-opt.)
> 
> This patch also introduces helper inlines in libio/strfile.h that
> encapsulate the process of initializing an _IO_strfile object for
> reading.  This allows us to call __vfscanf_internal directly from
> sscanf, and __vfwscanf_internal directly from swscanf, without
> duplicating the initialization code.  (Previously, they called their
> v-counterparts, but that won't work if we want to control *both* C99
> mode and ldbl-is-dbl mode using the flags argument to__vfscanf_internal.)
> It's still a little awkward, especially for wide strfiles, but it's
> much better than what we had.

Look good in general, some remarks below.

> 
> 	* libio/libioP.h (SCANF_LDBL_IS_DBL, SCANF_ISOC99_A): New constants.
> 	(__vfscanf_internal, __vfwscanf_internal): New function prototypes.
>         * libio/libio.h: Remove libc_hidden_proto for _IO_vfscanf.
> 	* libio/strfile.h: Add multiple inclusion guard.
> 	(_IO_strfile_read, _IO_strfile_readw): New inline functions.
> 
> 	* sysdeps/generic/math_ldbl_opt.h: Include shlib-compat.h, for
> 	consistency with the other version of this file.
> 	(ldbl_compat_symbol): New macro.
> 	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h (ldbl_compat_symbol):
> 	New macro.
> 
> 	* stdio-common/vfscanf-internal.c: Rename from vfscanf.c.
> 	Define __vfscanf_internal or __vfwscanf_internal, depending on
> 	COMPILE_WPRINTF; don't define any other public symbols.
> 	Temporarily check __ldbl_is_dbl and _IO_FLAGS2_SCANF_STD as well
> 	as the mode_flags argument.
> 	(encode_error, conv_error, input_error): Don't set errval.
> 	* stdio-common/vfwscanf-internal.c: Rename from vfwscanf.c.
> 	Include vfscanf-internal.c.
> 	* stdio-common/vfscanf.c, stdio-common/vfwscanf.c: New files
> 	defining the public entry points vfscanf and vfwscanf respectively.
> 	* stdio-common/iovfscanf.c, stdio-common/iovfwscanf.c: New files
> 	defining the compat symbols _IO_vfscanf and _IO_vfwscanf respectively.
> 	* stdio-common/Makefile (routines): Add vfscanf-internal,
> 	vfwscanf-internal, iovfscanf, iovfwscanf.
>         * stdio-common/Versions: Mention GLIBC_2.28, so that
>         it can be used in SHLIB_COMPAT expressions.
> 	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl__IO_vfscanf):
> 	Wrap definition and compat_symbol line in #if SHLIB_COMPAT.
> 
> 	* libio/iovsscanf.c, libio/vscanf.c, libio/vwscanf.c, libio/wscanf.c
> 	* libio/iovswscanf.c, stdio-common/isoc99_fscanf.c
> 	* stdio-common/isoc99_scanf.c, stdio-common/isoc99_vfscanf.c
> 	* stdio-common/isoc99_vscanf.c, stdio-common/isoc99_vsscanf.c
> 	* stdio-common/scanf.c, sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> 	* wcsmbs/isoc99_fwscanf.c, wcsmbs/isoc99_vfwscanf.c
> 	* wcsmbs/isoc99_vswscanf.c, wcsmbs/isoc99_vwscanf.c
> 	* wcsmbs/isoc99_wscanf.c: Use __vfscanf_internal instead of
> 	_IO_vfscanf, and/or __vfwscanf_internal instead of _IO_vfwscanf.
> 
> 	* libio/iovsscanf.c, stdio-common/isoc99_vsscanf.c:
> 	Use _IO_strfile_read.  Clean up includes.
> 	* stdio-common/sscanf.c, stdio-common/isoc99_sscanf.c:
> 	Use _IO_strfile_read to set up a FILE, and then call
> 	__vfwcanf_internal directly.  Clean up includes.
> 
> 	* libio/iovswscanf.c, wcsmbs/isoc99_vswscanf.c:
> 	Use _IO_strfile_readw.  Clean up includes.
> 	* libio/swscanf.c, wcsmbs/isoc99_swscanf.c:
> 	Use _IO_strfile_readw to set up a FILE, and then call
> 	__vfwscanf_internal directly.  Clean up includes.
> ---
>  libio/iovsscanf.c                                |   12 +-
>  libio/iovswscanf.c                               |   14 +-
>  libio/libio.h                                    |    1 -
>  libio/libioP.h                                   |    9 +
>  libio/strfile.h                                  |   33 +-
>  libio/swscanf.c                                  |   10 +-
>  libio/vscanf.c                                   |    2 +-
>  libio/vwscanf.c                                  |    2 +-
>  libio/wscanf.c                                   |    2 +-
>  stdio-common/Makefile                            |    3 +-
>  stdio-common/Versions                            |    3 +
>  stdio-common/iovfscanf.c                         |   34 +
>  stdio-common/iovfwscanf.c                        |   34 +
>  stdio-common/isoc99_fscanf.c                     |    2 +-
>  stdio-common/isoc99_scanf.c                      |    2 +-
>  stdio-common/isoc99_sscanf.c                     |    8 +-
>  stdio-common/isoc99_vfscanf.c                    |    2 +-
>  stdio-common/isoc99_vscanf.c                     |    2 +-
>  stdio-common/isoc99_vsscanf.c                    |   17 +-
>  stdio-common/scanf.c                             |    2 +-
>  stdio-common/sscanf.c                            |   12 +-
>  stdio-common/{vfscanf.c => vfscanf-internal.c}   |   46 +-
>  stdio-common/vfscanf.c                           |   27 +
>  stdio-common/{vfwscanf.c => vfwscanf-internal.c} |    2 +-
>  stdio-common/vfwscanf.c                          |   25 +
>  sysdeps/generic/math_ldbl_opt.h                  |    4 +
>  sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h         |    4 +
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c          |   12 +-
>  wcsmbs/isoc99_fwscanf.c                          |    2 +-
>  wcsmbs/isoc99_swscanf.c                          |   12 +-
>  wcsmbs/isoc99_vfwscanf.c                         |    2 +-
>  wcsmbs/isoc99_vswscanf.c                         |   16 +-
>  wcsmbs/isoc99_vwscanf.c                          |    2 +-
>  wcsmbs/isoc99_wscanf.c                           |    2 +-
>  34 files changed, 211 insertions(+), 115 deletions(-)
>  create mode 100644 stdio-common/iovfscanf.c
>  create mode 100644 stdio-common/iovfwscanf.c
>  create mode 100644 stdio-common/vfscanf.c
>  create mode 100644 stdio-common/vfwscanf.c
> 
> diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
> index e56ab8bd7d..ee6a99ec6a 100644
> --- a/libio/iovsscanf.c
> +++ b/libio/iovsscanf.c
> @@ -24,22 +24,14 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include "libioP.h"
>  #include "strfile.h"
>  
>  int
>  _IO_vsscanf (const char *string, const char *format, va_list args)
>  {
> -  int ret;
>    _IO_strfile sf;
> -#ifdef _IO_MTSAFE_IO
> -  sf._sbf._f._lock = NULL;
> -#endif
> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
> -  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
> -  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
> -  return ret;
> +  FILE *f = _IO_strfile_read (&sf, string);
> +  return __vfscanf_internal (f, format, args, 0);
>  }
>  ldbl_weak_alias (_IO_vsscanf, __vsscanf)
>  ldbl_weak_alias (_IO_vsscanf, vsscanf)

Ok.

> diff --git a/libio/iovswscanf.c b/libio/iovswscanf.c
> index 5bd1c88412..cb9cbe15cc 100644
> --- a/libio/iovswscanf.c
> +++ b/libio/iovswscanf.c
> @@ -24,24 +24,16 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include "libioP.h"
> -#include "strfile.h"
>  #include <wchar.h>
> +#include "strfile.h"
>  
>  int
>  __vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
>  {
> -  int ret;
>    _IO_strfile sf;
>    struct _IO_wide_data wd;
> -#ifdef _IO_MTSAFE_IO
> -  sf._sbf._f._lock = NULL;
> -#endif
> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
> -  _IO_fwide (&sf._sbf._f, 1);
> -  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
> -  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
> -  return ret;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, string);
> +  return __vfwscanf_internal (f, format, args, 0);
>  }
>  libc_hidden_def (__vswscanf)
>  ldbl_hidden_def (__vswscanf, vswscanf)

Ok.

> diff --git a/libio/libio.h b/libio/libio.h
> index 00f9169613..d4eba2df54 100644
> --- a/libio/libio.h
> +++ b/libio/libio.h
> @@ -321,7 +321,6 @@ libc_hidden_proto (_IO_padn)
>  libc_hidden_proto (_IO_putc)
>  libc_hidden_proto (_IO_sgetn)
>  libc_hidden_proto (_IO_vfprintf)
> -libc_hidden_proto (_IO_vfscanf)
>  
>  #ifdef _IO_MTSAFE_IO
>  # undef _IO_peekc

Ok.

> diff --git a/libio/libioP.h b/libio/libioP.h
> index 8afe7032e3..a471c90be8 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -704,6 +704,15 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)
>  
>  #endif /* _G_HAVE_MMAP */
>  
> +/* Flags for __vfscanf_internal and __vfwscanf_internal.  */
> +#define SCANF_LDBL_IS_DBL 0x0001
> +#define SCANF_ISOC99_A    0x0002
> +
> +extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
> +                               unsigned int flags);
> +extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
> +                                unsigned int flags);
> +
>  extern int _IO_vscanf (const char *, va_list) __THROW;
>  
>  #ifdef _IO_MTSAFE_IO

Ok.

> diff --git a/libio/strfile.h b/libio/strfile.h
> index 46ac81809a..715149f5bd 100644
> --- a/libio/strfile.h
> +++ b/libio/strfile.h
> @@ -24,7 +24,9 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <stdio.h>
> +#ifndef STRFILE_H_
> +#define STRFILE_H_
> +
>  #include "libioP.h"
>  
>  typedef void *(*_IO_alloc_type) (size_t);
> @@ -81,3 +83,32 @@ typedef struct
>  } _IO_wstrnfile;
>  
>  extern const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden;
> +
> +/* Initialize an _IO_strfile SF to read from narrow string STRING, and
> +   return the corresponding FILE object.  It is not necessary to fclose
> +   the FILE when it is no longer needed.  */
> +static inline FILE *
> +_IO_strfile_read (_IO_strfile *sf, const char *string)
> +{
> +  sf->_sbf._f._lock = NULL;
> +  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> +  _IO_JUMPS (&sf->_sbf) = &_IO_str_jumps;
> +  _IO_str_init_static_internal (sf, (char*)string, 0, NULL);
> +  return &sf->_sbf._f;
> +}

Should we add a note about _IO_MTSAFE_IO cleanup?

> +
> +/* Initialize an _IO_strfile SF and _IO_wide_data WD to read from wide
> +   string STRING, and return the corresponding FILE object.  It is not
> +   necessary to fclose the FILE when it is no longer needed.  */
> +static inline FILE *
> +_IO_strfile_readw (_IO_strfile *sf, struct _IO_wide_data *wd,
> +                   const wchar_t *string)
> +{
> +  sf->_sbf._f._lock = NULL;
> +  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, 0, wd, &_IO_wstr_jumps);
> +  _IO_fwide (&sf->_sbf._f, 1);
> +  _IO_wstr_init_static (&sf->_sbf._f, (wchar_t *)string, 0, NULL);
> +  return &sf->_sbf._f;
> +}
> +
> +#endif /* strfile.h.  */

Ok.

> diff --git a/libio/swscanf.c b/libio/swscanf.c
> index c8686bcbaf..90f721cc51 100644
> --- a/libio/swscanf.c
> +++ b/libio/swscanf.c
> @@ -15,20 +15,22 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <libioP.h>
>  #include <stdarg.h>
> -#include <wchar.h>
> +#include "strfile.h"
>  
>  /* Read formatted input from S, according to the format string FORMAT.  */
> -/* VARARGS2 */
> +
>  int
>  __swscanf (const wchar_t *s, const wchar_t *format, ...)
>  {
>    va_list arg;
>    int done;
> +  _IO_strfile sf;
> +  struct _IO_wide_data wd;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
>  
>    va_start (arg, format);
> -  done = __vswscanf (s, format, arg);
> +  done = __vfwscanf_internal (f, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/libio/vscanf.c b/libio/vscanf.c
> index 9c27122c27..a3e2dd43f2 100644
> --- a/libio/vscanf.c
> +++ b/libio/vscanf.c
> @@ -32,6 +32,6 @@
>  int
>  _IO_vscanf (const char *format, va_list args)
>  {
> -  return _IO_vfscanf (_IO_stdin, format, args, NULL);
> +  return __vfscanf_internal (_IO_stdin, format, args, 0);
>  }
>  ldbl_weak_alias (_IO_vscanf, vscanf)

Ok.

> diff --git a/libio/vwscanf.c b/libio/vwscanf.c
> index 0d5f558758..7af770c8c3 100644
> --- a/libio/vwscanf.c
> +++ b/libio/vwscanf.c
> @@ -30,6 +30,6 @@
>  int
>  __vwscanf (const wchar_t *format, va_list args)
>  {
> -  return _IO_vfwscanf (_IO_stdin, format, args, NULL);
> +  return __vfwscanf_internal (_IO_stdin, format, args, 0);
>  }
>  ldbl_strong_alias (__vwscanf, vwscanf)

Ok.

> diff --git a/libio/wscanf.c b/libio/wscanf.c
> index c8cdad0acd..fe27ff6fa6 100644
> --- a/libio/wscanf.c
> +++ b/libio/wscanf.c
> @@ -30,7 +30,7 @@ __wscanf (const wchar_t *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = _IO_vfwscanf (stdin, format, arg, NULL);
> +  done = __vfwscanf_internal (stdin, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index 9dfc115313..b7b1f01bdd 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -39,7 +39,8 @@ routines	:=							      \
>  	flockfile ftrylockfile funlockfile				      \
>  	isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
>  	isoc99_vsscanf							      \
> -	psiginfo gentempfd
> +	psiginfo gentempfd						      \
> +	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
>  
>  aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
>  

Ok.

> diff --git a/stdio-common/Versions b/stdio-common/Versions
> index 5016f69c20..7af44949f7 100644
> --- a/stdio-common/Versions
> +++ b/stdio-common/Versions
> @@ -57,6 +57,9 @@ libc {
>      psiginfo;
>      register_printf_modifier; register_printf_type; register_printf_specifier;
>    }
> +  GLIBC_2.28 {
> +    # SHLIB_COMPAT(GLIBC_2_0, GLIBC_2_28) used in iovfscanf.c etc
> +  }



>    GLIBC_PRIVATE {
>      # global variables
>      _itoa_lower_digits;
> diff --git a/stdio-common/iovfscanf.c b/stdio-common/iovfscanf.c
> new file mode 100644
> index 0000000000..fb347d60cb
> --- /dev/null
> +++ b/stdio-common/iovfscanf.c
> @@ -0,0 +1,34 @@
> +/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.

Missing one line description.

> +
> +   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 <libioP.h>
> +#include <shlib-compat.h>
> +
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
> +
> +int
> +attribute_compat_text_section
> +__IO_vfscanf (FILE *fp, const char *format, va_list ap, int *errp)
> +{
> +  int rv = __vfscanf_internal (fp, format, ap, 0);
> +  if (__glibc_unlikely (errp != 0))
> +    *errp = (rv == -1);
> +  return rv;
> +}
> +ldbl_compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
> +
> +#endif
> diff --git a/stdio-common/iovfwscanf.c b/stdio-common/iovfwscanf.c
> new file mode 100644
> index 0000000000..73936f68b2
> --- /dev/null
> +++ b/stdio-common/iovfwscanf.c
> @@ -0,0 +1,34 @@
> +/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
Missing one line description.

> +
> +   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 <libioP.h>
> +#include <shlib-compat.h>
> +
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
> +
> +int
> +attribute_compat_text_section
> +__IO_vfwscanf (FILE *fp, const wchar_t *format, va_list ap, int *errp)
> +{
> +  int rv = __vfwscanf_internal (fp, format, ap, 0);
> +  if (__glibc_unlikely (errp != 0))
> +    *errp = (rv == -1);
> +  return rv;
> +}
> +compat_symbol (libc, __IO_vfwscanf, _IO_vfwscanf, GLIBC_2_0);
> +
> +#endif
> diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
> index 9cdf85e679..4210d11f2b 100644
> --- a/stdio-common/isoc99_fscanf.c
> +++ b/stdio-common/isoc99_fscanf.c
> @@ -31,7 +31,7 @@ __isoc99_fscanf (FILE *stream, const char *format, ...)
>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = _IO_vfscanf (stream, format, arg, NULL);
> +  done = __vfscanf_internal (stream, format, arg, 0);
>    va_end (arg);
>  
>    _IO_release_lock (stream);

Ok.

> diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
> index bf7dbe86bb..64c873eed9 100644
> --- a/stdio-common/isoc99_scanf.c
> +++ b/stdio-common/isoc99_scanf.c
> @@ -34,7 +34,7 @@ __isoc99_scanf (const char *format, ...)
>    stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = _IO_vfscanf (stdin, format, arg, NULL);
> +  done = __vfscanf_internal (stdin, format, arg, 0);
>    va_end (arg);
>  
>  #ifdef _IO_MTSAFE_IO

Ok.

> diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
> index 56a60a2c05..95b94a68b5 100644
> --- a/stdio-common/isoc99_sscanf.c
> +++ b/stdio-common/isoc99_sscanf.c
> @@ -16,8 +16,7 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -#include <libioP.h>
> +#include <libio/strfile.h>
>  
>  /* Read formatted input from S, according to the format string FORMAT.  */
>  /* VARARGS2 */

I think you can cleanup this VARARGS2 comment as before.

> @@ -26,9 +25,12 @@ __isoc99_sscanf (const char *s, const char *format, ...)
>  {
>    va_list arg;
>    int done;
> +  _IO_strfile sf;
> +  FILE *f = _IO_strfile_read (&sf, s);
> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = __isoc99_vsscanf (s, format, arg);
> +  done = __vfscanf_internal (f, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
> index b80e05f8db..c96ca831ae 100644
> --- a/stdio-common/isoc99_vfscanf.c
> +++ b/stdio-common/isoc99_vfscanf.c
> @@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
>  
>    _IO_acquire_lock_clear_flags2 (stream);
>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = _IO_vfscanf (stream, format, args, NULL);
> +  done = __vfscanf_internal (stream, format, args, 0);
>    _IO_release_lock (stream);
>    return done;
>  }

Ok.

> diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
> index 0b747f85ba..72ae72ddee 100644
> --- a/stdio-common/isoc99_vscanf.c
> +++ b/stdio-common/isoc99_vscanf.c
> @@ -27,7 +27,7 @@ __isoc99_vscanf (const char *format, va_list args)
>  
>    _IO_acquire_lock_clear_flags2 (stdin);
>    stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = _IO_vfscanf (stdin, format, args, NULL);
> +  done = __vfscanf_internal (stdin, format, args, 0);
>    _IO_release_lock (stdin);
>    return done;
>  }

Ok.

> diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
> index ac85ef2d0d..02bc0f50e6 100644
> --- a/stdio-common/isoc99_vsscanf.c
> +++ b/stdio-common/isoc99_vsscanf.c
> @@ -24,23 +24,14 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <libioP.h>
> -#include <stdio.h>
> -#include "../libio/strfile.h"
> +#include <libio/strfile.h>
>  
>  int
>  __isoc99_vsscanf (const char *string, const char *format, va_list args)
>  {
> -  int ret;
>    _IO_strfile sf;
> -#ifdef _IO_MTSAFE_IO
> -  sf._sbf._f._lock = NULL;
> -#endif
> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
> -  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
> -  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
> -  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
> -  return ret;
> +  FILE *f = _IO_strfile_read (&sf, string);
> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
> +  return __vfscanf_internal (f, format, args, 0);
>  }
>  libc_hidden_def (__isoc99_vsscanf)

Ok.

> diff --git a/stdio-common/scanf.c b/stdio-common/scanf.c
> index e61b5f1ad3..de38d70353 100644
> --- a/stdio-common/scanf.c
> +++ b/stdio-common/scanf.c
> @@ -30,7 +30,7 @@ __scanf (const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = _IO_vfscanf (stdin, format, arg, NULL);
> +  done = __vfscanf_internal (stdin, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/sscanf.c b/stdio-common/sscanf.c
> index 88cd641798..e25e9c27a5 100644
> --- a/stdio-common/sscanf.c
> +++ b/stdio-common/sscanf.c
> @@ -16,26 +16,24 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -#include <libioP.h>
> -#define __vsscanf(s, f, a) _IO_vsscanf (s, f, a)
> +#include <libio/strfile.h>
>  
>  /* Read formatted input from S, according to the format string FORMAT.  */
> -/* VARARGS2 */
> +
>  int
>  __sscanf (const char *s, const char *format, ...)
>  {
>    va_list arg;
>    int done;
> +  _IO_strfile sf;
> +  FILE *f = _IO_strfile_read (&sf, s);
>  
>    va_start (arg, format);
> -  done = __vsscanf (s, format, arg);
> +  done = __vfscanf_internal (f, format, arg, 0);
>    va_end (arg);
>  
>    return done;
>  }
>  ldbl_hidden_def (__sscanf, sscanf)
>  ldbl_strong_alias (__sscanf, sscanf)
> -#undef _IO_sscanf
> -/* This is for libg++.  */
>  ldbl_strong_alias (__sscanf, _IO_sscanf)

Ok.

> diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf-internal.c
> similarity index 98%
> rename from stdio-common/vfscanf.c
> rename to stdio-common/vfscanf-internal.c
> index 3263268c7e..93b07ad4bc 100644
> --- a/stdio-common/vfscanf.c
> +++ b/stdio-common/vfscanf-internal.c
> @@ -132,16 +132,13 @@
>  #include "printf-parse.h" /* Use read_int.  */
>  
>  #define encode_error() do {						      \
> -			  errval = 4;					      \
>  			  __set_errno (EILSEQ);				      \
>  			  goto errout;					      \
>  			} while (0)
>  #define conv_error()	do {						      \
> -			  errval = 2;					      \
>  			  goto errout;					      \
>  			} while (0)
>  #define input_error()	do {						      \
> -			  errval = 1;					      \
>  			  if (done == 0) done = EOF;			      \
>  			  goto errout;					      \
>  			} while (0)
> @@ -267,12 +264,12 @@ char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
>     Return the number of assignments made, or -1 for an input error.  */
>  #ifdef COMPILE_WSCANF
>  int
> -_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
> -	      int *errp)
> +__vfwscanf_internal (FILE *s, const wchar_t *format, va_list argptr,
> +                     unsigned int mode_flags)
>  #else
>  int
> -_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> -		      int *errp)
> +__vfscanf_internal (FILE *s, const char *format, va_list argptr,
> +                    unsigned int mode_flags)
>  #endif
>  {
>    va_list arg;
> @@ -283,7 +280,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>    WINT_T c = 0;	/* Last char read.  */
>    int width;		/* Maximum field width.  */
>    int flags;		/* Modifiers for current format element.  */
> -  int errval = 0;
>  #ifndef COMPILE_WSCANF
>    locale_t loc = _NL_CURRENT_LOCALE;
>    struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
> @@ -335,6 +331,14 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>    struct char_buffer charbuf;
>    scratch_buffer_init (&charbuf.scratch);
>  
> +#define LDBL_DISTINCT (__glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
> +#define USE_ISOC99_A  (__glibc_likely (mode_flags & SCANF_ISOC99_A))
> +  /* Temporarily honor the environmental mode bits.  */
> +  if (__ldbl_is_dbl)
> +    mode_flags |= SCANF_LDBL_IS_DBL;
> +  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
> +    mode_flags |= SCANF_ISOC99_A;
> +
>  #ifdef __va_copy
>    __va_copy (arg, argptr);
>  #else
> @@ -566,7 +570,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>  	    }
>  	  /* In __isoc99_*scanf %as, %aS and %a[ extension is not
>  	     supported at all.  */
> -	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
> +	  if (USE_ISOC99_A)
>  	    {
>  	      --f;
>  	      break;
> @@ -2422,7 +2426,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>  	      done = EOF;
>  	      goto errout;
>  	    }
> -	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
> +	  if ((flags & LONGDBL) && LDBL_DISTINCT)
>  	    {
>  	      long double d = __strtold_internal
>  		(char_buffer_start (&charbuf), &tw, flags & GROUP);
> @@ -3017,8 +3021,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>    UNLOCK_STREAM (s);
>  
>    scratch_buffer_free (&charbuf.scratch);
> -  if (errp != NULL)
> -    *errp |= errval;
>  
>    if (__glibc_unlikely (done == EOF))
>      {
> @@ -3044,23 +3046,3 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>      }
>    return done;
>  }
> -
> -#ifdef COMPILE_WSCANF
> -int
> -__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
> -{
> -  return _IO_vfwscanf (s, format, argptr, NULL);
> -}
> -ldbl_weak_alias (__vfwscanf, vfwscanf)
> -#else
> -int
> -___vfscanf (FILE *s, const char *format, va_list argptr)
> -{
> -  return _IO_vfscanf_internal (s, format, argptr, NULL);
> -}
> -ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
> -ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
> -ldbl_strong_alias (___vfscanf, __vfscanf)
> -ldbl_hidden_def (___vfscanf, __vfscanf)
> -ldbl_weak_alias (___vfscanf, vfscanf)
> -#endif

Ok.

> diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
> index 0000000000..5eedca8340 100644
> --- /dev/null	2018-02-21 11:21:31.435874074 -0500
> +++ b/stdio-common/vfscanf.c	2018-03-07 08:44:37.578545222 -0500
> @@ -0,0 +1,27 @@
> +/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.

Missing one line description.

> +
> +   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 <libioP.h>
> +
> +int
> +___vfscanf (FILE *s, const char *format, va_list argptr)
> +{
> +  return __vfscanf_internal (s, format, argptr, 0);
> +}
> +ldbl_strong_alias (___vfscanf, __vfscanf)
> +ldbl_hidden_def (___vfscanf, __vfscanf)
> +ldbl_weak_alias (___vfscanf, vfscanf)

Ok.

> diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf-internal.c
> similarity index 50%
> rename from stdio-common/vfscanf.c
> rename to stdio-common/vfscanf-internal.c
> index 26b1a66608..26c89270b7 100644
> --- a/stdio-common/vfwscanf.c
> +++ b/stdio-common/vfwscanf-internal.c
> @@ -1,2 +1,2 @@
>  #define COMPILE_WSCANF	1
> -#include "vfscanf.c"
> +#include "vfscanf-internal.c"

Ok.

> diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
> new file mode 100644
> index 0000000000..0554b7eae1
> --- a/stdio-common/vfwscanf.c
> +++ b/stdio-common/vfwscanf.c
> @@ -0,0 +1,25 @@
> +/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
Missing one line description.

> +
> +   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 <libioP.h>
> +
> +int
> +__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
> +{
> +  return __vfwscanf_internal (s, format, argptr, 0);
> +}
> +ldbl_weak_alias (__vfwscanf, vfwscanf)

Ok.

> diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
> index 8a5d8ba107..92f670dff7 100644
> --- a/sysdeps/generic/math_ldbl_opt.h
> +++ b/sysdeps/generic/math_ldbl_opt.h
> @@ -6,9 +6,13 @@
>     for platforms where compatibility symbols are required for a previous
>     ABI that defined long double functions as aliases for the double code.  */
>  
> +#include <shlib-compat.h>
> +
>  #define LONG_DOUBLE_COMPAT(lib, introduced) 0
>  #define long_double_symbol(lib, local, symbol)
>  #define ldbl_hidden_def(local, name) libc_hidden_def (name)
>  #define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
>  #define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
> +#define ldbl_compat_symbol(lib, local, symbol, version) \
> +  compat_symbol (lib, local, symbol, version)
>  #define __ldbl_is_dbl 0

Isn't the idea that if long double being a different type than double the compat
symbols are not really required? I think this should be just an empty macro.

> diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> index af861c11ea..ee70d085fd 100644
> --- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> +++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> @@ -20,10 +20,14 @@
>    long_double_symbol (libc, __GL_##name##_##aliasname, aliasname);
>  # define long_double_symbol_1(lib, local, symbol, version) \
>    versioned_symbol (lib, local, symbol, version)
> +# define ldbl_compat_symbol(lib, local, symbol, version) \
> +  compat_symbol (lib, local, symbol, LONG_DOUBLE_COMPAT_VERSION)
>  #else
>  # define ldbl_hidden_def(local, name) libc_hidden_def (name)
>  # define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
>  # define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
> +# define ldbl_compat_symbol(lib, local, symbol, version) \
> +  compat_symbol (lib, local, symbol, version)
>  # ifndef __ASSEMBLER__
>  /* Note that weak_alias cannot be used - it is defined to nothing
>     in most of the C files.  */

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 7d19eaba8d..9ac88deb74 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -329,16 +329,20 @@ __nldbl_wprintf (const wchar_t *fmt, ...)
>    return done;
>  }
>  
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
>  int
>  attribute_compat_text_section
>  __nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vfscanf (s, fmt, ap, errp);
> +  res = __vfscanf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
> +  if (__glibc_unlikely (errp != 0))
> +    *errp = (res == -1);
>    return res;
>  }
> +#endif
>  
>  int
>  attribute_compat_text_section
> @@ -346,7 +350,7 @@ __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vfscanf (s, fmt, ap, NULL);
> +  res = __vfscanf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -422,7 +426,7 @@ __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vfwscanf (s, fmt, ap, NULL);
> +  res = __vfwscanf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -1026,7 +1030,9 @@ compat_symbol (libc, __nldbl_vdprintf, vdprintf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_vsnprintf, vsnprintf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_vsprintf, vsprintf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl__IO_sscanf, _IO_sscanf, GLIBC_2_0);
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
>  compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
> +#endif
>  compat_symbol (libc, __nldbl___vfscanf, __vfscanf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl___vsscanf, __vsscanf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_fscanf, fscanf, GLIBC_2_0);

I am not sure that nesting SHLIB_COMPAT is correct way logically and stylisc here:
the compat symbol will be create only for ABI which initial version of GLIBC_2_0
(which might not be an issue with current ABIs that requires ldbl to dbl compat
symbol).

Should we just add it on the end of the list?

> diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
> index 0c6a2c47ac..00b07dd48e 100644
> --- a/wcsmbs/isoc99_fwscanf.c
> +++ b/wcsmbs/isoc99_fwscanf.c
> @@ -32,7 +32,7 @@ __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = _IO_vfwscanf (stream, format, arg, NULL);
> +  done = __vfwscanf_internal (stream, format, arg, 0);
>    va_end (arg);
>  
>    _IO_release_lock (stream);

Ok.

> diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
> index ff523db706..40401d0aa1 100644
> --- a/wcsmbs/isoc99_swscanf.c
> +++ b/wcsmbs/isoc99_swscanf.c
> @@ -16,20 +16,22 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -#include <libioP.h>
> -#include <wchar.h>
> +#include <libio/strfile.h>
>  
>  /* Read formatted input from S, according to the format string FORMAT.  */
> -/* VARARGS2 */
> +
>  int
>  __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
>  {
>    va_list arg;
>    int done;
> +  _IO_strfile sf;
> +  struct _IO_wide_data wd;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = __isoc99_vswscanf (s, format, arg);
> +  done = __vfwscanf_internal (f, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
> index 7beb45b4d3..f70c6b596d 100644
> --- a/wcsmbs/isoc99_vfwscanf.c
> +++ b/wcsmbs/isoc99_vfwscanf.c
> @@ -28,7 +28,7 @@ __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
>  
>    _IO_acquire_lock_clear_flags2 (stream);
>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = _IO_vfwscanf (stream, format, args, NULL);
> +  done = __vfwscanf_internal (stream, format, args, 0);
>    _IO_release_lock (stream);
>    return done;
>  }

Ok.

> diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
> index 130769154d..b91eb651a3 100644
> --- a/wcsmbs/isoc99_vswscanf.c
> +++ b/wcsmbs/isoc99_vswscanf.c
> @@ -24,24 +24,16 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <libioP.h>
>  #include <wchar.h>
> -#include "../libio/strfile.h"
> +#include <libio/strfile.h>
>  
>  int
>  __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
>  {
> -  int ret;
>    _IO_strfile sf;
>    struct _IO_wide_data wd;
> -#ifdef _IO_MTSAFE_IO
> -  sf._sbf._f._lock = NULL;
> -#endif
> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
> -  _IO_fwide (&sf._sbf._f, 1);
> -  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
> -  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
> -  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
> -  return ret;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, string);
> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
> +  return __vfwscanf_internal (f, format, args, 0);
>  }
>  libc_hidden_def (__isoc99_vswscanf)

Ok.

> diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
> index 049521b964..eb22c8acae 100644
> --- a/wcsmbs/isoc99_vwscanf.c
> +++ b/wcsmbs/isoc99_vwscanf.c
> @@ -28,7 +28,7 @@ __isoc99_vwscanf (const wchar_t *format, va_list args)
>  
>    _IO_acquire_lock_clear_flags2 (stdin);
>    stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = _IO_vfwscanf (stdin, format, args, NULL);
> +  done = __vfwscanf_internal (stdin, format, args, 0);
>    _IO_release_lock (stdin);
>    return done;
>  }

Ok.

> diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
> index abfbd50c11..59f80d78fb 100644
> --- a/wcsmbs/isoc99_wscanf.c
> +++ b/wcsmbs/isoc99_wscanf.c
> @@ -33,7 +33,7 @@ __isoc99_wscanf (const wchar_t *format, ...)
>    stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = _IO_vfwscanf (stdin, format, arg, NULL);
> +  done = __vfwscanf_internal (stdin, format, arg, 0);
>    va_end (arg);
>  
>    _IO_release_lock (stdin);
> 

Ok.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-03-13 11:59   ` Florian Weimer
@ 2018-03-13 12:39     ` Zack Weinberg
  2018-03-13 12:43       ` Florian Weimer
  0 siblings, 1 reply; 37+ messages in thread
From: Zack Weinberg @ 2018-03-13 12:39 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

On Tue, Mar 13, 2018 at 7:59 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 03/07/2018 08:32 PM, Zack Weinberg wrote:
>
>> +/* __vsyslog_internal uses the same mode_flags bits as
>> +   __v*printf_internal; see libio/libioP.h.  */
>> +extern void __vsyslog_internal (int pri, const char *fmt, __gnuc_va_list
>> ap,
>> +                                unsigned int mode_flags)
>> +     __attribute__ ((__format__ (__printf__, 2, 0)));
>
>
> I'm surprised that this doesn't need attribute_hidden or libc_hidden_proto
> to avoid new PLT calls.

That's only needed for functions that will be called _both_ from
inside and outside glibc.  This function is only ever called from
inside glibc, so it doesn't appear in any Versions files and it's
hidden by default.

zw

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-03-13 12:39     ` Zack Weinberg
@ 2018-03-13 12:43       ` Florian Weimer
  2018-03-13 13:37         ` Zack Weinberg
  0 siblings, 1 reply; 37+ messages in thread
From: Florian Weimer @ 2018-03-13 12:43 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: GNU C Library

On 03/13/2018 01:39 PM, Zack Weinberg wrote:
> On Tue, Mar 13, 2018 at 7:59 AM, Florian Weimer <fweimer@redhat.com> wrote:
>> On 03/07/2018 08:32 PM, Zack Weinberg wrote:
>>
>>> +/* __vsyslog_internal uses the same mode_flags bits as
>>> +   __v*printf_internal; see libio/libioP.h.  */
>>> +extern void __vsyslog_internal (int pri, const char *fmt, __gnuc_va_list
>>> ap,
>>> +                                unsigned int mode_flags)
>>> +     __attribute__ ((__format__ (__printf__, 2, 0)));
>>
>>
>> I'm surprised that this doesn't need attribute_hidden or libc_hidden_proto
>> to avoid new PLT calls.
> 
> That's only needed for functions that will be called _both_ from
> inside and outside glibc.  This function is only ever called from
> inside glibc, so it doesn't appear in any Versions files and it's
> hidden by default.

Some architectures will still use indirect calls without 
attribute_hidden, so please add it.  The existing tests do not catch 
this reliably unfortunately.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-03-13 12:43       ` Florian Weimer
@ 2018-03-13 13:37         ` Zack Weinberg
  2018-03-13 13:50           ` Florian Weimer
  0 siblings, 1 reply; 37+ messages in thread
From: Zack Weinberg @ 2018-03-13 13:37 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

On Tue, Mar 13, 2018 at 8:43 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 03/13/2018 01:39 PM, Zack Weinberg wrote:
>>
>> On Tue, Mar 13, 2018 at 7:59 AM, Florian Weimer <fweimer@redhat.com>
>> wrote:
>>>
>>> On 03/07/2018 08:32 PM, Zack Weinberg wrote:
>>>
>>>> +/* __vsyslog_internal uses the same mode_flags bits as
>>>> +   __v*printf_internal; see libio/libioP.h.  */
>>>> +extern void __vsyslog_internal (int pri, const char *fmt,
>>>> __gnuc_va_list
>>>> ap,
>>>> +                                unsigned int mode_flags)
>>>> +     __attribute__ ((__format__ (__printf__, 2, 0)));
>>>
>>>
>>>
>>> I'm surprised that this doesn't need attribute_hidden or
>>> libc_hidden_proto
>>> to avoid new PLT calls.
>>
>>
>> That's only needed for functions that will be called _both_ from
>> inside and outside glibc.  This function is only ever called from
>> inside glibc, so it doesn't appear in any Versions files and it's
>> hidden by default.
>
>
> Some architectures will still use indirect calls without attribute_hidden,
> so please add it.  The existing tests do not catch this reliably
> unfortunately.

Can you be more specific?  This will affect all of the other new
__*_internal functions added in this patchset, so I need to know how
to be sure I got it right.  Also, this seems like something we should
find a way to automate if at all possible.

zw

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-03-13 13:37         ` Zack Weinberg
@ 2018-03-13 13:50           ` Florian Weimer
  2018-03-13 14:11             ` Zack Weinberg
  0 siblings, 1 reply; 37+ messages in thread
From: Florian Weimer @ 2018-03-13 13:50 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: GNU C Library

On 03/13/2018 02:37 PM, Zack Weinberg wrote:
> On Tue, Mar 13, 2018 at 8:43 AM, Florian Weimer <fweimer@redhat.com> wrote:
>> On 03/13/2018 01:39 PM, Zack Weinberg wrote:
>>>
>>> On Tue, Mar 13, 2018 at 7:59 AM, Florian Weimer <fweimer@redhat.com>
>>> wrote:
>>>>
>>>> On 03/07/2018 08:32 PM, Zack Weinberg wrote:
>>>>
>>>>> +/* __vsyslog_internal uses the same mode_flags bits as
>>>>> +   __v*printf_internal; see libio/libioP.h.  */
>>>>> +extern void __vsyslog_internal (int pri, const char *fmt,
>>>>> __gnuc_va_list
>>>>> ap,
>>>>> +                                unsigned int mode_flags)
>>>>> +     __attribute__ ((__format__ (__printf__, 2, 0)));
>>>>
>>>>
>>>>
>>>> I'm surprised that this doesn't need attribute_hidden or
>>>> libc_hidden_proto
>>>> to avoid new PLT calls.
>>>
>>>
>>> That's only needed for functions that will be called _both_ from
>>> inside and outside glibc.  This function is only ever called from
>>> inside glibc, so it doesn't appear in any Versions files and it's
>>> hidden by default.
>>
>>
>> Some architectures will still use indirect calls without attribute_hidden,
>> so please add it.  The existing tests do not catch this reliably
>> unfortunately.
> 
> Can you be more specific?  This will affect all of the other new
> __*_internal functions added in this patchset, so I need to know how
> to be sure I got it right.  Also, this seems like something we should
> find a way to automate if at all possible.

Consider this code:

$ cat call.c
int external (void) ATTR;

int
call (void)
{
   return external () + 1;
}

With default visibility, GCC 7 produces:

$ ppc64-linux-gnu-gcc -m32 -fPIC -c -O2 -DATTR= call.c && 
ppc64-linux-gnu-objdump -d --reloc call.o

call.o:     file format elf32-powerpc


Disassembly of section .text:

00000000 <call>:
    0:	94 21 ff e0 	stwu    r1,-32(r1)
    4:	7c 08 02 a6 	mflr    r0
    8:	42 9f 00 05 	bcl     20,4*cr7+so,c <call+0xc>
    c:	93 c1 00 18 	stw     r30,24(r1)
   10:	7f c8 02 a6 	mflr    r30
   14:	90 01 00 24 	stw     r0,36(r1)
   18:	3f de 00 00 	addis   r30,r30,0
			1a: R_PPC_REL16_HA	.got2+0x800e
   1c:	3b de 00 00 	addi    r30,r30,0
			1e: R_PPC_REL16_LO	.got2+0x8012
   20:	48 00 00 01 	bl      20 <call+0x20>
			20: R_PPC_PLTREL24	external+0x8000
   24:	80 01 00 24 	lwz     r0,36(r1)
   28:	83 c1 00 18 	lwz     r30,24(r1)
   2c:	38 21 00 20 	addi    r1,r1,32
   30:	38 63 00 01 	addi    r3,r3,1
   34:	7c 08 03 a6 	mtlr    r0
   38:	4e 80 00 20 	blr

With hidden visibility, we get instead:

$ ppc64-linux-gnu-gcc -m32 -fPIC -c -O2 -DATTR='__attribute ((visibility 
("hidden")))' call.c && ppc64-linux-gnu-objdump -d --reloc call.o

call.o:     file format elf32-powerpc


Disassembly of section .text:

00000000 <call>:
    0:	94 21 ff e0 	stwu    r1,-32(r1)
    4:	7c 08 02 a6 	mflr    r0
    8:	93 c1 00 18 	stw     r30,24(r1)
    c:	90 01 00 24 	stw     r0,36(r1)
   10:	48 00 00 01 	bl      10 <call+0x10>
			10: R_PPC_LOCAL24PC	external
   14:	80 01 00 24 	lwz     r0,36(r1)
   18:	83 c1 00 18 	lwz     r30,24(r1)
   1c:	38 21 00 20 	addi    r1,r1,32
   20:	38 63 00 01 	addi    r3,r3,1
   24:	7c 08 03 a6 	mtlr    r0
   28:	4e 80 00 20 	blr

The linker may have some optimization to eliminate the PLT indirection 
(blinding the localplt test), but it cannot get rid of the other 
unnecessary instructions.

Does this example help?

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-03-13 13:50           ` Florian Weimer
@ 2018-03-13 14:11             ` Zack Weinberg
  2018-03-13 14:13               ` Florian Weimer
  0 siblings, 1 reply; 37+ messages in thread
From: Zack Weinberg @ 2018-03-13 14:11 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

On Tue, Mar 13, 2018 at 9:50 AM, Florian Weimer <fweimer@redhat.com> wrote:
>>> Some architectures will still use indirect calls without
>>> attribute_hidden,
>>> so please add it.  The existing tests do not catch this reliably
>>> unfortunately.
>>
>>
>> Can you be more specific?  This will affect all of the other new
>> __*_internal functions added in this patchset, so I need to know how
>> to be sure I got it right.  Also, this seems like something we should
>> find a way to automate if at all possible.
...
> The linker may have some optimization to eliminate the PLT indirection
> (blinding the localplt test), but it cannot get rid of the other unnecessary
> instructions.
>
> Does this example help?

I believe I understand the problem now, thank you.  And we can't/don't
use -fvisibility=hidden because then we would have to annotate all of
the _public_ symbols with visibility default, yes?

zw

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-03-13 14:11             ` Zack Weinberg
@ 2018-03-13 14:13               ` Florian Weimer
  0 siblings, 0 replies; 37+ messages in thread
From: Florian Weimer @ 2018-03-13 14:13 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: GNU C Library

On 03/13/2018 03:11 PM, Zack Weinberg wrote:
> I believe I understand the problem now, thank you.  And we can't/don't
> use -fvisibility=hidden because then we would have to annotate all of
> the_public_  symbols with visibility default, yes?

That, and on some architectures, it is impossible to call IFUNCs with 
hidden visibility declared to the compiler.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 4/9] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-07 19:32 ` [PATCH 4/9] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl Zack Weinberg
@ 2018-03-14 12:22   ` Florian Weimer
  2018-03-26 15:36   ` Gabriel F. T. Gomes
  1 sibling, 0 replies; 37+ messages in thread
From: Florian Weimer @ 2018-03-14 12:22 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha

On 03/07/2018 08:32 PM, Zack Weinberg wrote:
> Change the callers of __vfscanf_internal and __vfwscanf_internal that
> want to treat 'long double' as another name for 'double' (all of which
> happen to be in sysdeps/ieee754/ldbl-opt/nldbl-compat.c) to communicate
> this via the new flags argument, instead of the per-thread variable
> __no_long_double and its __ldbl_is_dbl wrapper macro.

Patch looks okay to me.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 0/9] Use more flags parameters instead of global bits in stdio
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (9 preceding siblings ...)
  2018-03-12 15:29 ` [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
@ 2018-03-26 15:16 ` Gabriel F. T. Gomes
  2018-03-26 15:47   ` Zack Weinberg
  2018-06-27 15:50 ` Florian Weimer
  11 siblings, 1 reply; 37+ messages in thread
From: Gabriel F. T. Gomes @ 2018-03-26 15:16 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha

On Wed, 07 Mar 2018, Zack Weinberg wrote:

>I got stuck on the patch to use C99-compliant scanf in _GNU_SOURCE
>mode because the interaction with ldbl-is-dbl was too confusing.  The
>reason it's too confusing is that C99 compliance in scanf, ldbl-is-dbl
>mode in scanf, printf, and strfmon, and fortify mode in printf are
>handled with mode bits on the FILE and thread-global flags that must
>be set and reset at just the right times.  Correct behavior is
>invariably to set and then reset around just one call to a lower-level
>function, and there's a better way to do that: flags parameters.
>
>This patch series implements _internal variants of scanf, printf,
>strfmon, and syslog that take flag parameters that control C99
>compliance, ldbl-is-dbl mode, and fortification.

Thanks for doing this.  It looks a lot less confusing now.

>I regret the length
>and the messiness, and it might make sense to squash it on landing.

Although I haven't tested each patch in the patch set individually, they
look self-contained and I don't see a compelling reason to squash them.

I did, however, test a branch with all the patches applied on powerpc64 and
powerp64le.  The tests passed OK.

>I have manually hacked the patches that introduce vfprintf-internal.c
>and vfscanf-internal.c so the diffs are actually readable -- git doesn't
>handle "rename this file and then create a new file in its place" very
>well.

Thanks for pointing this out, it made it easier to know what to do in
order to apply them.


Overall, the patch set looks good to me.  I have some comments and
questions for each individual patch, which I'm sending right away.
(patches 1 through 5, that is. I didn't have time to write about patches
6 through 8).

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 1/9] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-07 19:32 ` [PATCH 1/9] Use STRFMON_LDBL_IS_DBL " Zack Weinberg
  2018-03-12 20:36   ` Adhemerval Zanella
@ 2018-03-26 15:17   ` Gabriel F. T. Gomes
  2018-03-26 15:40     ` Zack Weinberg
  1 sibling, 1 reply; 37+ messages in thread
From: Gabriel F. T. Gomes @ 2018-03-26 15:17 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha

On Wed, 07 Mar 2018, Zack Weinberg wrote:

>	* include/monetary.h (STRFMON_LDBL_IS_DBL): New constant.
>	(__vstrfmon_l): Rename to __vstrfmon_l_internal and add flags
>	argument.

Maybe mention that attribute_hidden was not required, thus removed?

Is this another instance of the 'only needed when called both from inside
and outside of glibc' argument (as pointed out in a previous message [1])?

[1] https://sourceware.org/ml/libc-alpha/2018-03/msg00311.html

>-extern ssize_t __vstrfmon_l (char *s, size_t maxsize, locale_t loc,
>-			     const char *format, va_list ap)
>-     attribute_hidden;

Same comment as above, i.e.: is this another instance of the 'only needed
when called both from inside and outside of glibc' argument?

>+extern ssize_t __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
>+                                      const char *format, va_list ap,
>+                                      unsigned int flags);
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Spaces that could be converted to tabs.


>-  ssize_t res = __vstrfmon_l (s, maxsize, _NL_CURRENT_LOCALE, format, ap);
>+  ssize_t res = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE,
>+                                       format, ap, 0);
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Likewise.

>-__vstrfmon_l (char *s, size_t maxsize, locale_t loc, const char *format,
>-	      va_list ap)
>+__vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
>+                       const char *format, va_list ap, unsigned int flags)
  ~~~~~~~~~~~~~~~~
Likewise.

>-  res = __nldbl___vstrfmon (s, maxsize, format, ap);
>+  ret = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE, format, ap,
>+                               STRFMON_LDBL_IS_DBL);
  ~~~~~~~~~~~~~~~~~~~~~~~~
Likewise.

>-  res = __nldbl___vstrfmon_l (s, maxsize, loc, format, ap);
>+  ret = __vstrfmon_l_internal (s, maxsize, loc, format, ap,
>+                               STRFMON_LDBL_IS_DBL);
  ~~~~~~~~~~~~~~~~~~~~~~~~
Likewise.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-03-07 19:32 ` [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments Zack Weinberg
  2018-03-13 12:35   ` Adhemerval Zanella
@ 2018-03-26 15:28   ` Gabriel F. T. Gomes
  2018-06-29 14:12     ` Florian Weimer
  2018-06-29 14:24   ` Florian Weimer
  2018-06-29 14:29   ` Florian Weimer
  3 siblings, 1 reply; 37+ messages in thread
From: Gabriel F. T. Gomes @ 2018-03-26 15:28 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha

On Wed, 07 Mar 2018, Zack Weinberg wrote:

>(It was necessary to introduce ldbl_compat_symbol for _IO_vfscanf.
>Please check that part of the patch very carefully, I am still not
>confident I understand all of the details of ldbl-opt.)

It looks good on powerpc64...  Oldest symbol (where long double had the
same format as double) is still there as a compat symbol with version
GLIBC_2.3...  The newer symbol, is a bit different, in the sense that it
is now a compat symbol (it was a default symbol previously).

Here's what readelf has to tell us:

Before the patch set:
  1355: 00000000001eea70   124 FUNC    GLOBAL DEFAULT   27 _IO_vfscanf@GLIBC_2.3
  1356: 00000000001f0a98 23552 FUNC    GLOBAL DEFAULT   27 _IO_vfscanf@@GLIBC_2.4

After the patch set:
  1355: 00000000001f0bd0   136 FUNC    GLOBAL DEFAULT   27 _IO_vfscanf@GLIBC_2.4
  1356: 00000000001ee968   136 FUNC    GLOBAL DEFAULT   27 _IO_vfscanf@GLIBC_2.3

For the static library, I think that Adhemerval is right (see comment below).

>	* libio/libioP.h (SCANF_LDBL_IS_DBL, SCANF_ISOC99_A): New constants.
>	(__vfscanf_internal, __vfwscanf_internal): New function prototypes.
>        * libio/libio.h: Remove libc_hidden_proto for _IO_vfscanf.
 ~~~~~~~~
Spaces instead of tabs.

>	* libio/strfile.h: Add multiple inclusion guard.

Perhaps mention the removal of stdio.h inclusion?

>        * stdio-common/Versions: Mention GLIBC_2.28, so that
>        it can be used in SHLIB_COMPAT expressions.
 ~~~~~~~~
Spaces instead of tabs.

>+extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
>+                               unsigned int flags);
  ~~~~~~~~~~~~~~~~~~~~~~~~
>+extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
>+                                unsigned int flags);
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Spaces instead of tabs.

>+/* Initialize an _IO_strfile SF and _IO_wide_data WD to read from wide
>+   string STRING, and return the corresponding FILE object.  It is not
>+   necessary to fclose the FILE when it is no longer needed.  */
>+static inline FILE *
>+_IO_strfile_readw (_IO_strfile *sf, struct _IO_wide_data *wd,
>+                   const wchar_t *string)
  ~~~~~~~~~~~~~~~~
Spaces instead of tabs.

>--- /dev/null
>+++ b/stdio-common/iovfscanf.c
>@@ -0,0 +1,34 @@
>+/* Copyright (C) 1991-2018 Free Software Foundation, Inc.

Should this (and other new files) be copyright 2018, since they're new?

>--- a/stdio-common/vfscanf.c
>+++ b/stdio-common/vfscanf-internal.c
>-_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
>-	      int *errp)
>+__vfwscanf_internal (FILE *s, const wchar_t *format, va_list argptr,
>+                     unsigned int mode_flags)
  ~~~~~~~~~~~~~~~~
Spaces instead of tabs.

>-_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>-		      int *errp)
>+__vfscanf_internal (FILE *s, const char *format, va_list argptr,
>+                    unsigned int mode_flags)
  ~~~~~~~~~~~~~~~~
Spaces instead of tabs.

>--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
>+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
>@@ -20,10 +20,14 @@
>   long_double_symbol (libc, __GL_##name##_##aliasname, aliasname);
> # define long_double_symbol_1(lib, local, symbol, version) \
>   versioned_symbol (lib, local, symbol, version)
>+# define ldbl_compat_symbol(lib, local, symbol, version) \
>+  compat_symbol (lib, local, symbol, LONG_DOUBLE_COMPAT_VERSION)
> #else
> # define ldbl_hidden_def(local, name) libc_hidden_def (name)
> # define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
> # define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
>+# define ldbl_compat_symbol(lib, local, symbol, version) \
>+  compat_symbol (lib, local, symbol, version)

I believe that Adhemerval's comment is correct and ldbl_compat_symbol
should translate to nothing when building static libraries.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 3/9] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD.
  2018-03-07 19:32 ` [PATCH 3/9] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD Zack Weinberg
@ 2018-03-26 15:35   ` Gabriel F. T. Gomes
  0 siblings, 0 replies; 37+ messages in thread
From: Gabriel F. T. Gomes @ 2018-03-26 15:35 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha

On Wed, 07 Mar 2018, Zack Weinberg wrote:

>Change the callers of __vfscanf_internal and __vfwscanf_internal that
>want C99-compliant behavior to communicate this via the new flags
>argument, rather than setting bits on the FILE object.  This also
>means these functions do not need to do their own locking.

Looks good to me.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 4/9] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-07 19:32 ` [PATCH 4/9] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl Zack Weinberg
  2018-03-14 12:22   ` Florian Weimer
@ 2018-03-26 15:36   ` Gabriel F. T. Gomes
  1 sibling, 0 replies; 37+ messages in thread
From: Gabriel F. T. Gomes @ 2018-03-26 15:36 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha

On Wed, 07 Mar 2018, Zack Weinberg wrote:

>Change the callers of __vfscanf_internal and __vfwscanf_internal that
>want to treat 'long double' as another name for 'double' (all of which
>happen to be in sysdeps/ieee754/ldbl-opt/nldbl-compat.c) to communicate
>this via the new flags argument, instead of the per-thread variable
>__no_long_double and its __ldbl_is_dbl wrapper macro.

The patch looks good to me

>	(__nldbl___isoc99_vfscanf, __nldbl___isoc99_sscanf)
>	(__nldbl___isoc99_vsscanf, __nldbl___isoc99_vscanf)
>	(__nldbl___isoc99_fscanf, __nldbl___isoc99_scanf)
>	(__nldbl___isoc99_vfwscanf, __nldbl___isoc99_swscanf)
>	(__nldbl___isoc99_vswscanf, __nldbl___isoc99_vwscanf)
>	(__nldbl___isoc99_fwscanf, __nldbl___isoc99_wscanf):
>	Call __vfscanf_internal / __vfwscanf_internal directly, passing
>	SCANF_LDBL_IS_DBL | SCANF_ISOC99_A.  Set up a strfile if necessary.
>        Do not set __no_long_double.  Normalize variable names.
 ~~~~~~~~
Spaces that could be converted to tabs.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 1/9] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-26 15:17   ` Gabriel F. T. Gomes
@ 2018-03-26 15:40     ` Zack Weinberg
  2018-03-26 15:52       ` Gabriel F. T. Gomes
  0 siblings, 1 reply; 37+ messages in thread
From: Zack Weinberg @ 2018-03-26 15:40 UTC (permalink / raw)
  To: Gabriel F. T. Gomes; +Cc: GNU C Library

On Mon, Mar 26, 2018 at 11:17 AM, Gabriel F. T. Gomes
<gabriel@inconstante.eti.br> wrote:
> On Wed, 07 Mar 2018, Zack Weinberg wrote:
>
>>       * include/monetary.h (STRFMON_LDBL_IS_DBL): New constant.
>>       (__vstrfmon_l): Rename to __vstrfmon_l_internal and add flags
>>       argument.
>
> Maybe mention that attribute_hidden was not required, thus removed?
>
> Is this another instance of the 'only needed when called both from inside
> and outside of glibc' argument (as pointed out in a previous message [1])?
>
> [1] https://sourceware.org/ml/libc-alpha/2018-03/msg00311.html

I was partially wrong about that, see the subsequent discussion
between me and Florian.  I'm in the process of revising this patchset
to get the hidden annotations 100% correct, and that's sent me down
two levels of rabbit hole...

The rules as I currently understand them are:

 - A function that is _only_ called from inside the DSO that defines
it should have its prototype declaration marked attribute_hidden; the
*_hidden_def and *_hidden_proto macros should not be used.
 - A function that is called from both inside and outside the DSO that
defines it needs two or possibly three names, depending on a bunch of
additional factors; the *_hidden_def and *_hidden_proto macros are for
this case.
 - A function that is _only_ called from _outside_ the DSO that
defines it should not use either attribute_hidden or
*_hidden_{def,proto}.

There are additional complications having to do with static linkage,
whether the function is part of the API exposed to applications,
whether it was specified in C89, and whether we're trying to write
internal code using this function to look like normal (application)
code.  It's a big mess, frankly.

>>+extern ssize_t __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
>>+                                      const char *format, va_list ap,
>>+                                      unsigned int flags);
>   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> Spaces that could be converted to tabs.

Ugh.  I will have to go through the entire patchset and check for
these.  (My editor is set to indent exclusively with spaces, because
several other projects I contribute or have contributed to require
that; glibc is the exception.)

zw

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add __v*printf_internal with flags arguments.
  2018-03-07 19:32 ` [PATCH 5/9] Add __v*printf_internal with flags arguments Zack Weinberg
@ 2018-03-26 15:41   ` Gabriel F. T. Gomes
  0 siblings, 0 replies; 37+ messages in thread
From: Gabriel F. T. Gomes @ 2018-03-26 15:41 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha

On Wed, 07 Mar 2018, Zack Weinberg wrote:

> int
>-_IO_vdprintf (int d, const char *format, va_list arg)
>+__vdprintf_internal (int d, const char *format, va_list arg,
>+                     unsigned int mode_flags)
  ~~~~~~~~~~~~~~~~
Spaces that could be converted to tabs.

> int
>-__IO_vsprintf (char *string, const char *format, va_list args)
>+__vsprintf_internal (char *string, const char *format, va_list args,
>+                     unsigned int mode_flags)
  ~~~~~~~~~~~~~~~~
Likewise.

>--- a/libio/libio.h
>+++ b/libio/libio.h
>@@ -298,8 +298,6 @@ weak_extern (_IO_stdin_used);
> 
> extern int _IO_vfwscanf (FILE * __restrict, const wchar_t * __restrict,
> 			 __gnuc_va_list, int *__restrict);
>-extern int _IO_vfwprintf (FILE *__restrict, const wchar_t *__restrict,
>-			  __gnuc_va_list);

In the second patch in this series, you mentioned that _IO_vfwscanf was
being kept because external callers could theoretically exist.  I don't
have the necessary background to understand why this doesn't apply to
_IO_vfwprintf, too.  Doesn't it?

>+/* Internal versions of v*printf that take an additional flags
>+   parameter.  */
>+extern int __vfprintf_internal (FILE *fp, const char *format, va_list ap,
>+                                unsigned int mode_flags);
>+extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap,
>+                                 unsigned int mode_flags);
>+
>+extern int __vasprintf_internal (char **result_ptr, const char *format,
>+                                 va_list ap, unsigned int mode_flags);
>+extern int __vdprintf_internal (int d, const char *format, va_list ap,
>+                                unsigned int mode_flags);
>+extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
>+                                       va_list ap, unsigned int mode_flags);
>+
>+extern int __vsprintf_internal (char *string, const char *format, va_list ap,
>+                                unsigned int mode_flags);
>+extern int __vsnprintf_internal (char *string, size_t maxlen,
>+                                 const char *format, va_list ap,
>+                                 unsigned int mode_flags);
>+extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
>+                                 const wchar_t *format, va_list ap,
>+                                 unsigned int mode_flags);
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In this block of function prototypes, some spaces that could be converted
to tabs.

> int
>-_IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
>+__obstack_vprintf_internal (struct obstack *obstack, const char *format,
>+                            va_list args, unsigned int mode_flags)
  ~~~~~~~~~~~~~~~~~~~~~~~~
Likewise.

>-  result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
>+  result = __vfprintf_internal (&new_f.ofile.file.file, format, args,
>+                                mode_flags);
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Likewise.

> int
>-_IO_vasprintf (char **result_ptr, const char *format, va_list args)
>+__vasprintf_internal (char **result_ptr, const char *format, va_list args,
>+                      unsigned int mode_flags)
  ~~~~~~~~~~~~~~~~
Likewise.

> int
>-_IO_vsnprintf (char *string, size_t maxlen, const char *format,
>-	       va_list args)
>+__vsnprintf_internal (char *string, size_t maxlen, const char *format,
>+                      va_list args, unsigned int mode_flags)
  ~~~~~~~~~~~~~~~~
Likewise.

>+int
>+___vsnprintf (char *string, size_t maxlen, const char *format, va_list args)
>+{
>+  return __vsnprintf_internal (string, maxlen, format, args, 0);
>+}
>+ldbl_weak_alias (___vsnprintf, __vsnprintf)
>+ldbl_hidden_def (___vsnprintf, __vsnprintf)
>+ldbl_weak_alias (___vsnprintf, vsnprintf)

OK.

> /* Helper function to provide temporary buffering for unbuffered streams.  */
>-static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
>+static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list,
>+                              unsigned int)
  ~~~~~~~~~~~~~~~~~~~~~~~~
Spaces instead of tabs.

>@@ -1223,7 +1230,9 @@ static int printf_positional (FILE *s,
> 			      va_list ap, va_list *ap_savep, int done,
> 			      int nspecs_done, const UCHAR_T *lead_str_end,
> 			      CHAR_T *work_buffer, int save_errno,
>-			      const char *grouping, THOUSANDS_SEP_T);
>+			      const char *grouping,
>+                              THOUSANDS_SEP_T thousands_sep,
>+                              unsigned int mode_flags);
  ~~~~~~~~~~~~~~~~~~~~~~~~
Likewise.

>@@ -1699,7 +1714,8 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
> 		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
> 		   const UCHAR_T *lead_str_end,
> 		   CHAR_T *work_buffer, int save_errno,
>-		   const char *grouping, THOUSANDS_SEP_T thousands_sep)
>+		   const char *grouping, THOUSANDS_SEP_T thousands_sep,
>+                   unsigned int mode_flags)
  ~~~~~~~~~~~~~~~~
Likewise.

> static int
>-buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
>+buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
>+                   unsigned int mode_flags)
  ~~~~~~~~~~~~~~~~
Likewise.

>   /* Now print to helper instead.  */
>-#ifndef COMPILE_WPRINTF
>-  result = _IO_vfprintf (hp, format, args);
>-#else
>-  result = vfprintf (hp, format, args);
>-#endif
>+  result = vfprintf (hp, format, args, mode_flags);

OK.

>--- a/stdlib/strfrom-skeleton.c
>+++ b/stdlib/strfrom-skeleton.c
>@@ -106,7 +106,7 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
>     }
> 
>   /* The following code to prepare the virtual file has been adapted from the
>-     function _IO_vsnprintf from libio.  */
>+     function __vsnprintf from libio.  */
                ~~~~~~~~~~~
It would be more precise to mention __vsnprint_internal.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 0/9] Use more flags parameters instead of global bits in stdio
  2018-03-26 15:16 ` Gabriel F. T. Gomes
@ 2018-03-26 15:47   ` Zack Weinberg
  0 siblings, 0 replies; 37+ messages in thread
From: Zack Weinberg @ 2018-03-26 15:47 UTC (permalink / raw)
  To: Gabriel F. T. Gomes; +Cc: GNU C Library

On Mon, Mar 26, 2018 at 11:16 AM, Gabriel F. T. Gomes
<gabriel@inconstante.eti.br> wrote:
> On Wed, 07 Mar 2018, Zack Weinberg wrote:
>
>>I got stuck on the patch to use C99-compliant scanf in _GNU_SOURCE
>>mode because the interaction with ldbl-is-dbl was too confusing.  The
>>reason it's too confusing is that C99 compliance in scanf, ldbl-is-dbl
>>mode in scanf, printf, and strfmon, and fortify mode in printf are
>>handled with mode bits on the FILE and thread-global flags that must
>>be set and reset at just the right times.  Correct behavior is
>>invariably to set and then reset around just one call to a lower-level
>>function, and there's a better way to do that: flags parameters.
>>
>>This patch series implements _internal variants of scanf, printf,
>>strfmon, and syslog that take flag parameters that control C99
>>compliance, ldbl-is-dbl mode, and fortification.
>
> Thanks for doing this.  It looks a lot less confusing now.

Thanks for reviewing.  I will look at all your individual comments
when I cycle back to this patchset again, which might not be for a
while -- as I mentioned in another message, trying to get the hidden
annotations 100% correct has sent me down a rabbit hole (first "let's
write a test so that these problems are automatically detected in the
future", and then "... whoops, there are a lot of existing errors that
will need to be corrected before we can have that test", and now I'm
on "fixing some of those errors involves major surgery on libpthread
and ld.so" :-/ ) and meanwhile I do have a day job that has nothing to
do with any of this.

zw

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 1/9] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-03-26 15:40     ` Zack Weinberg
@ 2018-03-26 15:52       ` Gabriel F. T. Gomes
  0 siblings, 0 replies; 37+ messages in thread
From: Gabriel F. T. Gomes @ 2018-03-26 15:52 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: GNU C Library

On Mon, 26 Mar 2018, Zack Weinberg wrote:

>Ugh.  I will have to go through the entire patchset and check for
>these.  (My editor is set to indent exclusively with spaces, because
>several other projects I contribute or have contributed to require
>that; glibc is the exception.)

Oh, OK.  Sorry for the similar reports in the other patches...  I won't
report them in the remaining.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 0/9] Use more flags parameters instead of global bits in stdio
  2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
                   ` (10 preceding siblings ...)
  2018-03-26 15:16 ` Gabriel F. T. Gomes
@ 2018-06-27 15:50 ` Florian Weimer
  11 siblings, 0 replies; 37+ messages in thread
From: Florian Weimer @ 2018-06-27 15:50 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha, Gabriel F. T. Gomes

On 03/07/2018 08:31 PM, Zack Weinberg wrote:
> I got stuck on the patch to use C99-compliant scanf in _GNU_SOURCE
> mode because the interaction with ldbl-is-dbl was too confusing.  The
> reason it's too confusing is that C99 compliance in scanf, ldbl-is-dbl
> mode in scanf, printf, and strfmon, and fortify mode in printf are
> handled with mode bits on the FILE and thread-global flags that must
> be set and reset at just the right times.  Correct behavior is
> invariably to set and then reset around just one call to a lower-level
> function, and there's a better way to do that: flags parameters.

I looked at how this change interacts with printf format specifier 
callbacks.

There currently does not appear to be a way to determine in the callback 
if an L argument was of double or long double type.  There is code to 
adjust the argument type for double mode:

       case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
         if (__ldbl_is_dbl)
           {
             args_value[cnt].pa_double = va_arg (*ap_savep, double);
             args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
           }
         else
           args_value[cnt].pa_long_double = va_arg (*ap_savep, long double);
         break;

But I don't think args_type is ever read back, and it's not really 
accessible to the second callback function afterwards.

With the thread-local variable, you can run something like this to 
determine if you are in double double or binary64 mode because snprintf 
will not reset the __no_long_double internal TLS variable:

static bool
is_long_double_mode (void)
{
   char buf[64];
   extern __typeof__ (snprintf) snprintf_alias __asm__ ("snprintf");
   snprintf_alias (buf, sizeof (buf), "%.30Lf",
                   1234.0000000000000000000001L);
   puts (buf);
   return strcmp (buf, "1234.000000000000000000000099999997") == 0;
}

There does not seem to be any other way to get at this variable, so I'm 
not sure this is something we need to support going forward.  The flag 
is not copied into the FILE * struct, either.  Considering that 
is_long_double_mode is so inefficient, I don't think this is anything to 
worry about for real code.

For the _IO_FLAGS2_FORTIFY flag, things are a bit different.  It is 
currently copied into the FILE * struct, so it is in theory accessible 
to the printf callbacks.  But it's now in an internal header, and it 
seems unlikely that any code would use it given that it was 
underdocumented before.  Again, this doesn't look a practical problem.

This concern does not apply to _IO_FLAGS2_SCANF_STD because there are no 
scanf hooks, so there isn't any problem there.

So I think this means that the change from thread-local variable and 
in-FILE flags to an argument is conceptually valid.  I have only started 
to review the implementation, though.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-03-13 12:35   ` Adhemerval Zanella
@ 2018-06-29 14:04     ` Florian Weimer
  0 siblings, 0 replies; 37+ messages in thread
From: Florian Weimer @ 2018-06-29 14:04 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha

On 03/13/2018 01:35 PM, Adhemerval Zanella wrote:
>> @@ -1026,7 +1030,9 @@ compat_symbol (libc, __nldbl_vdprintf, vdprintf, GLIBC_2_0);
>>   compat_symbol (libc, __nldbl_vsnprintf, vsnprintf, GLIBC_2_0);
>>   compat_symbol (libc, __nldbl_vsprintf, vsprintf, GLIBC_2_0);
>>   compat_symbol (libc, __nldbl__IO_sscanf, _IO_sscanf, GLIBC_2_0);
>> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
>>   compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
>> +#endif
>>   compat_symbol (libc, __nldbl___vfscanf, __vfscanf, GLIBC_2_0);
>>   compat_symbol (libc, __nldbl___vsscanf, __vsscanf, GLIBC_2_0);
>>   compat_symbol (libc, __nldbl_fscanf, fscanf, GLIBC_2_0);

> I am not sure that nesting SHLIB_COMPAT is correct way logically and stylisc here:
> the compat symbol will be create only for ABI which initial version of GLIBC_2_0
> (which might not be an issue with current ABIs that requires ldbl to dbl compat
> symbol).

Wouldn't GLIBC_2_0 be expanded to the relevant default ABI baseline for 
the port and do the right thing here?

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-03-26 15:28   ` Gabriel F. T. Gomes
@ 2018-06-29 14:12     ` Florian Weimer
  0 siblings, 0 replies; 37+ messages in thread
From: Florian Weimer @ 2018-06-29 14:12 UTC (permalink / raw)
  To: Gabriel F. T. Gomes, Zack Weinberg; +Cc: libc-alpha

On 03/26/2018 05:27 PM, Gabriel F. T. Gomes wrote:
> On Wed, 07 Mar 2018, Zack Weinberg wrote:
> 
>> (It was necessary to introduce ldbl_compat_symbol for _IO_vfscanf.
>> Please check that part of the patch very carefully, I am still not
>> confident I understand all of the details of ldbl-opt.)
> 
> It looks good on powerpc64...  Oldest symbol (where long double had the
> same format as double) is still there as a compat symbol with version
> GLIBC_2.3...  The newer symbol, is a bit different, in the sense that it
> is now a compat symbol (it was a default symbol previously).
> 
> Here's what readelf has to tell us:
> 
> Before the patch set:
>    1355: 00000000001eea70   124 FUNC    GLOBAL DEFAULT   27 _IO_vfscanf@GLIBC_2.3
>    1356: 00000000001f0a98 23552 FUNC    GLOBAL DEFAULT   27 _IO_vfscanf@@GLIBC_2.4
> 
> After the patch set:
>    1355: 00000000001f0bd0   136 FUNC    GLOBAL DEFAULT   27 _IO_vfscanf@GLIBC_2.4
>    1356: 00000000001ee968   136 FUNC    GLOBAL DEFAULT   27 _IO_vfscanf@GLIBC_2.3

I think that's correct and intended because there is no user redirect to 
_IO_vfscanf in public headers, and libndbl_nonshared.a does not use this 
interface, either (it uses __nldbl__IO_vfscanf).

>> --- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
>> +++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
>> @@ -20,10 +20,14 @@
>>    long_double_symbol (libc, __GL_##name##_##aliasname, aliasname);
>> # define long_double_symbol_1(lib, local, symbol, version) \
>>    versioned_symbol (lib, local, symbol, version)
>> +# define ldbl_compat_symbol(lib, local, symbol, version) \
>> +  compat_symbol (lib, local, symbol, LONG_DOUBLE_COMPAT_VERSION)
>> #else
>> # define ldbl_hidden_def(local, name) libc_hidden_def (name)
>> # define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
>> # define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
>> +# define ldbl_compat_symbol(lib, local, symbol, version) \
>> +  compat_symbol (lib, local, symbol, version)
> 
> I believe that Adhemerval's comment is correct and ldbl_compat_symbol
> should translate to nothing when building static libraries.

The shared library should not contain any definition for the compat 
symbol.  The SHLIB_COMPAT mechanism takes care of that.

But I do wonder if we need this mechanism at all.  Wouldn't it be more 
appropriate to define LONG_DOUBLE_COMPAT_VERSION by default, as 
GLIBC_2_0, and then just use

compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, LONG_DOUBLE_COMPAT_VERSION);

?

This pretends that GLIBC_2_0 already underwent the long double 
transition, and this seems somewhat consistent to me.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-03-07 19:32 ` [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments Zack Weinberg
  2018-03-13 12:35   ` Adhemerval Zanella
  2018-03-26 15:28   ` Gabriel F. T. Gomes
@ 2018-06-29 14:24   ` Florian Weimer
  2018-06-29 14:29   ` Florian Weimer
  3 siblings, 0 replies; 37+ messages in thread
From: Florian Weimer @ 2018-06-29 14:24 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha, Gabriel F. T. Gomes

On 03/07/2018 08:31 PM, Zack Weinberg wrote:
> diff --git a/stdio-common/iovfwscanf.c b/stdio-common/iovfwscanf.c
> new file mode 100644
> index 0000000000..73936f68b2
> --- /dev/null
> +++ b/stdio-common/iovfwscanf.c
> @@ -0,0 +1,34 @@
> +/* Copyright (C) 1991-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 <libioP.h>
> +#include <shlib-compat.h>
> +
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
> +
> +int
> +attribute_compat_text_section
> +__IO_vfwscanf (FILE *fp, const wchar_t *format, va_list ap, int *errp)
> +{
> +  int rv = __vfwscanf_internal (fp, format, ap, 0);
> +  if (__glibc_unlikely (errp != 0))
> +    *errp = (rv == -1);
> +  return rv;
> +}
> +compat_symbol (libc, __IO_vfwscanf, _IO_vfwscanf, GLIBC_2_0);
> +
> +#endif

_IO_vfwscanf was listed in <libio.h>, but never exported from the 
library.  If it is not needed anymore, you can just drop the function.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-03-07 19:32 ` [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments Zack Weinberg
                     ` (2 preceding siblings ...)
  2018-06-29 14:24   ` Florian Weimer
@ 2018-06-29 14:29   ` Florian Weimer
  3 siblings, 0 replies; 37+ messages in thread
From: Florian Weimer @ 2018-06-29 14:29 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha, Gabriel F. T. Gomes

On 03/07/2018 08:31 PM, Zack Weinberg wrote:
> diff --git a/stdio-common/iovfscanf.c b/stdio-common/iovfscanf.c
> new file mode 100644
> index 0000000000..fb347d60cb
> --- /dev/null
> +++ b/stdio-common/iovfscanf.c
> @@ -0,0 +1,34 @@
> +/* Copyright (C) 1991-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 <libioP.h>
> +#include <shlib-compat.h>
> +
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
> +
> +int
> +attribute_compat_text_section
> +__IO_vfscanf (FILE *fp, const char *format, va_list ap, int *errp)
> +{
> +  int rv = __vfscanf_internal (fp, format, ap, 0);
> +  if (__glibc_unlikely (errp != 0))
> +    *errp = (rv == -1);
> +  return rv;
> +}
> +ldbl_compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
> +
> +#endif

Now that _IO_vfscanf is a compat symbol, its wrapper should be removed 
from the libnldbl_nonshared.a library.  That is, the file 
sysdeps/ieee754/ldbl-opt/nldbl-iovfscanf.c should be deleted by this 
patch (and the makefile adjusted).

Thanks,
Florian

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2018-06-29 14:29 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-07 19:32 [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
2018-03-07 19:32 ` [PATCH 8/9] Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl Zack Weinberg
2018-03-07 19:32 ` [PATCH 3/9] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD Zack Weinberg
2018-03-26 15:35   ` Gabriel F. T. Gomes
2018-03-07 19:32 ` [PATCH 2/9] Add __vfscanf_internal and __vfwscanf_internal with flags arguments Zack Weinberg
2018-03-13 12:35   ` Adhemerval Zanella
2018-06-29 14:04     ` Florian Weimer
2018-03-26 15:28   ` Gabriel F. T. Gomes
2018-06-29 14:12     ` Florian Weimer
2018-06-29 14:24   ` Florian Weimer
2018-06-29 14:29   ` Florian Weimer
2018-03-07 19:32 ` [PATCH 4/9] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl Zack Weinberg
2018-03-14 12:22   ` Florian Weimer
2018-03-26 15:36   ` Gabriel F. T. Gomes
2018-03-07 19:32 ` [PATCH 1/9] Use STRFMON_LDBL_IS_DBL " Zack Weinberg
2018-03-12 20:36   ` Adhemerval Zanella
2018-03-12 21:11     ` Zack Weinberg
2018-03-13 11:45       ` Adhemerval Zanella
2018-03-26 15:17   ` Gabriel F. T. Gomes
2018-03-26 15:40     ` Zack Weinberg
2018-03-26 15:52       ` Gabriel F. T. Gomes
2018-03-07 19:32 ` [PATCH 5/9] Add __v*printf_internal with flags arguments Zack Weinberg
2018-03-26 15:41   ` Gabriel F. T. Gomes
2018-03-07 19:32 ` [PATCH 6/9] Add __vsyslog_internal, with same flags as __v*printf_internal Zack Weinberg
2018-03-13 11:59   ` Florian Weimer
2018-03-13 12:39     ` Zack Weinberg
2018-03-13 12:43       ` Florian Weimer
2018-03-13 13:37         ` Zack Weinberg
2018-03-13 13:50           ` Florian Weimer
2018-03-13 14:11             ` Zack Weinberg
2018-03-13 14:13               ` Florian Weimer
2018-03-07 19:51 ` [PATCH 9/9] Post-cleanup: don't include math.h/math_private.h in math_ldbl_opt.h Zack Weinberg
2018-03-07 19:51 ` [PATCH 7/9] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY Zack Weinberg
2018-03-12 15:29 ` [PATCH 0/9] Use more flags parameters instead of global bits in stdio Zack Weinberg
2018-03-26 15:16 ` Gabriel F. T. Gomes
2018-03-26 15:47   ` Zack Weinberg
2018-06-27 15:50 ` Florian Weimer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).