[PATCH v2 0/8] Use more flags parameters instead of global bits in stdio

classic Classic list List threaded Threaded
34 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 0/8] Use more flags parameters instead of global bits in stdio

Gabriel F. T. Gomes-2
In March, Zack Weinberg posted a patch set [1] that, among many other
improvements to code readability and symbol versioning, removed the TLS
variable __ldbl_is_dbl.

This patch set is very relevant in itself *and* it is very useful for
the long double work on powerpc64le.  I have a special interest in
this patch set being approved and I worked on many of the comments that
were raised during the review of the first version, as well as I have
made other changes that were not mentioned at that time.

Each of the patches contains a "Changed since v1" section, where I
describe all (except for unintentional omissions, if any) changes,
anyhow, I mention some of them below, because I think they might require
additional attention:

  - I removed some occurrences of libc_hidden_def and libc_hidden_proto
    from function definitions that were not commented on in the previous
    discussion.  I removed them because I checked that such functions
    are not called from within libc (although they could be called from
    libnldbl_nonshared.a).  There could be other occurrences in the
    code, but before I work on a patch to get rid of them all, I thought
    it would be best to get feedback.
  - I added attribute_hidden to function declarations that were not
    commented on in the previous discussion.  I did it because I
    understood that adding this attribute can lead to better code
    generation on some architectures, e.g. 32-bits powerpc, thus I also
    pasted the output of objdumps before and after the change.  I hope
    that helps with the review.
  - I kept the definition of ldbl_compat_symbol based on my
    understanding that it would be best to have this additional macro,
    instead on relying on the implicit, suggested [2] semantics for
    LONG_DOUBLE_COMPAT_VERSION (i.e.: on platforms where a long double
    transition never occurred, we pretend that it occurred on GLIBC 2.0)
  - I removed the declaration of many functions (e.g.: _IO_vfprintf)
    from internal headers, because they are no longer called from within
    libc, thus the internal declaration is only duplicating code.

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

[2] https://sourceware.org/ml/libc-alpha/2018-06/msg00980.html

Zack Weinberg (8):
  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.

 argp/argp-fmtstream.c                    |    3 +-
 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                       |   12 +-
 include/stdio.h                          |    8 -
 include/sys/syslog.h                     |   19 +-
 include/wchar.h                          |   12 -
 libio/fwprintf.c                         |    2 +-
 libio/iolibio.h                          |    8 -
 libio/iovdprintf.c                       |   13 +-
 libio/iovsprintf.c                       |   66 +-
 libio/iovsscanf.c                        |   12 +-
 libio/iovswscanf.c                       |   14 +-
 libio/libio.h                            |    8 -
 libio/libioP.h                           |   77 +-
 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                        |   16 +-
 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                            |   36 +-
 stdio-common/Makefile                    |    4 +-
 stdio-common/Versions                    |    3 +
 stdio-common/asprintf.c                  |    6 +-
 stdio-common/dprintf.c                   |    5 +-
 stdio-common/fprintf.c                   |    2 +-
 stdio-common/fxprintf.c                  |    4 +-
 stdio-common/iovfscanf.c                 |   38 +
 stdio-common/iovfwscanf.c                |   38 +
 stdio-common/isoc99_fscanf.c             |    7 +-
 stdio-common/isoc99_scanf.c              |   12 +-
 stdio-common/isoc99_sscanf.c             |    8 +-
 stdio-common/isoc99_vfscanf.c            |    9 +-
 stdio-common/isoc99_vscanf.c             |    9 +-
 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          | 3045 ++++++++++++++++++++++++++++++
 stdio-common/vfscanf.c                   | 3042 +----------------------------
 stdio-common/vfwprintf-internal.c        |    2 +
 stdio-common/vfwprintf.c                 |   28 +-
 stdio-common/vfwscanf-internal.c         |    2 +
 stdio-common/vfwscanf.c                  |   28 +-
 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-opt/Makefile        |    2 +-
 sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h |    9 +-
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c  |  807 ++++----
 sysdeps/ieee754/ldbl-opt/nldbl-compat.h  |    8 +-
 sysdeps/nptl/stdio-lock.h                |    7 -
 wcsmbs/isoc99_fwscanf.c                  |    7 +-
 wcsmbs/isoc99_swscanf.c                  |   11 +-
 wcsmbs/isoc99_vfwscanf.c                 |    9 +-
 wcsmbs/isoc99_vswscanf.c                 |   15 +-
 wcsmbs/isoc99_vwscanf.c                  |    9 +-
 wcsmbs/isoc99_wscanf.c                   |    7 +-
 95 files changed, 6458 insertions(+), 6620 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.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 1/8] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.

Gabriel F. T. Gomes-2
From: Zack Weinberg <[hidden email]>

Changed since v1:

  - Added attribute hidden to __vstrfmon_l_internal.
    On powerpc, code in the call sites changed:
    From:
      $ objdump -d --reloc VISIBLE-glibc/libc.so.6 | grep __nldbl___vstrfmon_l -A 13
      001502a0 <__nldbl___vstrfmon_l>:
        1502a0:       94 21 ff f0     stwu    r1,-16(r1)
        1502a4:       39 00 00 01     li      r8,1
        1502a8:       7c 08 02 a6     mflr    r0
        1502ac:       42 9f 00 05     bcl     20,4*cr7+so,1502b0 <__nldbl___vstrfmon_l+0x10>
        1502b0:       93 c1 00 08     stw     r30,8(r1)
        1502b4:       90 01 00 14     stw     r0,20(r1)
        1502b8:       7f c8 02 a6     mflr    r30
        1502bc:       3f de 00 05     addis   r30,r30,5
        1502c0:       3b de fd 44     addi    r30,r30,-700
        1502c4:       4b ef b6 5d     bl      4b920 <__vstrfmon_l_internal>
        1502c8:       80 01 00 14     lwz     r0,20(r1)
        1502cc:       83 c1 00 08     lwz     r30,8(r1)
        1502d0:       38 21 00 10     addi    r1,r1,16
        1502d4:       7c 08 03 a6     mtlr    r0
        1502d8:       4e 80 00 20     blr
        1502dc:       60 00 00 00     nop
    To:
      $ objdump -d --reloc HIDDEN-glibc/libc.so.6 | grep __nldbl___vstrfmon_l -A 5
      00150260 <__nldbl___vstrfmon_l>:
        150260:       39 00 00 01     li      r8,1
        150264:       4b ef b6 bc     b       4b920 <__vstrfmon_l_internal>
        150268:       60 00 00 00     nop
        15026c:       60 00 00 00     nop
  - Replaced blocks of eight spaces with tabs.
  - Added signed-off-by field with Zack's and mine names.
  - Extended commit message and comments.

-- 8< --
On platforms where long double used to have the same format as double,
but later switched to a different format (alpha, s390, sparc, and
powerpc), accessing the older behavior is possible and it happens via
__nldbl_* functions (not on the API, but accessible from header
redirection and from compat symbols).  These functions write to the
global flag __ldbl_is_dbl, which tells other functions that long double
variables should be handled as double.  This patch takes the first step
towards removing this global flag and creates __vstrfmon_l_internal,
which takes an explicit flags parameter.

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.

Tested for powerpc and powerpc64le.

2018-10-11  Zack Weinberg  <[hidden email]>
            Gabriel F. T. Gomes  <[hidden email]>

        * 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 from
        __nldbl___vstrfmon and __nldbl___vstrfmon_l, because they are no
        longer called from within the library.
        * sysdeps/ieee754/ldbl-opt/nldbl-compat.h: Don't use NLDBL_DECL
        for __nldbl___vstrfmon_l, declare it explicitly.

        * manual/locale.texi: Update a reference to vstrfmon_l in comments.

Signed-off-by: Zack Weinberg <[hidden email]>
Signed-off-by: Gabriel F. T. Gomes <[hidden email]>
---
 include/monetary.h                      | 12 +++++++++---
 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, 37 insertions(+), 37 deletions(-)

diff --git a/include/monetary.h b/include/monetary.h
index c130ed56a3..a226305adf 100644
--- a/include/monetary.h
+++ b/include/monetary.h
@@ -2,7 +2,13 @@
 #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)
+  attribute_hidden;
+
+/* 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..3058b3eed1 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..5293104400 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 ffb5fabebe..7a1e89c1a3 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -51,8 +51,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)
@@ -780,12 +778,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
@@ -794,12 +793,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)
 
@@ -807,28 +807,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 b7e938f785..b7606c3c2d 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
@@ -64,7 +64,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);
@@ -78,10 +77,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.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 2/8] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
From: Zack Weinberg <[hidden email]>

Changed since v1:

  - Added one line comment to new files.
  - In nldbl-compat.c, added explanation for the need to use
    '#if SHLIB_COMPAT' within 'if LONG_DOUBLE_COMPAT'.  Also moved the
    block further down, for stylistic reasons [1].
  - Added attribute_hidden to the internal (libioP.h) declarations of
    __vfscanf_internal and __vfwscanf_internal [2].
  - Added comment explaining the reason for the use of SHLIB_COMPAT on
    stdio-common/iovfscanf.c and stdio-common/iovfwscanf.c.
  - Converted the definition of ldbl_compat_symbol from an expansion of
    compat_symbol to '...', because ldbl_compat_symbol is also not
    supposed to be used outside of '#if SHLIB_COMPAT' statements.  In my
    opinion, it's better to make this clear in the definition of
    ldbl_compat_symbol itself, rather than having to go to the
    definition of compat_symbol to learn this (if people think that this
    is not the best option, I can revert this change (In that case, the
    definition of ldbl_compat_symbol could be moved outside the '#if
    SHARED' block).  Added a comment with this explanation.
  - Added signed-off-by statements.
  - Replaced 2.28 with 2.29 to adjust for the next release.

Not changed since v1:

  - Florian suggested that the need for ldbl_compat_symbol is
    questionable, because we could define LONG_DOUBLE_COMPAT_VERSION to
    GLIBC_2_0 by default (pretending that the long double transition
    happened for all other platforms), then use it in compat_symbol
    calls, which would create the compat symbols for _IO_vfscanf and
    _IO_vfwscanf with that version.
    That would work, because all the functions that will use
    ldbl_compat_symbol after this patch set were actually introduced
    before GLIBC_2_0.  However, for newer functions, such as swscanf,
    that wouldn't work, if we ever need to do something similar.

Additional note for review:

  - Reviewing the changes from vfscanf.c to vfscanf-internal.c in the
    original patch would be vey hard, because git doesn't detect the
    filename change.  To make review a little easier, I did as Zack did
    and manually edited the diff.  I'll reply to this thread and attach
    the original patch if someone wants to apply it.
    (ping me if I forget it)

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

[2] As a result, internal calls to __vfscanf_internal, on powerpc, do
    not use the PLT, the following blocks show the difference:

    Without __attribute__ (hidden):
      $ objdump -d --reloc VFSCANF-VISIBLE-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 17
      0014ea00 <__nldbl___vfscanf>:
        14ea00:       94 21 ff f0     stwu    r1,-16(r1)
        14ea04:       38 c0 00 01     li      r6,1
        14ea08:       7c 08 02 a6     mflr    r0
        14ea0c:       42 9f 00 05     bcl     20,4*cr7+so,14ea10 <__nldbl___vfscanf+0x10>
        14ea10:       93 c1 00 08     stw     r30,8(r1)
        14ea14:       90 01 00 14     stw     r0,20(r1)
        14ea18:       7f c8 02 a6     mflr    r30
        14ea1c:       3f de 00 05     addis   r30,r30,5
        14ea20:       3b de 15 e4     addi    r30,r30,5604
        14ea24:       4b f0 b8 0d     bl      5a230 <__vfscanf_internal>
        14ea28:       80 01 00 14     lwz     r0,20(r1)
        14ea2c:       83 c1 00 08     lwz     r30,8(r1)
        14ea30:       38 21 00 10     addi    r1,r1,16
        14ea34:       7c 08 03 a6     mtlr    r0
        14ea38:       4e 80 00 20     blr
        14ea3c:       60 00 00 00     nop

    With __attribute__ (hidden):
      $ objdump -d --reloc VFSCANF-HIDDEN-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 5
      0014e8b0 <__nldbl___vfscanf>:
        14e8b0:       38 c0 00 01     li      r6,1
        14e8b4:       4b f0 b8 bc     b       5a170 <__vfscanf_internal>
        14e8b8:       60 00 00 00     nop
        14e8bc:       60 00 00 00     nop

-- 8< --
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.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <[hidden email]>
            Gabriel F. T. Gomes  <[hidden email]>

        * 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_WSCANF; don't define any other public symbols.
        Remove errval and code to set errp.
        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: New file defining the public entry
        point vfscanf, which calls __vfscanf_internal.
        * stdio-common/vfwscanf.c: New file defining the public entry
        point vfwscanf, which calls __vfwscanf_internal.

        * stdio-common/iovfscanf.c: New file.
        * stdio-common/iovfwscanf.c: Likewise.

        * stdio-common/Makefile (routines): Add vfscanf-internal,
        vfwscanf-internal, iovfscanf, iovfwscanf.
        * stdio-common/Versions: Mention GLIBC_2.29, 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.
        Call __vfscanf_internal, instead of _IO_vfscanf.
        (__nldbl___vfscanf): Call __vfscanf_internal, instead of
        _IO_vfscanf.
        (__nldbl_vfwscanf): Call __vfwscanf_internal, instead of
        _IO_vfwscanf.

        * libio/iovsscanf.c: Clean up includes, when possible.  Use
        _IO_strfile_read or _IO_strfile_readw, when needed.  Call
        __vfscanf_internal or __vfwscanf_internal directly.
        * libio/iovswscanf.c: Likewise.
        * libio/swscanf.c: Likewise.
        * libio/vscanf.c: Likewise.
        * libio/vwscanf.c: Likewise.
        * libio/wscanf.c: Likewise.
        * stdio-common/isoc99_fscanf.c: Likewise.
        * stdio-common/isoc99_scanf.c: Likewise.
        * stdio-common/isoc99_sscanf.c: Likewise.
        * stdio-common/isoc99_vfscanf.c: Likewise.
        * stdio-common/isoc99_vscanf.c: Likewise.
        * stdio-common/isoc99_vsscanf.c: Likewise.
        * stdio-common/scanf.c: Likewise.
        * stdio-common/sscanf.c: Likewise.
        * wcsmbs/isoc99_fwscanf.c: Likewise.
        * wcsmbs/isoc99_swscanf.c: Likewise.
        * wcsmbs/isoc99_vfwscanf.c: Likewise.
        * wcsmbs/isoc99_vswscanf.c: Likewise.
        * wcsmbs/isoc99_vwscanf.c: Likewise.
        * wcsmbs/isoc99_wscanf.c: Likewise.

Signed-off-by: Zack Weinberg <[hidden email]>
Signed-off-by: Gabriel F. T. Gomes <[hidden email]>
---
 libio/iovsscanf.c                        |   12 +-
 libio/iovswscanf.c                       |   14 +-
 libio/libio.h                            |    1 -
 libio/libioP.h                           |   11 +
 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                 |   38 +
 stdio-common/iovfwscanf.c                |   38 +
 stdio-common/isoc99_fscanf.c             |    2 +-
 stdio-common/isoc99_scanf.c              |    2 +-
 stdio-common/isoc99_sscanf.c             |    9 +-
 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-internal.c          | 3050 ++++++++++++++++++++++++++++++
 stdio-common/vfscanf.c                   | 3042 +----------------------------
 stdio-common/vfwscanf-internal.c         |    2 +
 stdio-common/vfwscanf.c                  |   28 +-
 sysdeps/generic/math_ldbl_opt.h          |    4 +
 sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h |    5 +
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c  |   17 +-
 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, 3273 insertions(+), 3128 deletions(-)
 create mode 100644 stdio-common/iovfscanf.c
 create mode 100644 stdio-common/iovfwscanf.c
 create mode 100644 stdio-common/vfscanf-internal.c
 create mode 100644 stdio-common/vfwscanf-internal.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 df2633d858..fa34a628fe 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -704,6 +704,17 @@ 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)
+  attribute_hidden;
+extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
+ unsigned int flags)
+  attribute_hidden;
+
 extern int _IO_vscanf (const char *, va_list) __THROW;
 
 #ifdef _IO_MTSAFE_IO
diff --git a/libio/strfile.h b/libio/strfile.h
index 75caac2af5..62900a7128 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);
@@ -80,3 +82,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 a10f12ab3c..f3b3ceddbd 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 b8217578c8..522f302198 100644
--- a/stdio-common/Versions
+++ b/stdio-common/Versions
@@ -60,6 +60,9 @@ libc {
   GLIBC_2.28 {
     renameat2;
   }
+  GLIBC_2.29 {
+    # SHLIB_COMPAT(GLIBC_2_0, GLIBC_2_29) 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..77e698f665
--- /dev/null
+++ b/stdio-common/iovfscanf.c
@@ -0,0 +1,38 @@
+/* Implementation and symbols for _IO_vfscanf.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libioP.h>
+#include <shlib-compat.h>
+
+/* This function is provided for ports older than GLIBC 2.29 because
+   external callers could theoretically exist.  Newer ports do not need,
+   since it is not part of the API.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
+
+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..26a57788cb
--- /dev/null
+++ b/stdio-common/iovfwscanf.c
@@ -0,0 +1,38 @@
+/* Implementation and symbols for _IO_vfwscanf.
+   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>
+
+/* This function is provided for ports older than GLIBC 2.29 because
+   external callers could theoretically exist.  Newer ports do not need,
+   since it is not part of the API.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
+
+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..2c89a03fe9 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -16,19 +16,20 @@
    <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 */
 int
 __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 -u stdio-common/vfscanf.c.old stdio-common/vfscanf-internal.c.new
--- stdio-common/vfscanf.c.old 2018-10-25 17:21:09.232711752 -0300
+++ stdio-common/vfscanf-internal.c.new 2018-10-25 17:21:24.143739981 -0300
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Internal functions for the *scanf* implementation.
+   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
@@ -132,16 +133,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 +265,12 @@
    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 +281,6 @@
   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 +332,14 @@
   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 +571,7 @@
     }
   /* 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;
@@ -2423,7 +2428,7 @@
       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);
@@ -3018,8 +3023,6 @@
   UNLOCK_STREAM (s);
 
   scratch_buffer_free (&charbuf.scratch);
-  if (errp != NULL)
-    *errp |= errval;
 
   if (__glibc_unlikely (done == EOF))
     {
@@ -3045,23 +3048,3 @@
     }
   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 -u /dev/null stdio-common/vfscanf.c.new
--- /dev/null 2018-10-15 19:30:16.914999855 -0300
+++ stdio-common/vfscanf.c.new 2018-10-25 17:21:39.355768779 -0300
@@ -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-internal.c b/stdio-common/vfwscanf-internal.c
new file mode 100644
index 0000000000..26c89270b7
--- /dev/null
+++ b/stdio-common/vfwscanf-internal.c
@@ -0,0 +1,2 @@
+#define COMPILE_WSCANF 1
+#include "vfscanf-internal.c"
diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
index 26b1a66608..f1c70ad6b3 100644
--- a/stdio-common/vfwscanf.c
+++ b/stdio-common/vfwscanf.c
@@ -1,2 +1,26 @@
-#define COMPILE_WSCANF 1
-#include "vfscanf.c"
+/* Implementation and symbols for vfwscanf.
+   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 61ba784f86..4d2f3c7be2 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -20,10 +20,15 @@
   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)
+/* Same as compat_symbol, ldbl_compat_symbol is not to be used outside
+   '#if SHLIB_COMPAT' statement and should fail if it is.  */
+# define ldbl_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 7a1e89c1a3..91ea27a423 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -330,16 +330,20 @@ __nldbl_wprintf (const wchar_t *fmt, ...)
   return done;
 }
 
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
 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
@@ -347,7 +351,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;
 }
@@ -423,7 +427,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;
 }
@@ -1027,7 +1031,6 @@ 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);
-compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
 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);
@@ -1040,6 +1043,12 @@ compat_symbol (libc, __nldbl___printf_fp, __printf_fp, GLIBC_2_0);
 compat_symbol (libc, __nldbl_strfmon, strfmon, GLIBC_2_0);
 compat_symbol (libc, __nldbl_syslog, syslog, GLIBC_2_0);
 compat_symbol (libc, __nldbl_vsyslog, vsyslog, GLIBC_2_0);
+/* This function is not in public headers, but was exported until
+   version 2.29.  For platforms that are newer than that, there's no
+   need to expose the symbol.  */
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
+compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
+# endif
 #endif
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_1)
 compat_symbol (libc, __nldbl___asprintf, __asprintf, GLIBC_2_1);
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.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 3/8] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
From: Zack Weinberg <[hidden email]>

Changes since v1:

  - Cleared VARGARSn comments.
  - Added signed-off-by statements.

-- 8< --
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.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <[hidden email]>
            Gabriel F. T. Gomes  <[hidden email]>

        * 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.

Signed-off-by: Zack Weinberg <[hidden email]>
Signed-off-by: Gabriel F. T. Gomes <[hidden email]>
---
 libio/libio.h                   |  1 -
 libio/libioP.h                  |  5 ++---
 stdio-common/isoc99_fscanf.c    |  7 +------
 stdio-common/isoc99_scanf.c     | 12 +-----------
 stdio-common/isoc99_sscanf.c    |  3 +--
 stdio-common/isoc99_vfscanf.c   |  9 +--------
 stdio-common/isoc99_vscanf.c    |  9 +--------
 stdio-common/isoc99_vsscanf.c   |  3 +--
 stdio-common/vfscanf-internal.c |  2 --
 wcsmbs/isoc99_fwscanf.c         |  7 +------
 wcsmbs/isoc99_swscanf.c         |  3 +--
 wcsmbs/isoc99_vfwscanf.c        |  9 +--------
 wcsmbs/isoc99_vswscanf.c        |  3 +--
 wcsmbs/isoc99_vwscanf.c         |  9 +--------
 wcsmbs/isoc99_wscanf.c          |  7 +------
 15 files changed, 14 insertions(+), 75 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 fa34a628fe..f90fb2c050 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -775,7 +775,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);
 }
@@ -789,8 +789,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..d7b5993f3e 100644
--- a/stdio-common/isoc99_fscanf.c
+++ b/stdio-common/isoc99_fscanf.c
@@ -20,20 +20,15 @@
 #include <stdio.h>
 
 /* Read formatted input from STREAM according to the format string FORMAT.  */
-/* VARARGS2 */
 int
 __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..3998322ea1 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/isoc99_scanf.c
@@ -19,26 +19,16 @@
 #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 2c89a03fe9..c9e5103b81 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -26,10 +26,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..3c59c60b3e 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -19,16 +19,9 @@
 #include <stdio.h>
 
 /* Read formatted input from STREAM according to the format string FORMAT.  */
-/* VARARGS2 */
 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..fc5d609ae7 100644
--- a/stdio-common/isoc99_vscanf.c
+++ b/stdio-common/isoc99_vscanf.c
@@ -19,15 +19,8 @@
 #include <stdio.h>
 
 /* Read formatted input from STDIN according to the format string FORMAT.  */
-/* VARARGS2 */
 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 1ae37a2a11..dc341b0b1f 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -337,8 +337,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..5829607916 100644
--- a/wcsmbs/isoc99_fwscanf.c
+++ b/wcsmbs/isoc99_fwscanf.c
@@ -21,20 +21,15 @@
 #include <wchar.h>
 
 /* Read formatted input from STREAM according to the format string FORMAT.  */
-/* VARARGS2 */
 int
 __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..715d354b5a 100644
--- a/wcsmbs/isoc99_vfwscanf.c
+++ b/wcsmbs/isoc99_vfwscanf.c
@@ -20,16 +20,9 @@
 #include <wchar.h>
 
 /* Read formatted input from STREAM according to the format string FORMAT.  */
-/* VARARGS2 */
 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..3ac3182608 100644
--- a/wcsmbs/isoc99_vwscanf.c
+++ b/wcsmbs/isoc99_vwscanf.c
@@ -20,15 +20,8 @@
 #include <wchar.h>
 
 /* Read formatted input from STDIN according to the format string FORMAT.  */
-/* VARARGS2 */
 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..b9418f7912 100644
--- a/wcsmbs/isoc99_wscanf.c
+++ b/wcsmbs/isoc99_wscanf.c
@@ -22,20 +22,15 @@
 
 
 /* Read formatted input from stdin according to the format string FORMAT.  */
-/* VARARGS1 */
 int
 __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.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 4/8] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
From: Zack Weinberg <[hidden email]>

Changed since v1:

  - In __nldbl___isoc99_vwscanf, called __vfwscanf_internal directly
    (missing (accidentally?) from the previous version).
  - Broke long lines.
  - Changed name of variable (from rv to ret), since the rationale for
    making these changes to variables names is consistency.
  - Added signed-off-by statements.

-- 8< --
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.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <[hidden email]>
            Gabriel F. T. Gomes  <[hidden email]>

        * 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.

Signed-off-by: Zack Weinberg <[hidden email]>
Signed-off-by: Gabriel F. T. Gomes <[hidden email]>
---
 stdio-common/vfscanf-internal.c         |   3 -
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 251 +++++++++++++++-----------------
 2 files changed, 121 insertions(+), 133 deletions(-)

diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index dc341b0b1f..f989f8dc07 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -334,9 +334,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 91ea27a423..468e23dec4 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 <math.h>
 #include <wchar.h>
 #include <printf.h>
@@ -335,13 +335,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
 
@@ -349,11 +346,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)
@@ -362,26 +355,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)
@@ -390,46 +383,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)
 
@@ -437,25 +426,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)
 
@@ -463,35 +455,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
@@ -866,11 +858,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)
 
@@ -878,25 +866,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)
 
@@ -904,46 +893,44 @@ 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 ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (stdin, fmt, ap,
+    SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 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)
 
@@ -951,26 +938,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)
 
@@ -978,35 +967,37 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_vwscanf (const wchar_t *fmt, va_list ap)
 {
-  return __nldbl___isoc99_vfwscanf (stdin, fmt, ap);
+  return __vfwscanf_internal (stdin, fmt, ap,
+     SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 
 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.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 5/8] Add __v*printf_internal with flags arguments.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
From: Zack Weinberg <[hidden email]>

Changes since v1:

  - Fixed white-space errors.
  - In argp_fmtstream_printf, do not call __vsnprintf, instead call
    __vsnprintf_internal passing 0 to mode_flags.  With this change,
    there's no need to use libc_hidden_{proto,def} for __vsnprintf
    (because it doesn't have other internal callers).  Also, it is no
    longer necessary to '#undef __vsnprintf' and '#define __vsnprintf
    vsnprintf' in argp-namefrob.h.
  - In __argp_error and __argp_failure call __vasprintf_internal
    directly, passing 0 (zero) to mode_flags, since these functions do
    not currently have support for long double with the same format as
    double (a subsequent patch in my personal branch provides that and
    adjusts the call accordingly).
    With this change, there's no need to use libc_hidden_{proto,def} for
    __vasprintf.  It is also no longer required to '#undef __vasprintf'
    and '#define __vasprintf vasprintf' in argp-namefrob.h.
  - Declarations of _IO_vfprintf, _IO_vsprintf, __vfwprintf, and
    __vswprintf removed from the internal headers: libio.h, iolibio.h,
    and include/wchar.h, since they are no longer called from within
    glibc.
  - Added attribute_hidden to all new internal functions, since they are
    all called from within libc.
    Here are the objdumps of one such calls, before and after this
    change, on a 32-bits powerpc machine:
    Without attribute_hidden:
      $ objdump -d --reloc INTERNAL-VISIBLE-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 21
      000523a0 <vprintf@@GLIBC_2.4>:
         523a0:       94 21 ff f0     stwu    r1,-16(r1)
         523a4:       7c 85 23 78     mr      r5,r4
         523a8:       7c 08 02 a6     mflr    r0
         523ac:       42 9f 00 05     bcl     20,4*cr7+so,523b0 <vprintf@@GLIBC_2.4+0x10>
         523b0:       7c 64 1b 78     mr      r4,r3
         523b4:       38 c0 00 00     li      r6,0
         523b8:       93 c1 00 08     stw     r30,8(r1)
         523bc:       90 01 00 14     stw     r0,20(r1)
         523c0:       7f c8 02 a6     mflr    r30
         523c4:       3f de 00 15     addis   r30,r30,21
         523c8:       3b de dc 44     addi    r30,r30,-9148
         523cc:       81 3e fe 80     lwz     r9,-384(r30)
         523d0:       80 69 00 00     lwz     r3,0(r9)
         523d4:       48 01 52 bd     bl      67690 <__vfprintf_internal>
         523d8:       80 01 00 14     lwz     r0,20(r1)
         523dc:       83 c1 00 08     lwz     r30,8(r1)
         523e0:       38 21 00 10     addi    r1,r1,16
         523e4:       7c 08 03 a6     mtlr    r0
         523e8:       4e 80 00 20     blr
    With attribute_hidden:
      $ objdump -d --reloc INTERNAL-HIDDEN-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 18
      00052370 <vprintf@@GLIBC_2.4>:
         52370:       94 21 ff f0     stwu    r1,-16(r1)
         52374:       7c 85 23 78     mr      r5,r4
         52378:       7d 88 02 a6     mflr    r12
         5237c:       42 9f 00 05     bcl     20,4*cr7+so,52380 <vprintf@@GLIBC_2.4+0x10>
         52380:       7c 64 1b 78     mr      r4,r3
         52384:       38 c0 00 00     li      r6,0
         52388:       93 c1 00 08     stw     r30,8(r1)
         5238c:       7f c8 02 a6     mflr    r30
         52390:       7d 88 03 a6     mtlr    r12
         52394:       3f de 00 15     addis   r30,r30,21
         52398:       3b de dc 74     addi    r30,r30,-9100
         5239c:       81 3e fe 80     lwz     r9,-384(r30)
         523a0:       83 c1 00 08     lwz     r30,8(r1)
         523a4:       80 69 00 00     lwz     r3,0(r9)
         523a8:       38 21 00 10     addi    r1,r1,16
         523ac:       48 01 52 24     b       675d0 <__vfprintf_internal>
    The branch-and-link instruction is gone.

Additional note for review:

  - Reviewing the changes from vfprintf.c to vfprintf-internal.c in the
    original patch would be vey hard, because git doesn't detect the
    filename change.  To make review a little easier, I did as Zack did
    and manually edited the diff.  I'll reply to this thread and attach
    the original patch if someone wants to apply it.
    (ping me if I forget it)

-- 8< --
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 and
_IO_vfprintf *are* exported, so those two stick around.

Summary for the changes to each of the affected symbols:

  _IO_vfprintf, _IO_vsprintf:
    All internal calls removed, thus the internal declarations, as well
    as uses of libc_hidden_proto and libc_hidden_def, were also removed.
    The external symbol is now exposed via uses of ldbl_strong_alias
    to __vfprintf_internal and __vsprintf_internal, respectively.

  _IO_vasprintf, _IO_vdprintf, _IO_vsnprintf,
  _IO_vfwprintf, _IO_vswprintf,
  _IO_obstack_vprintf, _IO_obstack_printf:
    All internal calls removed, thus declaration in internal headers
    were also removed.  They were never exported, so there are no
    aliases tying them to the internal functions.  I.e.: entirely gone.

  __vsnprintf:
    Internal calls were always preceded by macros such as
      #define __vsnprintf _IO_vsnprintf, and
      #define __vsnprintf vsnprintf
    The macros were removed and their uses replaced with calls to the
    new internal function __vsnprintf_internal.  Since there were no
    internal calls, the internal declaration was also removed.  The
    external symbol is preserved with ldbl_weak_alias to ___vsnprintf.

  __vfwprintf:
    All internal calls converted into calls to __vfwprintf_internal,
    thus the internal declaration was removed.  The function is now a
    wrapper that calls __vfwprintf_internal.  The external symbol is
    preserved.

  __vswprintf:
    Similarly, but no external symbol.

  __vasprintf, __vdprintf, __vfprintf, __vsprintf:
    New internal wrappers.  Not exported.

  vasprintf, vdprintf, vfprintf, vsprintf, vsnprintf,
  vfwprintf, vswprintf,
  obstack_vprintf, obstack_printf:
    These functions used to be aliases to the respective _IO_* function,
    they are now aliases to their respective __* functions.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <[hidden email]>
            Gabriel F. T. Gomes  <[hidden email]>

        * 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.
        Remove use of ldbl_hidden_def, since __vsnprintf is no longer
        called internally.
        * 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 and declaration for
        _IO_vfprintf.
        Remove declaration of _IO_vfwprintf.
        * libio/iolibio.h: Remove libc_hidden_proto and declaration for
        _IO_vsprintf.
        Remove declarations of _IO_vswprintf, _IO_obstack_printf, and
        _IO_obstack_printf.
        * include/stdio.h: Add prototype for __vasprintf.
        (__vsnprintf): Remove declaration, because there are no more
        internal calls.
        * include/wchar.h (__vfwprintf, __vswprintf): Remove
        declaration, because there are no more internal calls.

        * argp/argp-fmtstream.c (__argp_fmtstream_printf): Use
        __vsnprintf_internal, instead of _IO_vsnprintf.
        * argp/argp-help.c (__argp_error, __argp_failure): Use
        __vasprintf_internal, instead of _IO_vasprintf.
        * argp/argp-namefrob.h (__vsnprintf): Do not undefined then
        redefine, because there are no more internal calls.

Signed-off-by: Zack Weinberg <[hidden email]>
Signed-off-by: Gabriel F. T. Gomes <[hidden email]>
---
 argp/argp-fmtstream.c                   |    3 +-
 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                         |    3 -
 include/wchar.h                         |   10 -
 libio/fwprintf.c                        |    2 +-
 libio/iolibio.h                         |    8 -
 libio/iovdprintf.c                      |   13 +-
 libio/iovsprintf.c                      |   16 +-
 libio/libio.h                           |    5 -
 libio/libioP.h                          |   40 +-
 libio/obprintf.c                        |   19 +-
 libio/swprintf.c                        |    2 +-
 libio/vasprintf.c                       |   20 +-
 libio/vsnprintf.c                       |   16 +-
 libio/vswprintf.c                       |   16 +-
 libio/vwprintf.c                        |    2 +-
 libio/wprintf.c                         |    2 +-
 stdio-common/Makefile                   |    3 +-
 stdio-common/asprintf.c                 |    6 +-
 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-internal.c        | 2366 +++++++++++++++++++++++++++++++
 stdio-common/vfprintf.c                 | 2351 +-----------------------------
 stdio-common/vfwprintf-internal.c       |    2 +
 stdio-common/vfwprintf.c                |   28 +-
 stdio-common/vprintf.c                  |    4 +-
 stdlib/strfrom-skeleton.c               |    2 +-
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c |   21 +-
 44 files changed, 2544 insertions(+), 2466 deletions(-)
 create mode 100644 stdio-common/vfprintf-internal.c
 create mode 100644 stdio-common/vfwprintf-internal.c

diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c
index e43a0c7cf1..b9dcb2c9c7 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
@@ -409,7 +408,7 @@ __argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)
 
       va_start (args, fmt);
       avail = fs->end - fs->p;
-      out = __vsnprintf (fs->p, avail, fmt, args);
+      out = __vsnprintf_internal (fs->p, avail, fmt, args, 0);
       va_end (args);
       if ((size_t) out >= avail)
  size_guess = out + 1;
diff --git a/argp/argp-help.c b/argp/argp-help.c
index 2b6b0775d6..6857391ce2 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_internal (&buf, fmt, ap, 0) < 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_internal (&buf, fmt, ap, 0) < 0)
  buf = NULL;
 
       __fxprintf (stream, ": %s", buf);
diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h
index 5588fe172a..5e48b5940d 100644
--- a/argp/argp-namefrob.h
+++ b/argp/argp-namefrob.h
@@ -98,8 +98,6 @@
 #define __strerror_r strerror_r
 #undef __strndup
 #define __strndup strndup
-#undef __vsnprintf
-#define __vsnprintf vsnprintf
 
 #if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED
 # define clearerr_unlocked(x) clearerr (x)
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 48b4741651..dbfebff83f 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 51ada4a4c4..0856d729d9 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -14,9 +14,6 @@ extern int __snprintf (char *__restrict __s, size_t __maxlen,
        const char *__restrict __format, ...)
      __attribute__ ((__format__ (__printf__, 3, 4)));
 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)));
 extern int __vfscanf (FILE *__restrict __s,
       const char *__restrict __format,
       __gnuc_va_list __arg)
diff --git a/include/wchar.h b/include/wchar.h
index 1db0ac8278..d0fe45c3a6 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -203,20 +203,10 @@ extern int __vfwscanf (__FILE *__restrict __s,
        __gnuc_va_list __arg)
      attribute_hidden
      /* __attribute__ ((__format__ (__wscanf__, 2, 0)) */;
-extern int __vswprintf (wchar_t *__restrict __s, size_t __n,
- const wchar_t *__restrict __format,
- __gnuc_va_list __arg)
-     attribute_hidden
-     /* __attribute__ ((__format__ (__wprintf__, 3, 0))) */;
 extern int __fwprintf (__FILE *__restrict __s,
        const wchar_t *__restrict __format, ...)
      attribute_hidden
      /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */;
-extern int __vfwprintf (__FILE *__restrict __s,
- const wchar_t *__restrict __format,
- __gnuc_va_list __arg)
-     attribute_hidden
-     /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */;
 extern int __vfwprintf_chk (FILE *__restrict __s, int __flag,
     const wchar_t *__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 6c94fe6d62..2642d71e4f 100644
--- a/libio/iolibio.h
+++ b/libio/iolibio.h
@@ -51,15 +51,7 @@ extern int _IO_sscanf (const char*, const char*, ...) __THROW;
 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..1d2ed0f9e7 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..3b1e8292b5 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..c188814ccc 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -255,8 +255,6 @@ extern int _IO_ftrylockfile (FILE *) __THROW;
 
 extern int _IO_vfscanf (FILE * __restrict, const char * __restrict,
  __gnuc_va_list, int *__restrict);
-extern int _IO_vfprintf (FILE *__restrict, const char *__restrict,
- __gnuc_va_list);
 extern __ssize_t _IO_padn (FILE *, int, __ssize_t);
 extern size_t _IO_sgetn (FILE *, void *, size_t);
 
@@ -298,8 +296,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 +315,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 f90fb2c050..c762cf9b67 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -658,12 +658,40 @@ 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)
+    attribute_hidden;
+extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap,
+ unsigned int mode_flags)
+    attribute_hidden;
+
+extern int __vasprintf_internal (char **result_ptr, const char *format,
+ va_list ap, unsigned int mode_flags)
+    attribute_hidden;
+extern int __vdprintf_internal (int d, const char *format, va_list ap,
+ unsigned int mode_flags)
+    attribute_hidden;
+extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
+       va_list ap, unsigned int mode_flags)
+    attribute_hidden;
+
+extern int __vsprintf_internal (char *string, const char *format, va_list ap,
+ unsigned int mode_flags)
+    attribute_hidden;
+extern int __vsnprintf_internal (char *string, size_t maxlen,
+ const char *format, va_list ap,
+ unsigned int mode_flags)
+    attribute_hidden;
+extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
+ const wchar_t *format, va_list ap,
+ unsigned int mode_flags)
+    attribute_hidden;
+
+/* 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..10a4b5c10c 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 6c35d2b108..fabd84f403 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_unused = (_IO_alloc_type) malloc;
   sf._s._free_buffer_unused = (_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..35b267abf8 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,17 @@ _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_weak_alias (___vsnprintf, vsnprintf)
diff --git a/libio/vswprintf.c b/libio/vswprintf.c
index bcc473d115..e415e39fc9 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 f3b3ceddbd..84bad1fafe 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..8943ffcae1 100644
--- a/stdio-common/asprintf.c
+++ b/stdio-common/asprintf.c
@@ -16,11 +16,7 @@
    <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 +28,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 8d02b71f91..a028e8edd5 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 -u stdio-common/vfprintf.c.old stdio-common/vfprintf-internal.c.new
--- stdio-common/vfprintf.c.old 2018-10-26 11:09:08.538713613 -0300
+++ stdio-common/vfprintf-internal.c.new 2018-10-26 11:08:45.130667960 -0300
@@ -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 @@
 # 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 @@
       \
  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 @@
  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 @@
       \
  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 @@
  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 @@
       /* NOTREACHED */      \
       \
     LABEL (form_number):      \
-      if (s->_flags2 & _IO_FLAGS2_FORTIFY)      \
+      if (DO_FORTIFY)      \
  {      \
   if (! readonly_format)      \
     {      \
@@ -1214,7 +1220,8 @@
 #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 @@
       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 @@
 
 /* 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 @@
      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 @@
   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 @@
     }
   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 @@
    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 @@
        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 @@
       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 @@
       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 @@
 #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 @@
   _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 @@
 
   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 -u /dev/null stdio-common/vfprintf.c.new
--- /dev/null 2018-10-15 19:30:16.914999855 -0300
+++ stdio-common/vfprintf.c.new 2018-10-26 11:08:58.758694540 -0300
@@ -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-internal.c b/stdio-common/vfwprintf-internal.c
new file mode 100644
index 0000000000..cefaf2fafe
--- /dev/null
+++ b/stdio-common/vfwprintf-internal.c
@@ -0,0 +1,2 @@
+#define COMPILE_WPRINTF 1
+#include "vfprintf-internal.c"
diff --git a/stdio-common/vfwprintf.c b/stdio-common/vfwprintf.c
index 2c3cd06fad..5d65eb7697 100644
--- a/stdio-common/vfwprintf.c
+++ b/stdio-common/vfwprintf.c
@@ -1,3 +1,25 @@
-#include <wctype.h>
-#define COMPILE_WPRINTF 1
-#include "vfprintf.c"
+/* 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..5b33604427 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_internal from libio.  */
 
   if (size == 0)
     {
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 468e23dec4..bda84af0bb 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -166,7 +166,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;
 }
@@ -175,15 +175,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
@@ -193,7 +194,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;
 }
@@ -245,7 +246,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;
 }
@@ -257,7 +258,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;
 }
@@ -269,7 +270,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;
 }
@@ -289,7 +290,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;
 }
@@ -303,7 +304,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.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 6/8] Add __vsyslog_internal, with same flags as __v*printf_internal.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
From: Zack Weinberg <[hidden email]>

Changed since v1:

  - Fixed white-space errors.
  - Removed internal declaration of __vsyslog_chk, because it's no
    longer called from within libc.  There's a call to it in the inline
    definition of vsyslog in bits/syslog.h, but that definition is only
    inlined in user code with:
      #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
  - Removed libc_hidden_def and libc_hidden_proto for vsyslog, as it is
    never called internally (it never was).
  - Added attribute_hidden to the internal declaration of
    __vsyslog_internal.  Here are the objdumps of one internal call,
    before and after this change, on a 32-bits powerpc machine:
    Without attribute_hidden:
      $ objdump -d --reloc SYSLOG-PRISTINE-glibc/libc.so | grep "<vsyslog@@GLIBC_2.4>:" -A 17
      000fc790 <vsyslog@@GLIBC_2.4>:
         fc790:       94 21 ff f0     stwu    r1,-16(r1)
         fc794:       38 c0 00 00     li      r6,0
         fc798:       7c 08 02 a6     mflr    r0
         fc79c:       42 9f 00 05     bcl     20,4*cr7+so,fc7a0 <vsyslog@@GLIBC_2.4+0x10>
         fc7a0:       93 c1 00 08     stw     r30,8(r1)
         fc7a4:       90 01 00 14     stw     r0,20(r1)
         fc7a8:       7f c8 02 a6     mflr    r30
         fc7ac:       3f de 00 0a     addis   r30,r30,10
         fc7b0:       3b de 38 54     addi    r30,r30,14420
         fc7b4:       4b ff f9 9d     bl      fc150 <__vsyslog_internal>
         fc7b8:       80 01 00 14     lwz     r0,20(r1)
         fc7bc:       83 c1 00 08     lwz     r30,8(r1)
         fc7c0:       38 21 00 10     addi    r1,r1,16
         fc7c4:       7c 08 03 a6     mtlr    r0
         fc7c8:       4e 80 00 20     blr
         fc7cc:       60 00 00 00     nop
    With attribute_hidden:
      $ objdump -d --reloc SYSLOG-PATCHED-glibc/libc.so | grep "<vsyslog@@GLIBC_2.4>:" -A 5
      000fc780 <vsyslog@@GLIBC_2.4>:
         fc780:       38 c0 00 00     li      r6,0
         fc784:       4b ff f9 cc     b       fc150 <__vsyslog_internal>
         fc788:       60 00 00 00     nop
         fc78c:       60 00 00 00     nop

-- 8< --
__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.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <[hidden email]>
            Gabriel F. T. Gomes  <[hidden email]>

        * 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 declaration and libc_hidden_proto for __vsyslog_chk.

        * sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl___vsyslog_chk):
        Use __vsyslog_internal.

Signed-off-by: Zack Weinberg <[hidden email]>
Signed-off-by: Gabriel F. T. Gomes <[hidden email]>
---
 include/sys/syslog.h                    | 19 ++++++++++-------
 misc/syslog.c                           | 36 +++++++++++++++++----------------
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c |  2 +-
 3 files changed, 32 insertions(+), 25 deletions(-)

diff --git a/include/sys/syslog.h b/include/sys/syslog.h
index 3be3189ed1..89d3479ebc 100644
--- a/include/sys/syslog.h
+++ b/include/sys/syslog.h
@@ -1,11 +1,16 @@
+#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)
 
-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
+/* __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_hidden
+     __attribute__ ((__format__ (__printf__, 2, 0)));
+
+#endif /* _ISOMAC */
+#endif /* syslog.h */
diff --git a/misc/syslog.c b/misc/syslog.c
index 644dbe80ec..3a15da41ce 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,38 @@ __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_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;
@@ -215,11 +229,8 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
     __set_errno (saved_errno);
 
     /* 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);
+       buffer.  */
+    __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 +327,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 bda84af0bb..958bbc1834 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -843,7 +843,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.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 7/8] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
From: Zack Weinberg <[hidden email]>

Changes since v1:

  - Fixed white-space errors.
  - Updated commit message.
  - In the declaration of __vsnprintf_internal, in libio/libioP.h,
    mention that passing -1 to the maxlen argument is the behavior of
    ordinary (v)sprintf function (this was already described in the
    commit message, but seems relevant to the code itself).

-- 8< --
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.

Tested for powerpc and powerpc64le.

2018-10-24  Zack Weinberg  <[hidden email]>
            Gabriel F. T. Gomes  <[hidden email]>

        * libio/iovsprintf.c (_IO_str_chk_overflow, libio_vtable):
        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.

        * 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/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_printf_chk): Directly call
        __obstack_vprintf_internal.
        (__obstack_vprintf_chk): Convert into a wrapper that calls
        __obstack_vprintf_internal (these two functions already had the
        same code) and move to new file...
        * debug/vobprintf_chk.c (__obstack_vprintf_chk): ... here.  New
        file.
        * debug/obprintf.c (__obstack_vprintf_internal): Remove the checking of
        the flags argument and the setting of _IO_FLAGS2_FORTIFY.
        * 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: Update prototype of __vsprintf_internal and add
        a comment explaining why it has the maxlen argument.
        (_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.

Signed-off-by: Zack Weinberg <[hidden email]>
Signed-off-by: Gabriel F. T. Gomes <[hidden email]>
---
 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                          | 27 ++++------
 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, 270 insertions(+), 550 deletions(-)
 create mode 100644 debug/vobprintf_chk.c

diff --git a/debug/Makefile b/debug/Makefile
index 506cebc3c4..2ef08cf23b 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 dbfebff83f..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_unused = (_IO_alloc_type) malloc;
-  sf._s._free_buffer_unused = (_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 <[hidden email]>, 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 0856d729d9..1b7da0f74d 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -216,11 +216,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 d0fe45c3a6..86506d28e9 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -216,8 +216,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 3b1e8292b5..08e4002625 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 c188814ccc..3a93807efc 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 c762cf9b67..17270b126f 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -677,9 +677,16 @@ extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
        va_list ap, unsigned int mode_flags)
     attribute_hidden;
 
-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.
+   This is the behavior of ordinary (v)sprintf functions, thus they call
+   __vsprintf_internal with that argument set to -1.  */
+extern int __vsprintf_internal (char *string, size_t maxlen,
+ const char *format, va_list ap,
  unsigned int mode_flags)
     attribute_hidden;
+
 extern int __vsnprintf_internal (char *string, size_t maxlen,
  const char *format, va_list ap,
  unsigned int mode_flags)
@@ -798,26 +805,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 7752ad5b68..b5ae868371 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 958bbc1834..59b2c9fcdd 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -179,7 +179,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;
 }
@@ -579,7 +579,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;
 }
@@ -591,7 +591,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;
 }
@@ -609,9 +609,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;
 }
@@ -622,9 +626,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;
 }
@@ -635,9 +643,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;
 }
@@ -670,7 +682,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;
 }
@@ -696,7 +709,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;
 }
@@ -723,7 +736,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.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 8/8] Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
From: Zack Weinberg <[hidden email]>

Changed since v1:

  - Removed libc_hidden_def and libc_hidden_proto from all of the
    __nldbl_*printf* function, since they are no longer called from
    within glibc, only from nldbl-*printf*.c files (libnldbl_nonshared.a)

-- 8< --
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.

Tested for powerpc and powerpc64le.

2018-10-25  Zack Weinberg  <[hidden email]>
            Gabriel F. T. Gomes  <[hidden email]>

        * 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: Remove
        libc_hidden_proto and libc_hidden_def from all __nldbl_*printf*
        and __nldbl_*syslog* functions.
        (__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.

Signed-off-by: Zack Weinberg <[hidden email]>
Signed-off-by: Gabriel F. T. Gomes <[hidden email]>
---
 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 |   4 -
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c  | 504 +++++++++++++++----------------
 5 files changed, 238 insertions(+), 277 deletions(-)

diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index b5ae868371..cf7e858e35 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 6854413fa3..64fdb8cb9e 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 4d2f3c7be2..dbd52d6d22 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -41,8 +41,4 @@
 #endif
 
 #ifndef __ASSEMBLER__
-/* 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 59b2c9fcdd..f6dd81759d 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -30,43 +30,15 @@
 
 #include "nldbl-compat.h"
 
-libc_hidden_proto (__nldbl_vfprintf)
 libc_hidden_proto (__nldbl_vsscanf)
-libc_hidden_proto (__nldbl_vsprintf)
 libc_hidden_proto (__nldbl_vfscanf)
 libc_hidden_proto (__nldbl_vfwscanf)
-libc_hidden_proto (__nldbl_vdprintf)
 libc_hidden_proto (__nldbl_vswscanf)
-libc_hidden_proto (__nldbl_vfwprintf)
-libc_hidden_proto (__nldbl_vswprintf)
-libc_hidden_proto (__nldbl_vsnprintf)
-libc_hidden_proto (__nldbl_vasprintf)
-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)
-libc_hidden_proto (__nldbl___vdprintf_chk)
-libc_hidden_proto (__nldbl___obstack_vprintf_chk)
 libc_hidden_proto (__nldbl___isoc99_vsscanf)
 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
@@ -76,14 +48,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)
 
@@ -91,28 +63,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)
 
@@ -120,28 +92,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)
 
@@ -149,14 +121,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)
 
@@ -164,123 +136,93 @@ 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)
 
 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)
-libc_hidden_def (__nldbl_vsprintf)
 
 int
 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)
 
 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)
 
 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)
 
 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
@@ -288,13 +230,8 @@ 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)
 
 int
@@ -302,33 +239,28 @@ 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)
 
 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_29)
@@ -491,42 +423,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
@@ -534,74 +475,94 @@ 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)
 
 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)
 
 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
@@ -612,14 +573,12 @@ __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)
 
 int
 attribute_compat_text_section
@@ -629,14 +588,12 @@ __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)
 
 int
 attribute_compat_text_section
@@ -646,116 +603,125 @@ __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)
 
 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)
 
 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)
 
 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)
 
 int
 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;
@@ -837,18 +803,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);
 }
 
@@ -856,17 +832,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.14.5

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 2/8] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
On Mon, 29 Oct 2018, Gabriel F. T. Gomes wrote:

>  - Reviewing the changes from vfscanf.c to vfscanf-internal.c in the
>    original patch would be vey hard, because git doesn't detect the
>    filename change.  To make review a little easier, I did as Zack did
>    and manually edited the diff.  I'll reply to this thread and attach
>    the original patch if someone wants to apply it.
>    (ping me if I forget it)

Original patch attached

original-v2-0002-Add-__vfscanf_internal-and-__vfwscanf_internal-wi.patch (192K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 5/8] Add __v*printf_internal with flags arguments.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
On Mon, 29 Oct 2018, Gabriel F. T. Gomes wrote:

>  - Reviewing the changes from vfprintf.c to vfprintf-internal.c in the
>    original patch would be vey hard, because git doesn't detect the
>    filename change.  To make review a little easier, I did as Zack did
>    and manually edited the diff.  I'll reply to this thread and attach
>    the original patch if someone wants to apply it.
>    (ping me if I forget it)

Original patch attached.

original-v2-0005-Add-__v-printf_internal-with-flags-arguments.patch (207K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 7/8] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY.

Gabriel F. T. Gomes-2
In reply to this post by Gabriel F. T. Gomes-2
On Mon, 29 Oct 2018, Gabriel F. T. Gomes wrote:

>From: Zack Weinberg <[hidden email]>
>
> 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)
> {
>
> [...]
>
>-  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
>
> [...]
>
>-  return done;
>+  return __vdprintf_internal (d, format, ap, mode);

While reviewing the first version of this patch, I noticed that it could
have an effect on bug 20231, because, after this patch, __vdprintf_chk
will call __vdprintf_internal, which has the extra check for EOF (as
reported in the bug).  However, the bug is marked as unconfirmed, and I
was unable to reproduce it with the following test case:

    #include <stdio.h>
    #include <stdarg.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    int
    main (void)
    {
      int fd, libret, sysret;
      va_list ap;
      fd = open ("/tmp/blablabla", O_RDWR | O_TRUNC | O_CREAT, S_IRWXU);
      if (fd == -1)
        perror (NULL);
      sysret = close (fd);
      if (sysret)
        perror (NULL);
      libret = vdprintf (fd, "blablabla", ap);
      if (libret != EOF)
        printf ("Bug 20231 reproduced\n");
      return 0;
    }

Maybe the test case is wrong, in which case I could fix it, then mark this
patch as solving bug 20231.  On the other hand, if the test case is
correct, we could just close bug 20231.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 0/8] Use more flags parameters instead of global bits in stdio

Zack Weinberg-2
In reply to this post by Gabriel F. T. Gomes-2
Thank you for updating these patches and doing what sounds like a
great deal of additional clean-up work.  I do not have time in the
foreseeable future to review them myself, unfortunately.

Do you think you might have time to pick up the follow-on patch that
changes scanf to be C99-conformant under _GNU_SOURCE?
(https://sourceware.org/ml/libc-alpha/2018-02/msg00608.html) It will
need quite a bit of work but I would really like to see that go into
the next release of glibc.

zw
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 0/8] Use more flags parameters instead of global bits in stdio

Gabriel F. T. Gomes-2
On Mon, 29 Oct 2018, Zack Weinberg wrote:

>Thank you for updating these patches and doing what sounds like a
>great deal of additional clean-up work.  I do not have time in the
>foreseeable future to review them myself, unfortunately.

OK, thanks for the heads up.

>Do you think you might have time to pick up the follow-on patch that
>changes scanf to be C99-conformant under _GNU_SOURCE?
>(https://sourceware.org/ml/libc-alpha/2018-02/msg00608.html) It will
>need quite a bit of work but I would really like to see that go into
>the next release of glibc.

Yes, I think I could. :)

As noted by Joseph in that thread [1], the test suite has little coverage
for -mlong-double-64, which could make it hard to review.  On the other
hand, I have been working on some new tests for -mabi=ieeelongdouble (not
yet on master), and I think I will be able to reuse them (similarly to what
Joseph suggested and I implemented for argp/err/error tests [2]).

[1] https://sourceware.org/ml/libc-alpha/2018-02/msg00630.html

[2] https://sourceware.org/ml/libc-alpha/2018-08/msg00583.html
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 1/8] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.

Adhemerval Zanella-2
In reply to this post by Gabriel F. T. Gomes-2


On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:

> From: Zack Weinberg <[hidden email]>
>
> Changed since v1:
>
>   - Added attribute hidden to __vstrfmon_l_internal.
>     On powerpc, code in the call sites changed:
>     From:
>       $ objdump -d --reloc VISIBLE-glibc/libc.so.6 | grep __nldbl___vstrfmon_l -A 13
>       001502a0 <__nldbl___vstrfmon_l>:
>         1502a0:       94 21 ff f0     stwu    r1,-16(r1)
>         1502a4:       39 00 00 01     li      r8,1
>         1502a8:       7c 08 02 a6     mflr    r0
>         1502ac:       42 9f 00 05     bcl     20,4*cr7+so,1502b0 <__nldbl___vstrfmon_l+0x10>
>         1502b0:       93 c1 00 08     stw     r30,8(r1)
>         1502b4:       90 01 00 14     stw     r0,20(r1)
>         1502b8:       7f c8 02 a6     mflr    r30
>         1502bc:       3f de 00 05     addis   r30,r30,5
>         1502c0:       3b de fd 44     addi    r30,r30,-700
>         1502c4:       4b ef b6 5d     bl      4b920 <__vstrfmon_l_internal>
>         1502c8:       80 01 00 14     lwz     r0,20(r1)
>         1502cc:       83 c1 00 08     lwz     r30,8(r1)
>         1502d0:       38 21 00 10     addi    r1,r1,16
>         1502d4:       7c 08 03 a6     mtlr    r0
>         1502d8:       4e 80 00 20     blr
>         1502dc:       60 00 00 00     nop
>     To:
>       $ objdump -d --reloc HIDDEN-glibc/libc.so.6 | grep __nldbl___vstrfmon_l -A 5
>       00150260 <__nldbl___vstrfmon_l>:
>         150260:       39 00 00 01     li      r8,1
>         150264:       4b ef b6 bc     b       4b920 <__vstrfmon_l_internal>
>         150268:       60 00 00 00     nop
>         15026c:       60 00 00 00     nop
>   - Replaced blocks of eight spaces with tabs.
>   - Added signed-off-by field with Zack's and mine names.
>   - Extended commit message and comments.
>
> -- 8< --
> On platforms where long double used to have the same format as double,
> but later switched to a different format (alpha, s390, sparc, and
> powerpc), accessing the older behavior is possible and it happens via
> __nldbl_* functions (not on the API, but accessible from header
> redirection and from compat symbols).  These functions write to the
> global flag __ldbl_is_dbl, which tells other functions that long double
> variables should be handled as double.  This patch takes the first step
> towards removing this global flag and creates __vstrfmon_l_internal,
> which takes an explicit flags parameter.
>
> 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.
>
> Tested for powerpc and powerpc64le.

Still LGTM, thanks with some nits below.

> diff --git a/include/monetary.h b/include/monetary.h
> index c130ed56a3..a226305adf 100644
> --- a/include/monetary.h
> +++ b/include/monetary.h
> @@ -2,7 +2,13 @@
>  #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)
> +  attribute_hidden;
> +
> +/* Flags for __vstrfmon_l_internal.  */
> +#define STRFMON_LDBL_IS_DBL 0x0001

Please extend the flag comment to describe what it does.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 1/8] Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.

Florian Weimer-5
In reply to this post by Gabriel F. T. Gomes-2
* Gabriel F. T. Gomes:

> Signed-off-by: Zack Weinberg <[hidden email]>
> Signed-off-by: Gabriel F. T. Gomes <[hidden email]>

We don't use DCO, but copyright assignments, so this is incorrect.

Thanks,
Florian
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 3/8] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD.

Adhemerval Zanella-2
In reply to this post by Gabriel F. T. Gomes-2


On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:

> From: Zack Weinberg <[hidden email]>
>
> Changes since v1:
>
>   - Cleared VARGARSn comments.
>   - Added signed-off-by statements.
>
> -- 8< --
> 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.
>
> Tested for powerpc and powerpc64le.

LGTM.

>
> 2018-10-16  Zack Weinberg  <[hidden email]>
>    Gabriel F. T. Gomes  <[hidden email]>
>
> * 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.
>
> Signed-off-by: Zack Weinberg <[hidden email]>
> Signed-off-by: Gabriel F. T. Gomes <[hidden email]>

We don't use DCO, but copyright assignments.

> ---
>  libio/libio.h                   |  1 -
>  libio/libioP.h                  |  5 ++---
>  stdio-common/isoc99_fscanf.c    |  7 +------
>  stdio-common/isoc99_scanf.c     | 12 +-----------
>  stdio-common/isoc99_sscanf.c    |  3 +--
>  stdio-common/isoc99_vfscanf.c   |  9 +--------
>  stdio-common/isoc99_vscanf.c    |  9 +--------
>  stdio-common/isoc99_vsscanf.c   |  3 +--
>  stdio-common/vfscanf-internal.c |  2 --
>  wcsmbs/isoc99_fwscanf.c         |  7 +------
>  wcsmbs/isoc99_swscanf.c         |  3 +--
>  wcsmbs/isoc99_vfwscanf.c        |  9 +--------
>  wcsmbs/isoc99_vswscanf.c        |  3 +--
>  wcsmbs/isoc99_vwscanf.c         |  9 +--------
>  wcsmbs/isoc99_wscanf.c          |  7 +------
>  15 files changed, 14 insertions(+), 75 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

Ok.

> diff --git a/libio/libioP.h b/libio/libioP.h
> index fa34a628fe..f90fb2c050 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -775,7 +775,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);
>  }
> @@ -789,8 +789,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
>  

Ok.

> diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
> index 4210d11f2b..d7b5993f3e 100644
> --- a/stdio-common/isoc99_fscanf.c
> +++ b/stdio-common/isoc99_fscanf.c
> @@ -20,20 +20,15 @@
>  #include <stdio.h>
>  
>  /* Read formatted input from STREAM according to the format string FORMAT.  */
> -/* VARARGS2 */
>  int
>  __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;
>  }

Ok.

> diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
> index 64c873eed9..3998322ea1 100644
> --- a/stdio-common/isoc99_scanf.c
> +++ b/stdio-common/isoc99_scanf.c
> @@ -19,26 +19,16 @@
>  #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;
>  }

Ok.

> diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
> index 2c89a03fe9..c9e5103b81 100644
> --- a/stdio-common/isoc99_sscanf.c
> +++ b/stdio-common/isoc99_sscanf.c
> @@ -26,10 +26,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;

Ok.

> diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
> index c96ca831ae..3c59c60b3e 100644
> --- a/stdio-common/isoc99_vfscanf.c
> +++ b/stdio-common/isoc99_vfscanf.c
> @@ -19,16 +19,9 @@
>  #include <stdio.h>
>  
>  /* Read formatted input from STREAM according to the format string FORMAT.  */
> -/* VARARGS2 */
>  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)

Ok.

> diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
> index 72ae72ddee..fc5d609ae7 100644
> --- a/stdio-common/isoc99_vscanf.c
> +++ b/stdio-common/isoc99_vscanf.c
> @@ -19,15 +19,8 @@
>  #include <stdio.h>
>  
>  /* Read formatted input from STDIN according to the format string FORMAT.  */
> -/* VARARGS2 */
>  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);
>  }

Ok.

> 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)

Ok.

> diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
> index 1ae37a2a11..dc341b0b1f 100644
> --- a/stdio-common/vfscanf-internal.c
> +++ b/stdio-common/vfscanf-internal.c
> @@ -337,8 +337,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);

Ok.

> diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
> index 00b07dd48e..5829607916 100644
> --- a/wcsmbs/isoc99_fwscanf.c
> +++ b/wcsmbs/isoc99_fwscanf.c
> @@ -21,20 +21,15 @@
>  #include <wchar.h>
>  
>  /* Read formatted input from STREAM according to the format string FORMAT.  */
> -/* VARARGS2 */
>  int
>  __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;
>  }

Ok.

> 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;

Ok.

> diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
> index f70c6b596d..715d354b5a 100644
> --- a/wcsmbs/isoc99_vfwscanf.c
> +++ b/wcsmbs/isoc99_vfwscanf.c
> @@ -20,16 +20,9 @@
>  #include <wchar.h>
>  
>  /* Read formatted input from STREAM according to the format string FORMAT.  */
> -/* VARARGS2 */
>  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)

Ok.

> 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)

Ok.

> diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
> index eb22c8acae..3ac3182608 100644
> --- a/wcsmbs/isoc99_vwscanf.c
> +++ b/wcsmbs/isoc99_vwscanf.c
> @@ -20,15 +20,8 @@
>  #include <wchar.h>
>  
>  /* Read formatted input from STDIN according to the format string FORMAT.  */
> -/* VARARGS2 */
>  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);
>  }

Ok.

> diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
> index 59f80d78fb..b9418f7912 100644
> --- a/wcsmbs/isoc99_wscanf.c
> +++ b/wcsmbs/isoc99_wscanf.c
> @@ -22,20 +22,15 @@
>  
>  
>  /* Read formatted input from stdin according to the format string FORMAT.  */
> -/* VARARGS1 */
>  int
>  __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;
>  }
>

Ok.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 4/8] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.

Adhemerval Zanella-2
In reply to this post by Gabriel F. T. Gomes-2


On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:

> From: Zack Weinberg <[hidden email]>
>
> Changed since v1:
>
>   - In __nldbl___isoc99_vwscanf, called __vfwscanf_internal directly
>     (missing (accidentally?) from the previous version).
>   - Broke long lines.
>   - Changed name of variable (from rv to ret), since the rationale for
>     making these changes to variables names is consistency.
>   - Added signed-off-by statements.
>
> -- 8< --
> 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.
>
> Tested for powerpc and powerpc64le.

LGTM.

>
> 2018-10-16  Zack Weinberg  <[hidden email]>
>    Gabriel F. T. Gomes  <[hidden email]>
>
> * 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.
>
> Signed-off-by: Zack Weinberg <[hidden email]>
> Signed-off-by: Gabriel F. T. Gomes <[hidden email]>

We don't use DCO, but copyright assignments.

> ---
>  stdio-common/vfscanf-internal.c         |   3 -
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 251 +++++++++++++++-----------------
>  2 files changed, 121 insertions(+), 133 deletions(-)
>
> diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
> index dc341b0b1f..f989f8dc07 100644
> --- a/stdio-common/vfscanf-internal.c
> +++ b/stdio-common/vfscanf-internal.c
> @@ -334,9 +334,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);

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 91ea27a423..468e23dec4 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 <math.h>
>  #include <wchar.h>
>  #include <printf.h>
> @@ -335,13 +335,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
>  

Ok.

> @@ -349,11 +346,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)

Ok.

> @@ -362,26 +355,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)
>  

Ok.

>  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)

Ok.

> @@ -390,46 +383,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);
>  }
>  

Ok.

>  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;
>  }
>  

Ok.

>  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)
>  

Ok.

> @@ -437,25 +426,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;
>  }
>  

Ok.

>  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)
>  

Ok.

> @@ -463,35 +455,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);
>  }
>  

Ok.

>  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;
>  }
>  

Ok.

>  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;
>  }
>  

Ok.

>  int
> @@ -866,11 +858,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)
>  

Ok.

> @@ -878,25 +866,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;
>  }
>  

Ok.

>  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)

Ok.

>  
> @@ -904,46 +893,44 @@ 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);
>  }
>  

Ok.

>  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;
>  }
>  

Ok.

>  int
>  attribute_compat_text_section
>  __nldbl___isoc99_scanf (const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___isoc99_vfscanf (stdin, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfscanf_internal (stdin, fmt, ap,
> +    SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  

Ok.

>  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)
>  

Ok.

> @@ -951,26 +938,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;
>  }
>  

Ok.

>  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)

Ok.

>  
> @@ -978,35 +967,37 @@ int
>  attribute_compat_text_section
>  __nldbl___isoc99_vwscanf (const wchar_t *fmt, va_list ap)
>  {
> -  return __nldbl___isoc99_vfwscanf (stdin, fmt, ap);
> +  return __vfwscanf_internal (stdin, fmt, ap,
> +     SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
>  }
>  

Ok.

>  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;
>  }
>  

Ok.

>  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)
>

Ok.
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 2/8] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.

Adhemerval Zanella-2
In reply to this post by Gabriel F. T. Gomes-2


On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:

> From: Zack Weinberg <[hidden email]>
>
> Changed since v1:
>
>   - Added one line comment to new files.
>   - In nldbl-compat.c, added explanation for the need to use
>     '#if SHLIB_COMPAT' within 'if LONG_DOUBLE_COMPAT'.  Also moved the
>     block further down, for stylistic reasons [1].
>   - Added attribute_hidden to the internal (libioP.h) declarations of
>     __vfscanf_internal and __vfwscanf_internal [2].
>   - Added comment explaining the reason for the use of SHLIB_COMPAT on
>     stdio-common/iovfscanf.c and stdio-common/iovfwscanf.c.
>   - Converted the definition of ldbl_compat_symbol from an expansion of
>     compat_symbol to '...', because ldbl_compat_symbol is also not
>     supposed to be used outside of '#if SHLIB_COMPAT' statements.  In my
>     opinion, it's better to make this clear in the definition of
>     ldbl_compat_symbol itself, rather than having to go to the
>     definition of compat_symbol to learn this (if people think that this
>     is not the best option, I can revert this change (In that case, the
>     definition of ldbl_compat_symbol could be moved outside the '#if
>     SHARED' block).  Added a comment with this explanation.
>   - Added signed-off-by statements.
>   - Replaced 2.28 with 2.29 to adjust for the next release.
>
> Not changed since v1:
>
>   - Florian suggested that the need for ldbl_compat_symbol is
>     questionable, because we could define LONG_DOUBLE_COMPAT_VERSION to
>     GLIBC_2_0 by default (pretending that the long double transition
>     happened for all other platforms), then use it in compat_symbol
>     calls, which would create the compat symbols for _IO_vfscanf and
>     _IO_vfwscanf with that version.
>     That would work, because all the functions that will use
>     ldbl_compat_symbol after this patch set were actually introduced
>     before GLIBC_2_0.  However, for newer functions, such as swscanf,
>     that wouldn't work, if we ever need to do something similar.
>
> Additional note for review:
>
>   - Reviewing the changes from vfscanf.c to vfscanf-internal.c in the
>     original patch would be vey hard, because git doesn't detect the
>     filename change.  To make review a little easier, I did as Zack did
>     and manually edited the diff.  I'll reply to this thread and attach
>     the original patch if someone wants to apply it.
>     (ping me if I forget it)

I would advise to avoid it, it is error-prone and we do have tools to
handle it.  One option is to use -C and -M git options with a higher s
imilarity index, for instance on this patch using:

git format-patch -M90% -C -1

it generates the expected result:

[...]
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf-internal.c
similarity index 98%
copy from stdio-common/vfscanf.c
copy to stdio-common/vfscanf-internal.c
index 1ce836a324..1ae37a2a11 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf-internal.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Internal functions for the *scanf* implementation.
+   Copyright (C) 1991-2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
[...]


>
> [1] https://sourceware.org/ml/libc-alpha/2018-03/msg00309.html
>
> [2] As a result, internal calls to __vfscanf_internal, on powerpc, do
>     not use the PLT, the following blocks show the difference:
>
>     Without __attribute__ (hidden):
>       $ objdump -d --reloc VFSCANF-VISIBLE-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 17
>       0014ea00 <__nldbl___vfscanf>:
>         14ea00:       94 21 ff f0     stwu    r1,-16(r1)
>         14ea04:       38 c0 00 01     li      r6,1
>         14ea08:       7c 08 02 a6     mflr    r0
>         14ea0c:       42 9f 00 05     bcl     20,4*cr7+so,14ea10 <__nldbl___vfscanf+0x10>
>         14ea10:       93 c1 00 08     stw     r30,8(r1)
>         14ea14:       90 01 00 14     stw     r0,20(r1)
>         14ea18:       7f c8 02 a6     mflr    r30
>         14ea1c:       3f de 00 05     addis   r30,r30,5
>         14ea20:       3b de 15 e4     addi    r30,r30,5604
>         14ea24:       4b f0 b8 0d     bl      5a230 <__vfscanf_internal>
>         14ea28:       80 01 00 14     lwz     r0,20(r1)
>         14ea2c:       83 c1 00 08     lwz     r30,8(r1)
>         14ea30:       38 21 00 10     addi    r1,r1,16
>         14ea34:       7c 08 03 a6     mtlr    r0
>         14ea38:       4e 80 00 20     blr
>         14ea3c:       60 00 00 00     nop
>
>     With __attribute__ (hidden):
>       $ objdump -d --reloc VFSCANF-HIDDEN-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 5
>       0014e8b0 <__nldbl___vfscanf>:
>         14e8b0:       38 c0 00 01     li      r6,1
>         14e8b4:       4b f0 b8 bc     b       5a170 <__vfscanf_internal>
>         14e8b8:       60 00 00 00     nop
>         14e8bc:       60 00 00 00     nop
>
> -- 8< --
> 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 with some nits below.

>
> Tested for powerpc and powerpc64le.
>
> 2018-10-16  Zack Weinberg  <[hidden email]>
>    Gabriel F. T. Gomes  <[hidden email]>
>
> * 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_WSCANF; don't define any other public symbols.
> Remove errval and code to set errp.
> 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: New file defining the public entry
> point vfscanf, which calls __vfscanf_internal.
> * stdio-common/vfwscanf.c: New file defining the public entry
> point vfwscanf, which calls __vfwscanf_internal.
>
> * stdio-common/iovfscanf.c: New file.
> * stdio-common/iovfwscanf.c: Likewise.
>
> * stdio-common/Makefile (routines): Add vfscanf-internal,
> vfwscanf-internal, iovfscanf, iovfwscanf.
> * stdio-common/Versions: Mention GLIBC_2.29, 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.
> Call __vfscanf_internal, instead of _IO_vfscanf.
> (__nldbl___vfscanf): Call __vfscanf_internal, instead of
> _IO_vfscanf.
> (__nldbl_vfwscanf): Call __vfwscanf_internal, instead of
> _IO_vfwscanf.
>
> * libio/iovsscanf.c: Clean up includes, when possible.  Use
> _IO_strfile_read or _IO_strfile_readw, when needed.  Call
> __vfscanf_internal or __vfwscanf_internal directly.
> * libio/iovswscanf.c: Likewise.
> * libio/swscanf.c: Likewise.
> * libio/vscanf.c: Likewise.
> * libio/vwscanf.c: Likewise.
> * libio/wscanf.c: Likewise.
> * stdio-common/isoc99_fscanf.c: Likewise.
> * stdio-common/isoc99_scanf.c: Likewise.
> * stdio-common/isoc99_sscanf.c: Likewise.
> * stdio-common/isoc99_vfscanf.c: Likewise.
> * stdio-common/isoc99_vscanf.c: Likewise.
> * stdio-common/isoc99_vsscanf.c: Likewise.
> * stdio-common/scanf.c: Likewise.
> * stdio-common/sscanf.c: Likewise.
> * wcsmbs/isoc99_fwscanf.c: Likewise.
> * wcsmbs/isoc99_swscanf.c: Likewise.
> * wcsmbs/isoc99_vfwscanf.c: Likewise.
> * wcsmbs/isoc99_vswscanf.c: Likewise.
> * wcsmbs/isoc99_vwscanf.c: Likewise.
> * wcsmbs/isoc99_wscanf.c: Likewise.
>
> Signed-off-by: Zack Weinberg <[hidden email]>
> Signed-off-by: Gabriel F. T. Gomes <[hidden email]>

As Florian has said, we don't use DCO, but copyright assignments.


> ---
>  libio/iovsscanf.c                        |   12 +-
>  libio/iovswscanf.c                       |   14 +-
>  libio/libio.h                            |    1 -
>  libio/libioP.h                           |   11 +
>  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                 |   38 +
>  stdio-common/iovfwscanf.c                |   38 +
>  stdio-common/isoc99_fscanf.c             |    2 +-
>  stdio-common/isoc99_scanf.c              |    2 +-
>  stdio-common/isoc99_sscanf.c             |    9 +-
>  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-internal.c          | 3050 ++++++++++++++++++++++++++++++
>  stdio-common/vfscanf.c                   | 3042 +----------------------------
>  stdio-common/vfwscanf-internal.c         |    2 +
>  stdio-common/vfwscanf.c                  |   28 +-
>  sysdeps/generic/math_ldbl_opt.h          |    4 +
>  sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h |    5 +
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c  |   17 +-
>  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, 3273 insertions(+), 3128 deletions(-)
>  create mode 100644 stdio-common/iovfscanf.c
>  create mode 100644 stdio-common/iovfwscanf.c
>  create mode 100644 stdio-common/vfscanf-internal.c
>  create mode 100644 stdio-common/vfwscanf-internal.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
> diff --git a/libio/libioP.h b/libio/libioP.h
> index df2633d858..fa34a628fe 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -704,6 +704,17 @@ 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

As before, please describe what actually the flag does.

> +
> +extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
> +       unsigned int flags)
> +  attribute_hidden;
> +extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
> + unsigned int flags)
> +  attribute_hidden;
> +
>  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 75caac2af5..62900a7128 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);
> @@ -80,3 +82,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.  */

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 a10f12ab3c..f3b3ceddbd 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 b8217578c8..522f302198 100644
> --- a/stdio-common/Versions
> +++ b/stdio-common/Versions
> @@ -60,6 +60,9 @@ libc {
>    GLIBC_2.28 {
>      renameat2;
>    }
> +  GLIBC_2.29 {
> +    # SHLIB_COMPAT(GLIBC_2_0, GLIBC_2_29) used in iovfscanf.c etc.
> +  }
>    GLIBC_PRIVATE {
>      # global variables
>      _itoa_lower_digits;

Ok.

> diff --git a/stdio-common/iovfscanf.c b/stdio-common/iovfscanf.c
> new file mode 100644
> index 0000000000..77e698f665
> --- /dev/null
> +++ b/stdio-common/iovfscanf.c
> @@ -0,0 +1,38 @@
> +/* Implementation and symbols for _IO_vfscanf.
> +   Copyright (C) 2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <libioP.h>
> +#include <shlib-compat.h>
> +
> +/* This function is provided for ports older than GLIBC 2.29 because
> +   external callers could theoretically exist.  Newer ports do not need,
> +   since it is not part of the API.  */
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
> +
> +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

Ok.

> diff --git a/stdio-common/iovfwscanf.c b/stdio-common/iovfwscanf.c
> new file mode 100644
> index 0000000000..26a57788cb
> --- /dev/null
> +++ b/stdio-common/iovfwscanf.c
> @@ -0,0 +1,38 @@
> +/* Implementation and symbols for _IO_vfwscanf.
> +   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>
> +
> +/* This function is provided for ports older than GLIBC 2.29 because
> +   external callers could theoretically exist.  Newer ports do not need,
> +   since it is not part of the API.  */
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
> +
> +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

Ok.

> 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..2c89a03fe9 100644
> --- a/stdio-common/isoc99_sscanf.c
> +++ b/stdio-common/isoc99_sscanf.c
> @@ -16,19 +16,20 @@
>     <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 */
>  int
>  __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 -u stdio-common/vfscanf.c.old stdio-common/vfscanf-internal.c.new
> --- stdio-common/vfscanf.c.old 2018-10-25 17:21:09.232711752 -0300
> +++ stdio-common/vfscanf-internal.c.new 2018-10-25 17:21:24.143739981 -0300
> @@ -1,4 +1,5 @@
> -/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +/* Internal functions for the *scanf* implementation.
> +   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
> @@ -132,16 +133,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 +265,12 @@
>     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 +281,6 @@
>    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 +332,14 @@
>    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))

Do we really gain anything using these defines? I tend to frown on macros
that use internal named variables instead of set them as arguments. Also
this is quite short, I think it is more readable to just use the comparison
directly.

> +  /* 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 +571,7 @@
>      }
>    /* 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;
> @@ -2423,7 +2428,7 @@
>        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);
> @@ -3018,8 +3023,6 @@
>    UNLOCK_STREAM (s);
>  
>    scratch_buffer_free (&charbuf.scratch);
> -  if (errp != NULL)
> -    *errp |= errval;
>  
>    if (__glibc_unlikely (done == EOF))
>      {
> @@ -3045,23 +3048,3 @@
>      }
>    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 -u /dev/null stdio-common/vfscanf.c.new
> --- /dev/null 2018-10-15 19:30:16.914999855 -0300
> +++ stdio-common/vfscanf.c.new 2018-10-25 17:21:39.355768779 -0300

This manually change diff is confusing, since most of the original patch
is code removal.

> @@ -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)

Ok.

> diff --git a/stdio-common/vfwscanf-internal.c b/stdio-common/vfwscanf-internal.c
> new file mode 100644
> index 0000000000..26c89270b7
> --- /dev/null
> +++ b/stdio-common/vfwscanf-internal.c
> @@ -0,0 +1,2 @@
> +#define COMPILE_WSCANF 1
> +#include "vfscanf-internal.c"

Ok.

> diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
> index 26b1a66608..f1c70ad6b3 100644
> --- a/stdio-common/vfwscanf.c
> +++ b/stdio-common/vfwscanf.c
> @@ -1,2 +1,26 @@
> -#define COMPILE_WSCANF 1
> -#include "vfscanf.c"
> +/* Implementation and symbols for vfwscanf.
> +   Copyright (C) 1991-2018 Free Software Foundation, Inc.

I think you should use just 2018 here.

> +   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)

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

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> index 61ba784f86..4d2f3c7be2 100644
> --- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> +++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> @@ -20,10 +20,15 @@
>    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)
> +/* Same as compat_symbol, ldbl_compat_symbol is not to be used outside
> +   '#if SHLIB_COMPAT' statement and should fail if it is.  */
> +# define ldbl_compat_symbol(lib, local, symbol, version) ...

Why not use an _Static_assert(0, "ldbl_compat_symbol should be used inside SHLIB_COMPAT")?

>  # 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 7a1e89c1a3..91ea27a423 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -330,16 +330,20 @@ __nldbl_wprintf (const wchar_t *fmt, ...)
>    return done;
>  }
>  
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
>  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
> @@ -347,7 +351,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;
>  }
> @@ -423,7 +427,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;
>  }
> @@ -1027,7 +1031,6 @@ 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);
> -compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
>  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);
> @@ -1040,6 +1043,12 @@ compat_symbol (libc, __nldbl___printf_fp, __printf_fp, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_strfmon, strfmon, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_syslog, syslog, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_vsyslog, vsyslog, GLIBC_2_0);
> +/* This function is not in public headers, but was exported until
> +   version 2.29.  For platforms that are newer than that, there's no
> +   need to expose the symbol.  */
> +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
> +compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
> +# endif
>  #endif
>  #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_1)
>  compat_symbol (libc, __nldbl___asprintf, __asprintf, GLIBC_2_1);

Ok.

> 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.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 5/8] Add __v*printf_internal with flags arguments.

Adhemerval Zanella-2
In reply to this post by Gabriel F. T. Gomes-2


On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:

> From: Zack Weinberg <[hidden email]>
>
> Changes since v1:
>
>   - Fixed white-space errors.
>   - In argp_fmtstream_printf, do not call __vsnprintf, instead call
>     __vsnprintf_internal passing 0 to mode_flags.  With this change,
>     there's no need to use libc_hidden_{proto,def} for __vsnprintf
>     (because it doesn't have other internal callers).  Also, it is no
>     longer necessary to '#undef __vsnprintf' and '#define __vsnprintf
>     vsnprintf' in argp-namefrob.h.
>   - In __argp_error and __argp_failure call __vasprintf_internal
>     directly, passing 0 (zero) to mode_flags, since these functions do
>     not currently have support for long double with the same format as
>     double (a subsequent patch in my personal branch provides that and
>     adjusts the call accordingly).
>     With this change, there's no need to use libc_hidden_{proto,def} for
>     __vasprintf.  It is also no longer required to '#undef __vasprintf'
>     and '#define __vasprintf vasprintf' in argp-namefrob.h.
>   - Declarations of _IO_vfprintf, _IO_vsprintf, __vfwprintf, and
>     __vswprintf removed from the internal headers: libio.h, iolibio.h,
>     and include/wchar.h, since they are no longer called from within
>     glibc.
>   - Added attribute_hidden to all new internal functions, since they are
>     all called from within libc.
>     Here are the objdumps of one such calls, before and after this
>     change, on a 32-bits powerpc machine:
>     Without attribute_hidden:
>       $ objdump -d --reloc INTERNAL-VISIBLE-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 21
>       000523a0 <vprintf@@GLIBC_2.4>:
>          523a0:       94 21 ff f0     stwu    r1,-16(r1)
>          523a4:       7c 85 23 78     mr      r5,r4
>          523a8:       7c 08 02 a6     mflr    r0
>          523ac:       42 9f 00 05     bcl     20,4*cr7+so,523b0 <vprintf@@GLIBC_2.4+0x10>
>          523b0:       7c 64 1b 78     mr      r4,r3
>          523b4:       38 c0 00 00     li      r6,0
>          523b8:       93 c1 00 08     stw     r30,8(r1)
>          523bc:       90 01 00 14     stw     r0,20(r1)
>          523c0:       7f c8 02 a6     mflr    r30
>          523c4:       3f de 00 15     addis   r30,r30,21
>          523c8:       3b de dc 44     addi    r30,r30,-9148
>          523cc:       81 3e fe 80     lwz     r9,-384(r30)
>          523d0:       80 69 00 00     lwz     r3,0(r9)
>          523d4:       48 01 52 bd     bl      67690 <__vfprintf_internal>
>          523d8:       80 01 00 14     lwz     r0,20(r1)
>          523dc:       83 c1 00 08     lwz     r30,8(r1)
>          523e0:       38 21 00 10     addi    r1,r1,16
>          523e4:       7c 08 03 a6     mtlr    r0
>          523e8:       4e 80 00 20     blr
>     With attribute_hidden:
>       $ objdump -d --reloc INTERNAL-HIDDEN-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 18
>       00052370 <vprintf@@GLIBC_2.4>:
>          52370:       94 21 ff f0     stwu    r1,-16(r1)
>          52374:       7c 85 23 78     mr      r5,r4
>          52378:       7d 88 02 a6     mflr    r12
>          5237c:       42 9f 00 05     bcl     20,4*cr7+so,52380 <vprintf@@GLIBC_2.4+0x10>
>          52380:       7c 64 1b 78     mr      r4,r3
>          52384:       38 c0 00 00     li      r6,0
>          52388:       93 c1 00 08     stw     r30,8(r1)
>          5238c:       7f c8 02 a6     mflr    r30
>          52390:       7d 88 03 a6     mtlr    r12
>          52394:       3f de 00 15     addis   r30,r30,21
>          52398:       3b de dc 74     addi    r30,r30,-9100
>          5239c:       81 3e fe 80     lwz     r9,-384(r30)
>          523a0:       83 c1 00 08     lwz     r30,8(r1)
>          523a4:       80 69 00 00     lwz     r3,0(r9)
>          523a8:       38 21 00 10     addi    r1,r1,16
>          523ac:       48 01 52 24     b       675d0 <__vfprintf_internal>
>     The branch-and-link instruction is gone.
>
> Additional note for review:
>
>   - Reviewing the changes from vfprintf.c to vfprintf-internal.c in the
>     original patch would be vey hard, because git doesn't detect the
>     filename change.  To make review a little easier, I did as Zack did
>     and manually edited the diff.  I'll reply to this thread and attach
>     the original patch if someone wants to apply it.
>     (ping me if I forget it)
>
> -- 8< --
> 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 and
> _IO_vfprintf *are* exported, so those two stick around.
>
> Summary for the changes to each of the affected symbols:
>
>   _IO_vfprintf, _IO_vsprintf:
>     All internal calls removed, thus the internal declarations, as well
>     as uses of libc_hidden_proto and libc_hidden_def, were also removed.
>     The external symbol is now exposed via uses of ldbl_strong_alias
>     to __vfprintf_internal and __vsprintf_internal, respectively.
>
>   _IO_vasprintf, _IO_vdprintf, _IO_vsnprintf,
>   _IO_vfwprintf, _IO_vswprintf,
>   _IO_obstack_vprintf, _IO_obstack_printf:
>     All internal calls removed, thus declaration in internal headers
>     were also removed.  They were never exported, so there are no
>     aliases tying them to the internal functions.  I.e.: entirely gone.
>
>   __vsnprintf:
>     Internal calls were always preceded by macros such as
>       #define __vsnprintf _IO_vsnprintf, and
>       #define __vsnprintf vsnprintf
>     The macros were removed and their uses replaced with calls to the
>     new internal function __vsnprintf_internal.  Since there were no
>     internal calls, the internal declaration was also removed.  The
>     external symbol is preserved with ldbl_weak_alias to ___vsnprintf.
>
>   __vfwprintf:
>     All internal calls converted into calls to __vfwprintf_internal,
>     thus the internal declaration was removed.  The function is now a
>     wrapper that calls __vfwprintf_internal.  The external symbol is
>     preserved.
>
>   __vswprintf:
>     Similarly, but no external symbol.
>
>   __vasprintf, __vdprintf, __vfprintf, __vsprintf:
>     New internal wrappers.  Not exported.
>
>   vasprintf, vdprintf, vfprintf, vsprintf, vsnprintf,
>   vfwprintf, vswprintf,
>   obstack_vprintf, obstack_printf:
>     These functions used to be aliases to the respective _IO_* function,
>     they are now aliases to their respective __* functions.
>
> Tested for powerpc and powerpc64le.

Look good in general with some nits below.

>
> 2018-10-16  Zack Weinberg  <[hidden email]>
>    Gabriel F. T. Gomes  <[hidden email]>
>
> * 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.
> Remove use of ldbl_hidden_def, since __vsnprintf is no longer
> called internally.
> * 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 and declaration for
> _IO_vfprintf.
> Remove declaration of _IO_vfwprintf.
> * libio/iolibio.h: Remove libc_hidden_proto and declaration for
> _IO_vsprintf.
> Remove declarations of _IO_vswprintf, _IO_obstack_printf, and
> _IO_obstack_printf.
> * include/stdio.h: Add prototype for __vasprintf.
> (__vsnprintf): Remove declaration, because there are no more
> internal calls.
> * include/wchar.h (__vfwprintf, __vswprintf): Remove
> declaration, because there are no more internal calls.
>
> * argp/argp-fmtstream.c (__argp_fmtstream_printf): Use
> __vsnprintf_internal, instead of _IO_vsnprintf.
> * argp/argp-help.c (__argp_error, __argp_failure): Use
> __vasprintf_internal, instead of _IO_vasprintf.
> * argp/argp-namefrob.h (__vsnprintf): Do not undefined then
> redefine, because there are no more internal calls.
>
> Signed-off-by: Zack Weinberg <[hidden email]>
> Signed-off-by: Gabriel F. T. Gomes <[hidden email]>

We don't use DCO, but copyright assignments.

> ---
>  argp/argp-fmtstream.c                   |    3 +-
>  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                         |    3 -
>  include/wchar.h                         |   10 -
>  libio/fwprintf.c                        |    2 +-
>  libio/iolibio.h                         |    8 -
>  libio/iovdprintf.c                      |   13 +-
>  libio/iovsprintf.c                      |   16 +-
>  libio/libio.h                           |    5 -
>  libio/libioP.h                          |   40 +-
>  libio/obprintf.c                        |   19 +-
>  libio/swprintf.c                        |    2 +-
>  libio/vasprintf.c                       |   20 +-
>  libio/vsnprintf.c                       |   16 +-
>  libio/vswprintf.c                       |   16 +-
>  libio/vwprintf.c                        |    2 +-
>  libio/wprintf.c                         |    2 +-
>  stdio-common/Makefile                   |    3 +-
>  stdio-common/asprintf.c                 |    6 +-
>  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-internal.c        | 2366 +++++++++++++++++++++++++++++++
>  stdio-common/vfprintf.c                 | 2351 +-----------------------------
>  stdio-common/vfwprintf-internal.c       |    2 +
>  stdio-common/vfwprintf.c                |   28 +-
>  stdio-common/vprintf.c                  |    4 +-
>  stdlib/strfrom-skeleton.c               |    2 +-
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c |   21 +-
>  44 files changed, 2544 insertions(+), 2466 deletions(-)
>  create mode 100644 stdio-common/vfprintf-internal.c
>  create mode 100644 stdio-common/vfwprintf-internal.c
>
> diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c
> index e43a0c7cf1..b9dcb2c9c7 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
> @@ -409,7 +408,7 @@ __argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)
>  
>        va_start (args, fmt);
>        avail = fs->end - fs->p;
> -      out = __vsnprintf (fs->p, avail, fmt, args);
> +      out = __vsnprintf_internal (fs->p, avail, fmt, args, 0);
>        va_end (args);
>        if ((size_t) out >= avail)
>   size_guess = out + 1;

Ok.

> diff --git a/argp/argp-help.c b/argp/argp-help.c
> index 2b6b0775d6..6857391ce2 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_internal (&buf, fmt, ap, 0) < 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_internal (&buf, fmt, ap, 0) < 0)
>   buf = NULL;
>  
>        __fxprintf (stream, ": %s", buf);

Ok.

> diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h
> index 5588fe172a..5e48b5940d 100644
> --- a/argp/argp-namefrob.h
> +++ b/argp/argp-namefrob.h
> @@ -98,8 +98,6 @@
>  #define __strerror_r strerror_r
>  #undef __strndup
>  #define __strndup strndup
> -#undef __vsnprintf
> -#define __vsnprintf vsnprintf
>  
>  #if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED
>  # define clearerr_unlocked(x) clearerr (x)

Ok.

> 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)

Ok.

> 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

Ok.

> diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
> index 48b4741651..dbfebff83f 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);

Ok.

> 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);
>  

Ok.

> 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;

Ok.

> 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';

Ok.

> 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;

Ok.

> 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

Ok.

> 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;

Ok.

> 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)

Ok.

> 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;
>  }

Ok.

> diff --git a/include/stdio.h b/include/stdio.h
> index 51ada4a4c4..0856d729d9 100644
> --- a/include/stdio.h
> +++ b/include/stdio.h
> @@ -14,9 +14,6 @@ extern int __snprintf (char *__restrict __s, size_t __maxlen,
>         const char *__restrict __format, ...)
>       __attribute__ ((__format__ (__printf__, 3, 4)));
>  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)));
>  extern int __vfscanf (FILE *__restrict __s,
>        const char *__restrict __format,
>        __gnuc_va_list __arg)

Ok.

> diff --git a/include/wchar.h b/include/wchar.h
> index 1db0ac8278..d0fe45c3a6 100644
> --- a/include/wchar.h
> +++ b/include/wchar.h
> @@ -203,20 +203,10 @@ extern int __vfwscanf (__FILE *__restrict __s,
>         __gnuc_va_list __arg)
>       attribute_hidden
>       /* __attribute__ ((__format__ (__wscanf__, 2, 0)) */;
> -extern int __vswprintf (wchar_t *__restrict __s, size_t __n,
> - const wchar_t *__restrict __format,
> - __gnuc_va_list __arg)
> -     attribute_hidden
> -     /* __attribute__ ((__format__ (__wprintf__, 3, 0))) */;
>  extern int __fwprintf (__FILE *__restrict __s,
>         const wchar_t *__restrict __format, ...)
>       attribute_hidden
>       /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */;
> -extern int __vfwprintf (__FILE *__restrict __s,
> - const wchar_t *__restrict __format,
> - __gnuc_va_list __arg)
> -     attribute_hidden
> -     /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */;
>  extern int __vfwprintf_chk (FILE *__restrict __s, int __flag,
>      const wchar_t *__restrict __format,
>      __gnuc_va_list __arg)

Ok.

> 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;

Ok.

> diff --git a/libio/iolibio.h b/libio/iolibio.h
> index 6c94fe6d62..2642d71e4f 100644
> --- a/libio/iolibio.h
> +++ b/libio/iolibio.h
> @@ -51,15 +51,7 @@ extern int _IO_sscanf (const char*, const char*, ...) __THROW;
>  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) \

Ok.

> diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c
> index 78a3a2bd15..1d2ed0f9e7 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)

Ok.

> diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
> index 4def251701..3b1e8292b5 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)

Ok.

> diff --git a/libio/libio.h b/libio/libio.h
> index 30cb7d784f..c188814ccc 100644
> --- a/libio/libio.h
> +++ b/libio/libio.h
> @@ -255,8 +255,6 @@ extern int _IO_ftrylockfile (FILE *) __THROW;
>  
>  extern int _IO_vfscanf (FILE * __restrict, const char * __restrict,
>   __gnuc_va_list, int *__restrict);
> -extern int _IO_vfprintf (FILE *__restrict, const char *__restrict,
> - __gnuc_va_list);
>  extern __ssize_t _IO_padn (FILE *, int, __ssize_t);
>  extern size_t _IO_sgetn (FILE *, void *, size_t);
>  
> @@ -298,8 +296,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 +315,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

Ok.

> diff --git a/libio/libioP.h b/libio/libioP.h
> index f90fb2c050..c762cf9b67 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -658,12 +658,40 @@ 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)
> +    attribute_hidden;
> +extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap,
> + unsigned int mode_flags)
> +    attribute_hidden;
> +
> +extern int __vasprintf_internal (char **result_ptr, const char *format,
> + va_list ap, unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vdprintf_internal (int d, const char *format, va_list ap,
> + unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
> +       va_list ap, unsigned int mode_flags)
> +    attribute_hidden;
> +
> +extern int __vsprintf_internal (char *string, const char *format, va_list ap,
> + unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vsnprintf_internal (char *string, size_t maxlen,
> + const char *format, va_list ap,
> + unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
> + const wchar_t *format, va_list ap,
> + unsigned int mode_flags)
> +    attribute_hidden;
> +
> +/* Flags for __v*printf_internal.  */
> +#define PRINTF_LDBL_IS_DBL 0x0001
> +#define PRINTF_FORTIFY     0x0002

Please extend the flags comment to describe what they do.

>  
>  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..10a4b5c10c 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)

Ok.

> 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;

Ok.

> diff --git a/libio/vasprintf.c b/libio/vasprintf.c
> index 6c35d2b108..fabd84f403 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_unused = (_IO_alloc_type) malloc;
>    sf._s._free_buffer_unused = (_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)

Ok.

> diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
> index 39b5500528..35b267abf8 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,17 @@ _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_weak_alias (___vsnprintf, vsnprintf)

Ok.

> diff --git a/libio/vswprintf.c b/libio/vswprintf.c
> index bcc473d115..e415e39fc9 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)

Ok.

> 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)

Ok.

> 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;

Ok.

> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index f3b3ceddbd..84bad1fafe 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
>  

Ok.

> diff --git a/stdio-common/asprintf.c b/stdio-common/asprintf.c
> index bff858e657..8943ffcae1 100644
> --- a/stdio-common/asprintf.c
> +++ b/stdio-common/asprintf.c
> @@ -16,11 +16,7 @@
>     <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 +28,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;

Ok.

> 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;

Ok.

> diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c
> index 8d02b71f91..a028e8edd5 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);

Ok.

> 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);

Ok.

> 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;

Ok.

> 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;

Ok.

> diff -u stdio-common/vfprintf.c.old stdio-common/vfprintf-internal.c.new
> --- stdio-common/vfprintf.c.old 2018-10-26 11:09:08.538713613 -0300
> +++ stdio-common/vfprintf-internal.c.new 2018-10-26 11:08:45.130667960 -0300
> @@ -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)

Do we really gain anything using these defines? I tend to frown on macros
that use internal named variables instead of set them as arguments. Also
this is quite short, I think it is more readable to just use the comparison
directly.

>  
>  #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 @@
>  # 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 @@
>        \
>   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 @@
>   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 @@
>        \
>   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 @@
>   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 @@
>        /* NOTREACHED */      \
>        \
>      LABEL (form_number):      \
> -      if (s->_flags2 & _IO_FLAGS2_FORTIFY)      \
> +      if (DO_FORTIFY)      \
>   {      \
>    if (! readonly_format)      \
>      {      \
> @@ -1214,7 +1220,8 @@
>  #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 @@
>        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 @@
>  
>  /* 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 @@
>       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 @@
>    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 @@
>      }
>    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 @@
>     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 @@
>         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 @@
>        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 @@
>        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 @@
>  #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 @@
>    _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 @@
>  
>    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

Ok.

> diff -u /dev/null stdio-common/vfprintf.c.new
> --- /dev/null 2018-10-15 19:30:16.914999855 -0300
> +++ stdio-common/vfprintf.c.new 2018-10-26 11:08:58.758694540 -0300
> @@ -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)

Ok.

> diff --git a/stdio-common/vfwprintf-internal.c b/stdio-common/vfwprintf-internal.c
> new file mode 100644
> index 0000000000..cefaf2fafe
> --- /dev/null
> +++ b/stdio-common/vfwprintf-internal.c
> @@ -0,0 +1,2 @@
> +#define COMPILE_WPRINTF 1
> +#include "vfprintf-internal.c"

Ok.

> diff --git a/stdio-common/vfwprintf.c b/stdio-common/vfwprintf.c
> index 2c3cd06fad..5d65eb7697 100644
> --- a/stdio-common/vfwprintf.c
> +++ b/stdio-common/vfwprintf.c
> @@ -1,3 +1,25 @@
> -#include <wctype.h>
> -#define COMPILE_WPRINTF 1
> -#include "vfprintf.c"
> +/* 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);

Ok.

> 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)

Ok

> diff --git a/stdlib/strfrom-skeleton.c b/stdlib/strfrom-skeleton.c
> index 2840512cae..5b33604427 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_internal from libio.  */
>  
>    if (size == 0)
>      {

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 468e23dec4..bda84af0bb 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -166,7 +166,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;
>  }
> @@ -175,15 +175,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
> @@ -193,7 +194,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;
>  }
> @@ -245,7 +246,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;
>  }
> @@ -257,7 +258,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;
>  }
> @@ -269,7 +270,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;
>  }
> @@ -289,7 +290,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;
>  }
> @@ -303,7 +304,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;
>  }
>

Ok.
12