[v3,6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)

Message ID 20181115214449.19262-7-gabriel@inconstante.eti.br
State New
Headers show
Series
  • Use more flags parameters instead of global bits in stdio
Related show

Commit Message

Gabriel F. T. Gomes Nov. 15, 2018, 9:44 p.m.
From: Zack Weinberg <zackw@panix.com>


Changes since v2:

  - Fix copyright statements.
  - Add note about the fix for bug 11319.

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.

As a side-effect of the unification of both fortified and non-fortified
vdprintf initialization, this patch fixes bug 11319.

Tested for powerpc and powerpc64le.

2018-10-24  Zack Weinberg  <zackw@panix.com>
	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

	[BZ #11319]
	* 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.
---
 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/{asprintf_chk.c => vobprintf_chk.c} | 23 +++-----
 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, 247 insertions(+), 564 deletions(-)
 copy debug/{asprintf_chk.c => vobprintf_chk.c} (61%)

-- 
2.14.5

Comments

Adhemerval Zanella Nov. 22, 2018, 6:11 p.m. | #1
On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>

> 

> Changes since v2:

> 

>   - Fix copyright statements.

>   - Add note about the fix for bug 11319.


I don't recall exactly which patch was the one that actually fixes BZ#11319,
my previous indication was 'Add __v*printf_internal with flags arguments.'.
Could you recheck it please?

Besides it the patch LGTM, thanks.

> 

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

> 

> As a side-effect of the unification of both fortified and non-fortified

> vdprintf initialization, this patch fixes bug 11319.

> 

> Tested for powerpc and powerpc64le.

> 

> 2018-10-24  Zack Weinberg  <zackw@panix.com>

> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

> 

> 	[BZ #11319]

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

> ---

>  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/{asprintf_chk.c => vobprintf_chk.c} | 23 +++-----

>  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, 247 insertions(+), 564 deletions(-)

>  copy debug/{asprintf_chk.c => vobprintf_chk.c} (61%)

> 

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

>  

>  

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

>  

> -  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/asprintf_chk.c b/debug/vobprintf_chk.c

> similarity index 61%

> copy from debug/asprintf_chk.c

> copy to debug/vobprintf_chk.c

> index 9cd4143f2e..bed2c98eac 100644

> --- a/debug/asprintf_chk.c

> +++ b/debug/vobprintf_chk.c

> @@ -1,4 +1,5 @@

> -/* Copyright (C) 1991-2018 Free Software Foundation, Inc.

> +/* Print output of stream to given obstack.

> +   Copyright (C) 2018 Free Software Foundation, Inc.

>     This file is part of the GNU C Library.

>  

>     The GNU C Library is free software; you can redistribute it and/or

> @@ -15,22 +16,16 @@

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

> +__obstack_vprintf_chk (struct obstack *obstack, int flag, const char *format,

> +		       va_list ap)

>  {

> -  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_start (arg, format);

> -  done = __vasprintf_chk (result_ptr, flags, format, arg);

> -  va_end (arg);

> -

> -  return done;

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

>  }

>  

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


Ok.

> 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 fe52ef1752..ce5228e382 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)

> @@ -818,26 +825,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 b0c86e99bd..4cc4261ead 100644

> --- a/stdio-common/vfprintf-internal.c

> +++ b/stdio-common/vfprintf-internal.c

> @@ -1283,8 +1283,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.
Gabriel F. T. Gomes Dec. 4, 2018, 4:19 p.m. | #2
On Thu, 22 Nov 2018, Adhemerval Zanella wrote:

>On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:

>> From: Zack Weinberg <zackw@panix.com>

>

>I don't recall exactly which patch was the one that actually fixes BZ#11319,

>my previous indication was 'Add __v*printf_internal with flags arguments.'.

>Could you recheck it please?


Yes, sure.  This patch fixes the bug, because of the following change...

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


Notice that the call to __vfprintf_internal was replaced with a call to
__vdprintf_internal, which has the check for EOF (lines 55 and 56 [1]).

I wrote a test case to check this and I confirm that the problem is
reproducible without this patch, but not with it.  (I'll clean the test up
and send to this list...  Maybe it should get in to avoid regressions).

[1] https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iovdprintf.c;h=78a3a2bd159bfc8020d970cecadeaca6e2312a7b;hb=HEAD
Adhemerval Zanella Dec. 4, 2018, 5:39 p.m. | #3
On 04/12/2018 14:19, Gabriel F. T. Gomes wrote:
> On Thu, 22 Nov 2018, Adhemerval Zanella wrote:

> 

>> On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:

>>> From: Zack Weinberg <zackw@panix.com>

>>

>> I don't recall exactly which patch was the one that actually fixes BZ#11319,

>> my previous indication was 'Add __v*printf_internal with flags arguments.'.

>> Could you recheck it please?

> 

> Yes, sure.  This patch fixes the bug, because of the following change...

> 

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

> 

> Notice that the call to __vfprintf_internal was replaced with a call to

> __vdprintf_internal, which has the check for EOF (lines 55 and 56 [1]).

> 

> I wrote a test case to check this and I confirm that the problem is

> reproducible without this patch, but not with it.  (I'll clean the test up

> and send to this list...  Maybe it should get in to avoid regressions).

> 

> [1] https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iovdprintf.c;h=78a3a2bd159bfc8020d970cecadeaca6e2312a7b;hb=HEAD

> 


Thanks for confirm it, could you attach the add the testcase as well?
I would prefer to push along with the patch itself, and there is no need
to send a new version for the whole set. Just update this one.
Gabriel F. T. Gomes Dec. 4, 2018, 6:01 p.m. | #4
On Tue, 04 Dec 2018, Adhemerval Zanella wrote:

>Thanks for confirm it, could you attach the add the testcase as well?

>I would prefer to push along with the patch itself, and there is no need

>to send a new version for the whole set. Just update this one.


This is the patch (I hope my email client doesn't screw it)...


From a583fded669048e7d58c760810e30758a5ede286 Mon Sep 17 00:00:00 2001
From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>

Date: Tue, 4 Dec 2018 15:57:57 -0200
Subject: [PATCH] Add test for bug 11319

The commit

commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
Author: Ulrich Drepper <drepper@redhat.com>
Date:   Wed Feb 24 16:07:57 2010 -0800

    Fix reporting of I/O errors in *dprintf functions.

fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for
__dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring
of libio functions, this bug is also fixed for the foritified functions.
This patch adds a test case to avoid regressions.

Tested for powerpc64le and x86_64.

	* stdio-common/Makefile (tests): Add tst-bz11319 and
	tst-bz11319-fortify2.
	(CFLAGS-tst-bz11319-fortify2.c): New macro.
	* stdio-common/tst-bz11319-fortify2.c: New file.
	* stdio-common/tst-bz11319.c: Likewise.
---
 stdio-common/Makefile               |  6 ++++-
 stdio-common/tst-bz11319-fortify2.c |  1 +
 stdio-common/tst-bz11319.c          | 48 +++++++++++++++++++++++++++++++++++++
 3 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 stdio-common/tst-bz11319-fortify2.c
 create mode 100644 stdio-common/tst-bz11319.c

diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 84bad1fafe..8978b3fb1f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 tst-vfprintf-user-type \
 	 tst-vfprintf-mbs-prec \
 	 tst-scanf-round \
-	 tst-renameat2 \
+	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
 
 test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
 
@@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
 # tst-gets.c tests a deprecated function.
 CFLAGS-tst-gets.c += -Wno-deprecated-declarations
 
+# BZ #11319 was first fixed for regular vdprintf, then reopened because
+# the fortified version had the same bug.
+CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
+
 CPPFLAGS += $(libio-mtsafe)
 
 $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1
diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
new file mode 100644
index 0000000000..a8df9a39bd
--- /dev/null
+++ b/stdio-common/tst-bz11319-fortify2.c
@@ -0,0 +1 @@
+#include <tst-bz11319.c>
diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
new file mode 100644
index 0000000000..ce2dee13ae
--- /dev/null
+++ b/stdio-common/tst-bz11319.c
@@ -0,0 +1,48 @@
+/* Regression test for bug 11319.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE	1
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/eventfd.h>
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  int ret;
+  int fd = eventfd(0, 0);
+
+  /* man 2 eventfd:
+
+     A write(2) will fail with the error EINVAL if the size of the
+     supplied buffer is less than 8 bytes... */
+  ret = dprintf(fd, "%d", 0);
+
+  TEST_VERIFY (ret < 0);
+  TEST_COMPARE (errno, EINVAL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.14.5
From a583fded669048e7d58c760810e30758a5ede286 Mon Sep 17 00:00:00 2001
From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>

Date: Tue, 4 Dec 2018 15:57:57 -0200
Subject: [PATCH] Add test for bug 11319

The commit

commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
Author: Ulrich Drepper <drepper@redhat.com>
Date:   Wed Feb 24 16:07:57 2010 -0800

    Fix reporting of I/O errors in *dprintf functions.

fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for
__dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring
of libio functions, this bug is also fixed for the foritified functions.
This patch adds a test case to avoid regressions.

Tested for powerpc64le and x86_64.

	* stdio-common/Makefile (tests): Add tst-bz11319 and
	tst-bz11319-fortify2.
	(CFLAGS-tst-bz11319-fortify2.c): New macro.
	* stdio-common/tst-bz11319-fortify2.c: New file.
	* stdio-common/tst-bz11319.c: Likewise.
---
 stdio-common/Makefile               |  6 ++++-
 stdio-common/tst-bz11319-fortify2.c |  1 +
 stdio-common/tst-bz11319.c          | 48 +++++++++++++++++++++++++++++++++++++
 3 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 stdio-common/tst-bz11319-fortify2.c
 create mode 100644 stdio-common/tst-bz11319.c

diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 84bad1fafe..8978b3fb1f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 tst-vfprintf-user-type \
 	 tst-vfprintf-mbs-prec \
 	 tst-scanf-round \
-	 tst-renameat2 \
+	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
 
 test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
 
@@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
 # tst-gets.c tests a deprecated function.
 CFLAGS-tst-gets.c += -Wno-deprecated-declarations
 
+# BZ #11319 was first fixed for regular vdprintf, then reopened because
+# the fortified version had the same bug.
+CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
+
 CPPFLAGS += $(libio-mtsafe)
 
 $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1
diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
new file mode 100644
index 0000000000..a8df9a39bd
--- /dev/null
+++ b/stdio-common/tst-bz11319-fortify2.c
@@ -0,0 +1 @@
+#include <tst-bz11319.c>
diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
new file mode 100644
index 0000000000..ce2dee13ae
--- /dev/null
+++ b/stdio-common/tst-bz11319.c
@@ -0,0 +1,48 @@
+/* Regression test for bug 11319.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE	1
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/eventfd.h>
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  int ret;
+  int fd = eventfd(0, 0);
+
+  /* man 2 eventfd:
+
+     A write(2) will fail with the error EINVAL if the size of the
+     supplied buffer is less than 8 bytes... */
+  ret = dprintf(fd, "%d", 0);
+
+  TEST_VERIFY (ret < 0);
+  TEST_COMPARE (errno, EINVAL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.14.5
Adhemerval Zanella Dec. 4, 2018, 9:06 p.m. | #5
On 04/12/2018 16:01, Gabriel F. T. Gomes wrote:
> On Tue, 04 Dec 2018, Adhemerval Zanella wrote:

> 

>> Thanks for confirm it, could you attach the add the testcase as well?

>> I would prefer to push along with the patch itself, and there is no need

>> to send a new version for the whole set. Just update this one.

> 

> This is the patch (I hope my email client doesn't screw it)...


Thanks, below some comments about the regression test.

> 

> 

> From a583fded669048e7d58c760810e30758a5ede286 Mon Sep 17 00:00:00 2001

> From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>

> Date: Tue, 4 Dec 2018 15:57:57 -0200

> Subject: [PATCH] Add test for bug 11319

> 

> The commit

> 

> commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3

> Author: Ulrich Drepper <drepper@redhat.com>

> Date:   Wed Feb 24 16:07:57 2010 -0800

> 

>     Fix reporting of I/O errors in *dprintf functions.

> 

> fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for

> __dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring

> of libio functions, this bug is also fixed for the foritified functions.

> This patch adds a test case to avoid regressions.

> 

> Tested for powerpc64le and x86_64.

> 

> 	* stdio-common/Makefile (tests): Add tst-bz11319 and

> 	tst-bz11319-fortify2.

> 	(CFLAGS-tst-bz11319-fortify2.c): New macro.

> 	* stdio-common/tst-bz11319-fortify2.c: New file.

> 	* stdio-common/tst-bz11319.c: Likewise.

> ---

>  stdio-common/Makefile               |  6 ++++-

>  stdio-common/tst-bz11319-fortify2.c |  1 +

>  stdio-common/tst-bz11319.c          | 48 +++++++++++++++++++++++++++++++++++++

>  3 files changed, 54 insertions(+), 1 deletion(-)

>  create mode 100644 stdio-common/tst-bz11319-fortify2.c

>  create mode 100644 stdio-common/tst-bz11319.c

> 

> diff --git a/stdio-common/Makefile b/stdio-common/Makefile

> index 84bad1fafe..8978b3fb1f 100644

> --- a/stdio-common/Makefile

> +++ b/stdio-common/Makefile

> @@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \

>  	 tst-vfprintf-user-type \

>  	 tst-vfprintf-mbs-prec \

>  	 tst-scanf-round \

> -	 tst-renameat2 \

> +	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \

>  

>  test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble

>  

> @@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"

>  # tst-gets.c tests a deprecated function.

>  CFLAGS-tst-gets.c += -Wno-deprecated-declarations

>  

> +# BZ #11319 was first fixed for regular vdprintf, then reopened because

> +# the fortified version had the same bug.

> +CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2

> +

>  CPPFLAGS += $(libio-mtsafe)

>  

>  $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1


Ok.

> diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c

> new file mode 100644

> index 0000000000..a8df9a39bd

> --- /dev/null

> +++ b/stdio-common/tst-bz11319-fortify2.c

> @@ -0,0 +1 @@

> +#include <tst-bz11319.c>

> diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c

> new file mode 100644

> index 0000000000..ce2dee13ae

> --- /dev/null

> +++ b/stdio-common/tst-bz11319.c

> @@ -0,0 +1,48 @@

> +/* Regression test for bug 11319.

> +   Copyright (C) 2018 Free Software Foundation, Inc.

> +   This file is part of the GNU C Library.

> +

> +   The GNU C Library is free software; you can redistribute it and/or

> +   modify it under the terms of the GNU Lesser General Public

> +   License as published by the Free Software Foundation; either

> +   version 2.1 of the License, or (at your option) any later version.

> +

> +   The GNU C Library is distributed in the hope that it will be useful,

> +   but WITHOUT ANY WARRANTY; without even the implied warranty of

> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

> +   Lesser General Public License for more details.

> +

> +   You should have received a copy of the GNU Lesser General Public

> +   License along with the GNU C Library; if not, see

> +   <http://www.gnu.org/licenses/>.  */

> +

> +#ifndef _GNU_SOURCE

> +# define _GNU_SOURCE	1

> +#endif


I think we can define it regardless

> +

> +#include <errno.h>

> +#include <stdio.h>

> +#include <string.h>

> +#include <sys/eventfd.h>


eventfd is Linux specific, so either we need to move this test to Linux
sysdeps or use a platform neutral way to stress this issue.

> +

> +#include <support/check.h>

> +

> +static int

> +do_test (void)

> +{

> +  int ret;

> +  int fd = eventfd(0, 0);


To stress this issue we just need a valid file descriptor that is seekable
but fail on a write.  Just use a temporary file opened in read-only mode.

> +

> +  /* man 2 eventfd:

> +

> +     A write(2) will fail with the error EINVAL if the size of the

> +     supplied buffer is less than 8 bytes... */

> +  ret = dprintf(fd, "%d", 0);

> +

> +  TEST_VERIFY (ret < 0);

> +  TEST_COMPARE (errno, EINVAL);

> +

> +  return 0;

> +}

> +

> +#include <support/test-driver.c>

>
Gabriel F. T. Gomes Dec. 5, 2018, 4:53 p.m. | #6
On Tue, 04 Dec 2018, Adhemerval Zanella wrote:

>On 04/12/2018 16:01, Gabriel F. T. Gomes wrote:

>>

>> +#ifndef _GNU_SOURCE

>> +# define _GNU_SOURCE	1

>> +#endif  

>

>I think we can define it regardless


OK.

>> +#include <errno.h>

>> +#include <stdio.h>

>> +#include <string.h>

>> +#include <sys/eventfd.h>  

>

>eventfd is Linux specific, so either we need to move this test to Linux

>sysdeps or use a platform neutral way to stress this issue.


Oh, indeed.

>> +

>> +#include <support/check.h>

>> +

>> +static int

>> +do_test (void)

>> +{

>> +  int ret;

>> +  int fd = eventfd(0, 0);  

>

>To stress this issue we just need a valid file descriptor that is seekable

>but fail on a write.  Just use a temporary file opened in read-only mode.


Does the following patch look better (thanks for the suggestion)?

From d992bc941921988fee31ff8b3fc13fb406f89b93 Mon Sep 17 00:00:00 2001
From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>

Date: Tue, 4 Dec 2018 15:57:57 -0200
Subject: [PATCH v2] Add test for bug 11319

The commit

commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
Author: Ulrich Drepper <drepper@redhat.com>
Date:   Wed Feb 24 16:07:57 2010 -0800

    Fix reporting of I/O errors in *dprintf functions.

fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for
__dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring
of libio functions, this bug is also fixed for the foritified functions.
This patch adds a test case to avoid regressions.

Tested for powerpc64le and x86_64.

	* stdio-common/Makefile (tests): Add tst-bz11319 and
	tst-bz11319-fortify2.
	(CFLAGS-tst-bz11319-fortify2.c): New macro.
	* stdio-common/tst-bz11319-fortify2.c: New file.
	* stdio-common/tst-bz11319.c: Likewise.
---
 stdio-common/Makefile               |  6 ++++-
 stdio-common/tst-bz11319-fortify2.c |  1 +
 stdio-common/tst-bz11319.c          | 52 +++++++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 1 deletion(-)
 create mode 100644 stdio-common/tst-bz11319-fortify2.c
 create mode 100644 stdio-common/tst-bz11319.c

diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 84bad1fafe..8978b3fb1f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 tst-vfprintf-user-type \
 	 tst-vfprintf-mbs-prec \
 	 tst-scanf-round \
-	 tst-renameat2 \
+	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
 
 test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
 
@@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
 # tst-gets.c tests a deprecated function.
 CFLAGS-tst-gets.c += -Wno-deprecated-declarations
 
+# BZ #11319 was first fixed for regular vdprintf, then reopened because
+# the fortified version had the same bug.
+CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
+
 CPPFLAGS += $(libio-mtsafe)
 
 $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1
diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
new file mode 100644
index 0000000000..a8df9a39bd
--- /dev/null
+++ b/stdio-common/tst-bz11319-fortify2.c
@@ -0,0 +1 @@
+#include <tst-bz11319.c>
diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
new file mode 100644
index 0000000000..29fbd729ab
--- /dev/null
+++ b/stdio-common/tst-bz11319.c
@@ -0,0 +1,52 @@
+/* Regression test for bug 11319.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+
+static int
+do_test (void)
+{
+  char *tempfile;
+  int ret;
+  FILE *fp;
+
+  /* Create a temporary file and open it in read-only mode.  */
+  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));
+  fp = xfopen (tempfile, "r");
+
+  /* Try and write to the temporary file to intentionally fail, then
+     check that dprintf (or __dprintf_chk) return EOF.  */
+  ret = dprintf (fp->_fileno, "%d", 0);
+  TEST_VERIFY (ret == EOF);
+
+  /* Clean up.  */
+  xfclose (fp);
+  if (tempfile)
+    free (tempfile);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.14.5
Adhemerval Zanella Dec. 5, 2018, 6:14 p.m. | #7
On 05/12/2018 14:53, Gabriel F. T. Gomes wrote:
> On Tue, 04 Dec 2018, Adhemerval Zanella wrote:

> 

>> On 04/12/2018 16:01, Gabriel F. T. Gomes wrote:

>>>

>>> +#ifndef _GNU_SOURCE

>>> +# define _GNU_SOURCE	1

>>> +#endif  

>>

>> I think we can define it regardless

> 

> OK.

> 

>>> +#include <errno.h>

>>> +#include <stdio.h>

>>> +#include <string.h>

>>> +#include <sys/eventfd.h>  

>>

>> eventfd is Linux specific, so either we need to move this test to Linux

>> sysdeps or use a platform neutral way to stress this issue.

> 

> Oh, indeed.

> 

>>> +

>>> +#include <support/check.h>

>>> +

>>> +static int

>>> +do_test (void)

>>> +{

>>> +  int ret;

>>> +  int fd = eventfd(0, 0);  

>>

>> To stress this issue we just need a valid file descriptor that is seekable

>> but fail on a write.  Just use a temporary file opened in read-only mode.

> 

> Does the following patch look better (thanks for the suggestion)?

> 

> From d992bc941921988fee31ff8b3fc13fb406f89b93 Mon Sep 17 00:00:00 2001

> From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>

> Date: Tue, 4 Dec 2018 15:57:57 -0200

> Subject: [PATCH v2] Add test for bug 11319

> 

> The commit

> 

> commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3

> Author: Ulrich Drepper <drepper@redhat.com>

> Date:   Wed Feb 24 16:07:57 2010 -0800

> 

>     Fix reporting of I/O errors in *dprintf functions.

> 

> fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for

> __dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring

> of libio functions, this bug is also fixed for the foritified functions.

> This patch adds a test case to avoid regressions.

> 

> Tested for powerpc64le and x86_64.

> 

> 	* stdio-common/Makefile (tests): Add tst-bz11319 and

> 	tst-bz11319-fortify2.

> 	(CFLAGS-tst-bz11319-fortify2.c): New macro.

> 	* stdio-common/tst-bz11319-fortify2.c: New file.

> 	* stdio-common/tst-bz11319.c: Likewise.

> ---

>  stdio-common/Makefile               |  6 ++++-

>  stdio-common/tst-bz11319-fortify2.c |  1 +

>  stdio-common/tst-bz11319.c          | 52 +++++++++++++++++++++++++++++++++++++

>  3 files changed, 58 insertions(+), 1 deletion(-)

>  create mode 100644 stdio-common/tst-bz11319-fortify2.c

>  create mode 100644 stdio-common/tst-bz11319.c

> 

> diff --git a/stdio-common/Makefile b/stdio-common/Makefile

> index 84bad1fafe..8978b3fb1f 100644

> --- a/stdio-common/Makefile

> +++ b/stdio-common/Makefile

> @@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \

>  	 tst-vfprintf-user-type \

>  	 tst-vfprintf-mbs-prec \

>  	 tst-scanf-round \

> -	 tst-renameat2 \

> +	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \

>  

>  test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble

>  

> @@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"

>  # tst-gets.c tests a deprecated function.

>  CFLAGS-tst-gets.c += -Wno-deprecated-declarations

>  

> +# BZ #11319 was first fixed for regular vdprintf, then reopened because

> +# the fortified version had the same bug.

> +CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2

> +

>  CPPFLAGS += $(libio-mtsafe)

>  

>  $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1

> diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c

> new file mode 100644

> index 0000000000..a8df9a39bd

> --- /dev/null

> +++ b/stdio-common/tst-bz11319-fortify2.c

> @@ -0,0 +1 @@

> +#include <tst-bz11319.c>

> diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c

> new file mode 100644

> index 0000000000..29fbd729ab

> --- /dev/null

> +++ b/stdio-common/tst-bz11319.c

> @@ -0,0 +1,52 @@

> +/* Regression test for bug 11319.

> +   Copyright (C) 2018 Free Software Foundation, Inc.

> +   This file is part of the GNU C Library.

> +

> +   The GNU C Library is free software; you can redistribute it and/or

> +   modify it under the terms of the GNU Lesser General Public

> +   License as published by the Free Software Foundation; either

> +   version 2.1 of the License, or (at your option) any later version.

> +

> +   The GNU C Library is distributed in the hope that it will be useful,

> +   but WITHOUT ANY WARRANTY; without even the implied warranty of

> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

> +   Lesser General Public License for more details.

> +

> +   You should have received a copy of the GNU Lesser General Public

> +   License along with the GNU C Library; if not, see

> +   <http://www.gnu.org/licenses/>.  */

> +

> +#define _GNU_SOURCE 1

> +

> +#include <stdio.h>

> +#include <stdlib.h>

> +

> +#include <support/check.h>

> +#include <support/temp_file.h>

> +#include <support/xstdio.h>

> +

> +static int

> +do_test (void)

> +{

> +  char *tempfile;

> +  int ret;

> +  FILE *fp;

> +

> +  /* Create a temporary file and open it in read-only mode.  */

> +  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));

> +  fp = xfopen (tempfile, "r");

> +

> +  /* Try and write to the temporary file to intentionally fail, then

> +     check that dprintf (or __dprintf_chk) return EOF.  */

> +  ret = dprintf (fp->_fileno, "%d", 0);

> +  TEST_VERIFY (ret == EOF);

> +

> +  /* Clean up.  */

> +  xfclose (fp);

> +  if (tempfile)

> +    free (tempfile);


For a lack of a better interface (to create/open read-only temporary files
or memfd_create), I think it would be simpler to:

static int
do_test (void)
{ 
  char *tempfile;
  int fd;

  /* Create a temporary file and open it in read-only mode.  */
  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));
  fd = xopen (tempfile, O_RDONLY, 0660);

  /* Try and write to the temporary file to intentionally fail, then
     check that dprintf (or __dprintf_chk) return EOF.  */
  TEST_COMPARE (dprintf (fd, "%d", 0), EOF);

  xclose (fd);
  free (tempfile);

  return 0;
}


> +

> +  return 0;

> +}

> +

> +#include <support/test-driver.c>

>
Gabriel F. T. Gomes Dec. 5, 2018, 7:11 p.m. | #8
On Wed, 05 Dec 2018, Adhemerval Zanella wrote:
>

>For a lack of a better interface (to create/open read-only temporary files

>or memfd_create), I think it would be simpler to:

>

>static int

>do_test (void)

>{ 

>  char *tempfile;

>  int fd;

>

>  /* Create a temporary file and open it in read-only mode.  */

>  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));

>  fd = xopen (tempfile, O_RDONLY, 0660);

>

>  /* Try and write to the temporary file to intentionally fail, then

>     check that dprintf (or __dprintf_chk) return EOF.  */

>  TEST_COMPARE (dprintf (fd, "%d", 0), EOF);

>

>  xclose (fd);

>  free (tempfile);

>

>  return 0;

>}


Looks good to me.  Should I post an updated version, or is it OK with the
suggested changes?
Adhemerval Zanella Dec. 5, 2018, 7:18 p.m. | #9
On 05/12/2018 17:11, Gabriel F. T. Gomes wrote:
> On Wed, 05 Dec 2018, Adhemerval Zanella wrote:

>>

>> For a lack of a better interface (to create/open read-only temporary files

>> or memfd_create), I think it would be simpler to:

>>

>> static int

>> do_test (void)

>> { 

>>  char *tempfile;

>>  int fd;

>>

>>  /* Create a temporary file and open it in read-only mode.  */

>>  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));

>>  fd = xopen (tempfile, O_RDONLY, 0660);

>>

>>  /* Try and write to the temporary file to intentionally fail, then

>>     check that dprintf (or __dprintf_chk) return EOF.  */

>>  TEST_COMPARE (dprintf (fd, "%d", 0), EOF);

>>

>>  xclose (fd);

>>  free (tempfile);

>>

>>  return 0;

>> }

> 

> Looks good to me.  Should I post an updated version, or is it OK with the

> suggested changes?

> 


I would suggest you to integrate it on the patch which fixes BZ#11319
and from my side you don't need to send an update version.
Gabriel F. T. Gomes Dec. 5, 2018, 7:27 p.m. | #10
On Wed, 05 Dec 2018, Adhemerval Zanella wrote:

>I would suggest you to integrate it on the patch which fixes BZ#11319

>and from my side you don't need to send an update version.


Oh, I see.  Then I'll send it again, because I need to update the commit
message and ChangeLog.
Adhemerval Zanella Dec. 5, 2018, 7:35 p.m. | #11
On 05/12/2018 17:27, Gabriel F. T. Gomes wrote:
> On Wed, 05 Dec 2018, Adhemerval Zanella wrote:

> 

>> I would suggest you to integrate it on the patch which fixes BZ#11319

>> and from my side you don't need to send an update version.

> 

> Oh, I see.  Then I'll send it again, because I need to update the commit

> message and ChangeLog.

> 


Alright.
Gabriel F. T. Gomes Dec. 5, 2018, 8:07 p.m. | #12
On Wed, 05 Dec 2018, Adhemerval Zanella wrote:

>On 05/12/2018 17:27, Gabriel F. T. Gomes wrote:

>> On Wed, 05 Dec 2018, Adhemerval Zanella wrote:

>>   

>>> I would suggest you to integrate it on the patch which fixes BZ#11319

>>> and from my side you don't need to send an update version.  

>> 

>> Oh, I see.  Then I'll send it again, because I need to update the commit

>> message and ChangeLog.

>>   

>

>Alright.


Hrm, I thought I would have to rewrite the messages (and that I would be
doubtful about it), but it turned out to be mostly copy-and-paste.  So,
I'll go ahead and push the changes.

Thanks again and sorry about the noise. :)
Szabolcs Nagy Dec. 18, 2018, 12:12 p.m. | #13
On 15/11/2018 21:44, Gabriel F. T. Gomes wrote:
> +/* 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';


note that since this change the following code changed behaviour:

#include <stdio.h>
int main()
{
  char buf[20] = "AB";
  sprintf (buf, "%sCD", buf);
  puts (buf);
}

this is ub in iso c, but previously printed "ABCD", but now
buf[0]=0 before the format string is processed, so it is "CD".

this is a heads up, since this pattern seems to appear in existing code,
in particular in SPEC2017 507.cactuBSSN_r/src/PUGH/PughUtils.c:

sprintf(mess,"  Size:");
for (i=0;i<dim+1;i++)
{
    sprintf(mess,"%s %d",mess,pughGH->GFExtras[dim]->nsize[i]);
}


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

>  }
Florian Weimer Dec. 18, 2018, 4:53 p.m. | #14
* Szabolcs Nagy:

> On 15/11/2018 21:44, Gabriel F. T. Gomes wrote:

>> +/* 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';

>

> note that since this change the following code changed behaviour:

>

> #include <stdio.h>

> int main()

> {

>   char buf[20] = "AB";

>   sprintf (buf, "%sCD", buf);

>   puts (buf);

> }

>

> this is ub in iso c, but previously printed "ABCD", but now

> buf[0]=0 before the format string is processed, so it is "CD".

>

> this is a heads up, since this pattern seems to appear in existing code,

> in particular in SPEC2017 507.cactuBSSN_r/src/PUGH/PughUtils.c:

>

> sprintf(mess,"  Size:");

> for (i=0;i<dim+1;i++)

> {

>     sprintf(mess,"%s %d",mess,pughGH->GFExtras[dim]->nsize[i]);

> }


I think we should make this specific to the fortify flag, even though
it's undefined.

Thanks,
Florian
Gabriel F. T. Gomes Dec. 18, 2018, 5:31 p.m. | #15
On Tue, 18 Dec 2018, Florian Weimer wrote:

>* Szabolcs Nagy:

>

>> On 15/11/2018 21:44, Gabriel F. T. Gomes wrote:  

>>> +/* 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';  

>>

>> note that since this change the following code changed behaviour:

>>

>> #include <stdio.h>

>> int main()

>> {

>>   char buf[20] = "AB";

>>   sprintf (buf, "%sCD", buf);

>>   puts (buf);

>> }

>>

>> this is ub in iso c, but previously printed "ABCD", but now

>> buf[0]=0 before the format string is processed, so it is "CD".

>>

>> this is a heads up, since this pattern seems to appear in existing code,

>> in particular in SPEC2017 507.cactuBSSN_r/src/PUGH/PughUtils.c:

>>

>> sprintf(mess,"  Size:");

>> for (i=0;i<dim+1;i++)

>> {

>>     sprintf(mess,"%s %d",mess,pughGH->GFExtras[dim]->nsize[i]);

>> }  

>

>I think we should make this specific to the fortify flag, even though

>it's undefined.


So, do you think that moving the `string[0] = '\0';' statement from
__vsprintf_internal to ___vsprintf_chk (before the second calls the first)
is an adequate fix?

I could write this with an accompanying test case to avoid regressions in
both fortified and non-fortified cases.
Szabolcs Nagy Dec. 19, 2018, 3:04 p.m. | #16
On 18/12/2018 17:31, Gabriel F. T. Gomes wrote:
> On Tue, 18 Dec 2018, Florian Weimer wrote:

> 

>> * Szabolcs Nagy:

>>

>>> On 15/11/2018 21:44, Gabriel F. T. Gomes wrote:  

>>>> +/* 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';  

>>>

>>> note that since this change the following code changed behaviour:

>>>

>>> #include <stdio.h>

>>> int main()

>>> {

>>>   char buf[20] = "AB";

>>>   sprintf (buf, "%sCD", buf);

>>>   puts (buf);

>>> }

>>>

>>> this is ub in iso c, but previously printed "ABCD", but now

>>> buf[0]=0 before the format string is processed, so it is "CD".

>>>

>>> this is a heads up, since this pattern seems to appear in existing code,

>>> in particular in SPEC2017 507.cactuBSSN_r/src/PUGH/PughUtils.c:

>>>

>>> sprintf(mess,"  Size:");

>>> for (i=0;i<dim+1;i++)

>>> {

>>>     sprintf(mess,"%s %d",mess,pughGH->GFExtras[dim]->nsize[i]);

>>> }  

>>

>> I think we should make this specific to the fortify flag, even though

>> it's undefined.

> 

> So, do you think that moving the `string[0] = '\0';' statement from

> __vsprintf_internal to ___vsprintf_chk (before the second calls the first)

> is an adequate fix?

> 

> I could write this with an accompanying test case to avoid regressions in

> both fortified and non-fortified cases.

> 



i would just do

if (maxlen == -1)
  .. old code ..
else
  .. new code ..

to revert the old sprintf behaviour.

later the code may be refactored further (it should be
possible to use shared code between sprintf, snprintf
and sprintf_chk, but that requires a lot more changes).
Gabriel F. T. Gomes Dec. 20, 2018, 9:55 p.m. | #17
On Wed, 19 Dec 2018, Szabolcs Nagy wrote:
>

>i would just do

>

>if (maxlen == -1)

>  .. old code ..

>else

>  .. new code ..

>

>to revert the old sprintf behaviour.


I found that just checking for maxlen == -1 is not enough for reverting to
the old behavior, because maxlen could be -1 when __vsprintf_internal is
called from __sprintf_chk and __vsprintf_chk (and not only  from sprintf
and vsprintf).  Thus, I added a new macro that __sprintf_chk and
__vsprintf_chk can set (through mode_flags), to let __vsprintf_internal
know where the call came from, then restore the old behavior.

More important to notice is the fact that the overwriting of the
destination buffer is *not* the only behavior affected by the refactoring.
Before the refactoring, sprintf and vsprintf would use _IO_str_jumps,
whereas __sprintf_chk and __vsprintf_chk would use _IO_str_chk_jumps.
After the refactoring, all use _IO_str_chk_jumps, which would make
sprintf and vsprintf report buffer overflows and terminate the program,
which sounds wrong to me (I haven't noticed this effect on sprintf and
vsprintf before, sorry about that. Maybe I should add an extra test to
avoid something similar in the future).

With the new macro, I can install the same jump table that used to be
installed before the refactoring, thus fully reverting to the old
behaviour.  I have just submitted a new patch at:

https://sourceware.org/ml/libc-alpha/2018-12/msg00838.html

>later the code may be refactored further (it should be

>possible to use shared code between sprintf, snprintf

>and sprintf_chk, but that requires a lot more changes).


It wasn't my intention to suggest that sprintf and snprintf should share
code (although I'm not against it)...  I was just referring to *sprintf,
__*sprintf_chk, and __vsprintf_internal.  Perhaps, I did not understand
what you mean with this comment.

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/asprintf_chk.c b/debug/vobprintf_chk.c
similarity index 61%
copy from debug/asprintf_chk.c
copy to debug/vobprintf_chk.c
index 9cd4143f2e..bed2c98eac 100644
--- a/debug/asprintf_chk.c
+++ b/debug/vobprintf_chk.c
@@ -1,4 +1,5 @@ 
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Print output of stream to given obstack.
+   Copyright (C) 2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -15,22 +16,16 @@ 
    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, ...)
+__obstack_vprintf_chk (struct obstack *obstack, int flag, const char *format,
+		       va_list ap)
 {
-  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_start (arg, format);
-  done = __vasprintf_chk (result_ptr, flags, format, arg);
-  va_end (arg);
-
-  return done;
+  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 fe52ef1752..ce5228e382 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)
@@ -818,26 +825,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 b0c86e99bd..4cc4261ead 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -1283,8 +1283,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)