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

Message ID 20181029121650.24544-8-gabriel@inconstante.eti.br
State Superseded
Headers

Commit Message

Gabriel F. T. Gomes Oct. 29, 2018, 12:16 p.m. UTC
  From: Zack Weinberg <zackw@panix.com>

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  <zackw@panix.com>
	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

	* 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 <zackw@panix.com>
Signed-off-by: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
---
 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
  

Comments

Gabriel F. T. Gomes Oct. 29, 2018, 12:24 p.m. UTC | #1
On Mon, 29 Oct 2018, Gabriel F. T. Gomes wrote:

>From: Zack Weinberg <zackw@panix.com>
>
> 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.
  
Adhemerval Zanella Nov. 8, 2018, 11:47 a.m. UTC | #2
On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> 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.

LGTM with two minor issues below.

> 
> 2018-10-24  Zack Weinberg  <zackw@panix.com>
> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
> 
> 	* 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 <zackw@panix.com>
> Signed-off-by: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>

We don't use DCO, but copyright assignments.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Maybe a __glibc_unlikely here?

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

> diff --git a/debug/vobprintf_chk.c b/debug/vobprintf_chk.c
> new file mode 100644
> index 0000000000..edfbe8f00a
> --- /dev/null
> +++ b/debug/vobprintf_chk.c
> @@ -0,0 +1,32 @@
> +/* Print output of stream to given obstack.
> +   Copyright (C) 1996-2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.

I think it is better to just set Copyright to 2018 without 'Contributed by'
(this implementation is quite different than the original one).

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

> 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

Ok.

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

Ok.

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

Ok.

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

Ok.
  
Adhemerval Zanella Nov. 8, 2018, 5:21 p.m. UTC | #3
On 29/10/2018 09:24, Gabriel F. T. Gomes wrote:
> On Mon, 29 Oct 2018, Gabriel F. T. Gomes wrote:
> 
>> From: Zack Weinberg <zackw@panix.com>
>>
>> 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.
> 

The BZ#20231 described issue does not happen, vdprintf_chk indeed returns EOF 
when trying to write on a closed file. It will currently call on master:

  _IO_new_file_seekoff
  \_ _IO_new_file_attach
     \_ __GI___vdprintf_chk
        \_ _IO_file_seek
           \_ __lseek64

And the __lseek64 will return -1/EBADF and thus _IO_new_file_attach will fail.

The code difference with default vdprintf is, in fact, BZ#11319, where vdprintf_chk 
does not return an error when an output error occurs (the same example reported on 
BZ#11319 fails with -D_FORTIFY_SOURCE=2 -O2).

I reopened BZ#11319 noting the fortified also needs fixing and the good thing is
the 'Add __v*printf_internal with flags arguments.' [1] refactor fixes it by
using a common correct function for both fortified and non-fortified vfprintf.
Please add a note that this patch fixes BZ#11319.

[1] https://sourceware.org/ml/libc-alpha/2018-10/msg00616.html
  
Gabriel F. T. Gomes Nov. 15, 2018, 3:08 p.m. UTC | #4
On Thu, 08 Nov 2018, Adhemerval Zanella wrote:

>On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:
>
>> Signed-off-by: Zack Weinberg <zackw@panix.com>
>> Signed-off-by: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>  
>
>We don't use DCO, but copyright assignments.

Ack, fixed.

>> --- /dev/null
>> +++ b/debug/vobprintf_chk.c
>> @@ -0,0 +1,32 @@
>> +/* Print output of stream to given obstack.
>> +   Copyright (C) 1996-2018 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.  
>
>I think it is better to just set Copyright to 2018 without 'Contributed by'
>(this implementation is quite different than the original one).

Ack, fixed.

>> -___sprintf_chk (char *s, int flags, size_t slen, const char *format, ...)
>> +___sprintf_chk (char *s, int flag, size_t slen, const char *format, ...)
>> [...]
>> +  if (slen == 0)
>> +    __chk_fail ();  
>
>Maybe a __glibc_unlikely here?

Looks right to me, added.  Please see comments below.

>>  __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
>>  			va_list ap)
>>  {
>> +  if (slen == 0)
>> +    __chk_fail ();

I added __glibc_unlikely here, too.

>>  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)
>> [...]
>>    if (slen == 0)
>>      __chk_fail ();

This is an unchanged hunk (brought in by diff context), but may I also add
__glibc_unlikely to it along with the other changes?

These are the only ocurrences of slen == 0 (__nldbl___sprintf_chk calls
__nldbl___vsprintf_chk, so it doesn't check slen on its own).
  
Florian Weimer Nov. 15, 2018, 4:24 p.m. UTC | #5
* Adhemerval Zanella:

>> +  if (slen == 0)
>> +    __chk_fail ();
>
> Maybe a __glibc_unlikely here?

I don't think this is required for paths which lead to a noreturn
function.

Thanks,
Florian
  
Adhemerval Zanella Nov. 15, 2018, 5:25 p.m. UTC | #6
On 15/11/2018 08:24, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>>> +  if (slen == 0)
>>> +    __chk_fail ();
>>
>> Maybe a __glibc_unlikely here?
> 
> I don't think this is required for paths which lead to a noreturn
> function.
> 
> Thanks,
> Florian
> 

Right, so I ok with current change as is.
  
Adhemerval Zanella Nov. 15, 2018, 5:26 p.m. UTC | #7
On 15/11/2018 07:08, Gabriel F. T. Gomes wrote:
> On Thu, 08 Nov 2018, Adhemerval Zanella wrote:
> 
>> On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:
>>
>>> Signed-off-by: Zack Weinberg <zackw@panix.com>
>>> Signed-off-by: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>  
>>
>> We don't use DCO, but copyright assignments.
> 
> Ack, fixed.
> 
>>> --- /dev/null
>>> +++ b/debug/vobprintf_chk.c
>>> @@ -0,0 +1,32 @@
>>> +/* Print output of stream to given obstack.
>>> +   Copyright (C) 1996-2018 Free Software Foundation, Inc.
>>> +   This file is part of the GNU C Library.
>>> +   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.  
>>
>> I think it is better to just set Copyright to 2018 without 'Contributed by'
>> (this implementation is quite different than the original one).
> 
> Ack, fixed.
> 
>>> -___sprintf_chk (char *s, int flags, size_t slen, const char *format, ...)
>>> +___sprintf_chk (char *s, int flag, size_t slen, const char *format, ...)
>>> [...]
>>> +  if (slen == 0)
>>> +    __chk_fail ();  
>>
>> Maybe a __glibc_unlikely here?
> 
> Looks right to me, added.  Please see comments below.
> 
>>>  __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
>>>  			va_list ap)
>>>  {
>>> +  if (slen == 0)
>>> +    __chk_fail ();
> 
> I added __glibc_unlikely here, too.
> 
>>>  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)
>>> [...]
>>>    if (slen == 0)
>>>      __chk_fail ();
> 
> This is an unchanged hunk (brought in by diff context), but may I also add
> __glibc_unlikely to it along with the other changes?
> 
> These are the only ocurrences of slen == 0 (__nldbl___sprintf_chk calls
> __nldbl___vsprintf_chk, so it doesn't check slen on its own).
> 

As Florian has pointed out I also think this is not really necessary.
So I am ok with current changes.
  

Patch

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 <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libio/libioP.h>
+
+
+int
+__obstack_vprintf_chk (struct obstack *obstack, int flag, const char *format,
+		       va_list ap)
+{
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+
+  return __obstack_vprintf_internal (obstack, format, ap, mode);
+}
diff --git a/debug/vprintf_chk.c b/debug/vprintf_chk.c
index b3b2c53df2..69fcb721ac 100644
--- a/debug/vprintf_chk.c
+++ b/debug/vprintf_chk.c
@@ -15,27 +15,17 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 ___vprintf_chk (int flag, const char *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = vfprintf (stdout, format, ap);
-
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return __vfprintf_internal (stdout, format, ap, mode);
 }
 ldbl_strong_alias (___vprintf_chk, __vprintf_chk)
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index 95d286f416..666a83b701 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -15,56 +15,22 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
 
-extern const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden;
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
-/* VARARGS5 */
 int
-___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
-		  const char *format, va_list args)
+___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
+		  const char *format, va_list ap)
 {
-  /* XXX Maybe for less strict version do not fail immediately.
-     Though, maxlen is supposed to be the size of buffer pointed
-     to by s, so a conforming program can't pass such maxlen
-     to *snprintf.  */
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  _IO_strnfile sf;
-  int ret;
-#ifdef _IO_MTSAFE_IO
-  sf.f._sbf._f._lock = NULL;
-#endif
-
-  /* We need to handle the special case where MAXLEN is 0.  Use the
-     overflow buffer right from the start.  */
-  if (maxlen == 0)
-    {
-      s = sf.overflow_buf;
-      maxlen = sizeof (sf.overflow_buf);
-    }
-
-  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
-  s[0] = '\0';
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
-  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
-    *sf.f._sbf._f._IO_write_ptr = '\0';
-  return ret;
+  return __vsnprintf_internal (s, maxlen, format, ap, mode);
 }
-ldbl_hidden_def (___vsnprintf_chk, __vsnprintf_chk)
 ldbl_strong_alias (___vsnprintf_chk, __vsnprintf_chk)
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
index 53f07236ae..c1b1a8da4f 100644
--- a/debug/vsprintf_chk.c
+++ b/debug/vsprintf_chk.c
@@ -15,75 +15,20 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
-
-
-static int _IO_str_chk_overflow (FILE *fp, int c) __THROW;
-
-static int
-_IO_str_chk_overflow (FILE *fp, int c)
-{
-  /* When we come to here this means the user supplied buffer is
-     filled.  */
-  __chk_fail ();
-}
-
-
-static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_str_finish),
-  JUMP_INIT(overflow, _IO_str_chk_overflow),
-  JUMP_INIT(underflow, _IO_str_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_str_pbackfail),
-  JUMP_INIT(xsputn, _IO_default_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_str_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_default_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
+#include <libio/libioP.h>
 
 int
-___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
-		 va_list args)
+___vsprintf_chk (char *s, int flag, size_t slen, const char *format,
+		 va_list ap)
 {
-  _IO_strfile f;
-  int ret;
-#ifdef _IO_MTSAFE_IO
-  f._sbf._f._lock = NULL;
-#endif
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
   if (slen == 0)
     __chk_fail ();
 
-  _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&f._sbf) = &_IO_str_chk_jumps;
-  s[0] = '\0';
-  _IO_str_init_static_internal (&f, s, slen - 1, s);
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
-     can only come from read-only format strings.  */
-  if (flags > 0)
-    f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
-
-  *f._sbf._f._IO_write_ptr = '\0';
-  return ret;
+  return __vsprintf_internal (s, slen, format, ap, mode);
 }
 ldbl_hidden_def (___vsprintf_chk, __vsprintf_chk)
 ldbl_strong_alias (___vsprintf_chk, __vsprintf_chk)
diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
index 4d616f8835..2c6fadd463 100644
--- a/debug/vswprintf_chk.c
+++ b/debug/vswprintf_chk.c
@@ -15,60 +15,21 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
-/* VARARGS5 */
 int
-__vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
-		 const wchar_t *format, va_list args)
+__vswprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
+		 const wchar_t *format, va_list ap)
 {
-  /* XXX Maybe for less strict version do not fail immediately.
-     Though, maxlen is supposed to be the size of buffer pointed
-     to by s, so a conforming program can't pass such maxlen
-     to *snprintf.  */
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  _IO_wstrnfile sf;
-  struct _IO_wide_data wd;
-  int ret;
-#ifdef _IO_MTSAFE_IO
-  sf.f._sbf._f._lock = NULL;
-#endif
-
-  /* We need to handle the special case where MAXLEN is 0.  Use the
-     overflow buffer right from the start.  */
-  if (__glibc_unlikely (maxlen == 0))
-    /* Since we have to write at least the terminating L'\0' a buffer
-       length of zero always makes the function fail.  */
-    return -1;
-
-  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstrn_jumps);
-  _IO_fwide (&sf.f._sbf._f, 1);
-  s[0] = L'\0';
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
-  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
-
-  if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
-    /* ISO C99 requires swprintf/vswprintf to return an error if the
-       output does not fit int he provided buffer.  */
-    return -1;
-
-  /* Terminate the string.  */
-  *sf.f._sbf._f._wide_data->_IO_write_ptr = '\0';
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  return ret;
+  return __vswprintf_internal (s, maxlen, format, ap, mode);
 }
-libc_hidden_def (__vswprintf_chk)
diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
index fedc7a46bf..f1e8878a54 100644
--- a/debug/vwprintf_chk.c
+++ b/debug/vwprintf_chk.c
@@ -15,27 +15,16 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 __vwprintf_chk (int flag, const wchar_t *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = __vfwprintf_internal (stdout, format, ap, 0);
-
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return __vfwprintf_internal (stdout, format, ap, mode);
 }
diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
index 819050e5af..9f406e95f8 100644
--- a/debug/wprintf_chk.c
+++ b/debug/wprintf_chk.c
@@ -16,29 +16,22 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 __wprintf_chk (int flag, const wchar_t *format, ...)
 {
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
+  int ret;
 
   va_start (ap, format);
-  done = __vfwprintf_internal (stdout, format, ap, 0);
+  ret = __vfwprintf_internal (stdout, format, ap, mode);
   va_end (ap);
 
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return ret;
 }
diff --git a/include/stdio.h b/include/stdio.h
index 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)