libio: Remove codecvt vtable [BZ #24588]

Message ID 87d0kdjliz.fsf@oldenburg2.str.redhat.com
State New
Headers show
Series
  • libio: Remove codecvt vtable [BZ #24588]
Related show

Commit Message

Florian Weimer May 20, 2019, 1:36 p.m.
The codecvt vtable is not a real vtable because it also contains the
conversion state data.  Furthermore, wide stream support was added to
GCC 3.0, after a C++ ABI bump, so there is no compatibility requirement
with libstdc++.

This change removes several unmangled function pointers which could
be used with a corrupted FILE object to redirect execution.  (libio
vtable verification did not cover the codecvt vtable.)

2019-05-20  Florian Weimer  <fweimer@redhat.com>

	[BZ #24588]
	libio: Remove codecvt vtable.
	* libio/fileops.c ( _IO_new_file_fopen): Do not copy
	__libio_codecvt.
	* libio/iofgetpos.c (_IO_new_fgetpos): Call
	__libio_codecvt_encoding.
	* libio/iofgetpos64.c (_IO_new_fgetpos): Likewise.
	* libio/iofsetpos.c (_IO_new_fsetpos): Likewise.
	* libio/iofsetpos64.c (_IO_new_fsetpos): Likewise.
	* libio/iofwide.c (__libio_codecvt): Remove variable.
	(_IO_fwide): Do not copy __libio_codecvt.
	(__libio_codecvt_out): Rename from do_out and export.
	(do_unshift): Remove function.
	(__libio_codecvt_in): Rename from do_in and export.
	(__libio_codecvt_encoding): Rename from do_encoding and export.
	(do_always_noconv): Remove function.
	(__libio_codecvt_length): Rename from do_length and export.
	(do_max_length): Remove function.
	* libio/libio.h (enum __codecvt_result): Remove definition; moved
	to libioP.h.
	(struct _IO_codecvt): Remove fields __codecvt_destr,
	__codecvt_do_out, __codecvt_do_unshift, __codecvt_do_in,
	__codecvt_do_encoding, __codecvt_do_always_noconv,
	__codecvt_do_length, __codecvt_do_max_length.
	* libio/libioP.h (enum __codecvt_result): Define; moved from
	libio.h.
	(__libio_codecvt_out, __libio_codecvt_in)
	(__libio_codecvt_encoding, __libio_codecvt_length): Declare
	functions.
	* libio/wfileops.c (_IO_wdo_write): Call __libio_codecvt_out.
	(_IO_wfile_underflow): Call __libio_codecvt_in.
	(_IO_wfile_underflow): Likewise.
	(_IO_wfile_underflow_mmap): Likewise.
	(_IO_wfile_sync): Call __libio_codecvt_encoding,
	__libio_codecvt_length.
	(adjust_wide_data): Call __libio_codecvt_encoding,
	__libio_codecvt_in.
	(do_ftell_wide): Call __libio_codecvt_length, __libio_codecvt_out.
	(_IO_wfile_seekoff): Call __libio_codecvt_encoding,
	__libio_codecvt_length.

Comments

Yann Droneaud May 20, 2019, 1:47 p.m. | #1
Hi,

Le lundi 20 mai 2019 à 15:36 +0200, Florian Weimer a écrit :
> The codecvt vtable is not a real vtable because it also contains the

> conversion state data.  Furthermore, wide stream support was added to

> GCC 3.0, after a C++ ABI bump, so there is no compatibility

> requirement

> with libstdc++.

> 

> This change removes several unmangled function pointers which could

> be used with a corrupted FILE object to redirect execution.  (libio

> vtable verification did not cover the codecvt vtable.)

> 

> 2019-05-20  Florian Weimer  <fweimer@redhat.com>

> 

> 	[BZ #24588]

> 	libio: Remove codecvt vtable.

> 	* libio/fileops.c ( _IO_new_file_fopen): Do not copy

> 	__libio_codecvt.

> 	* libio/iofgetpos.c (_IO_new_fgetpos): Call

> 	__libio_codecvt_encoding.

> 	* libio/iofgetpos64.c (_IO_new_fgetpos): Likewise.

> 	* libio/iofsetpos.c (_IO_new_fsetpos): Likewise.

> 	* libio/iofsetpos64.c (_IO_new_fsetpos): Likewise.

> 	* libio/iofwide.c (__libio_codecvt): Remove variable.

> 	(_IO_fwide): Do not copy __libio_codecvt.

> 	(__libio_codecvt_out): Rename from do_out and export.

> 	(do_unshift): Remove function.

> 	(__libio_codecvt_in): Rename from do_in and export.

> 	(__libio_codecvt_encoding): Rename from do_encoding and export.

> 	(do_always_noconv): Remove function.

> 	(__libio_codecvt_length): Rename from do_length and export.

> 	(do_max_length): Remove function.

> 	* libio/libio.h (enum __codecvt_result): Remove definition;

> moved

> 	to libioP.h.

> 	(struct _IO_codecvt): Remove fields __codecvt_destr,

> 	__codecvt_do_out, __codecvt_do_unshift, __codecvt_do_in,

> 	__codecvt_do_encoding, __codecvt_do_always_noconv,

> 	__codecvt_do_length, __codecvt_do_max_length.

> 	* libio/libioP.h (enum __codecvt_result): Define; moved from

> 	libio.h.

> 	(__libio_codecvt_out, __libio_codecvt_in)

> 	(__libio_codecvt_encoding, __libio_codecvt_length): Declare

> 	functions.

> 	* libio/wfileops.c (_IO_wdo_write): Call __libio_codecvt_out.

> 	(_IO_wfile_underflow): Call __libio_codecvt_in.

> 	(_IO_wfile_underflow): Likewise.

> 	(_IO_wfile_underflow_mmap): Likewise.

> 	(_IO_wfile_sync): Call __libio_codecvt_encoding,

> 	__libio_codecvt_length.

> 	(adjust_wide_data): Call __libio_codecvt_encoding,

> 	__libio_codecvt_in.

> 	(do_ftell_wide): Call __libio_codecvt_length,

> __libio_codecvt_out.

> 	(_IO_wfile_seekoff): Call __libio_codecvt_encoding,

> 	__libio_codecvt_length.

> 


Reviewed-by: Yann Droneaud <ydroneaud@opteya.com>


Regards

-- 
Yann Droneaud
OPTEYA
Adhemerval Zanella May 20, 2019, 7:46 p.m. | #2
On 20/05/2019 10:36, Florian Weimer wrote:
> The codecvt vtable is not a real vtable because it also contains the

> conversion state data.  Furthermore, wide stream support was added to

> GCC 3.0, after a C++ ABI bump, so there is no compatibility requirement

> with libstdc++.

> 

> This change removes several unmangled function pointers which could

> be used with a corrupted FILE object to redirect execution.  (libio

> vtable verification did not cover the codecvt vtable.)

> 

> 2019-05-20  Florian Weimer  <fweimer@redhat.com>

> 

> 	[BZ #24588]

> 	libio: Remove codecvt vtable.

> 	* libio/fileops.c ( _IO_new_file_fopen): Do not copy

> 	__libio_codecvt.

> 	* libio/iofgetpos.c (_IO_new_fgetpos): Call

> 	__libio_codecvt_encoding.

> 	* libio/iofgetpos64.c (_IO_new_fgetpos): Likewise.

> 	* libio/iofsetpos.c (_IO_new_fsetpos): Likewise.

> 	* libio/iofsetpos64.c (_IO_new_fsetpos): Likewise.

> 	* libio/iofwide.c (__libio_codecvt): Remove variable.

> 	(_IO_fwide): Do not copy __libio_codecvt.

> 	(__libio_codecvt_out): Rename from do_out and export.

> 	(do_unshift): Remove function.

> 	(__libio_codecvt_in): Rename from do_in and export.

> 	(__libio_codecvt_encoding): Rename from do_encoding and export.

> 	(do_always_noconv): Remove function.

> 	(__libio_codecvt_length): Rename from do_length and export.

> 	(do_max_length): Remove function.

> 	* libio/libio.h (enum __codecvt_result): Remove definition; moved

> 	to libioP.h.

> 	(struct _IO_codecvt): Remove fields __codecvt_destr,

> 	__codecvt_do_out, __codecvt_do_unshift, __codecvt_do_in,

> 	__codecvt_do_encoding, __codecvt_do_always_noconv,

> 	__codecvt_do_length, __codecvt_do_max_length.

> 	* libio/libioP.h (enum __codecvt_result): Define; moved from

> 	libio.h.

> 	(__libio_codecvt_out, __libio_codecvt_in)

> 	(__libio_codecvt_encoding, __libio_codecvt_length): Declare

> 	functions.

> 	* libio/wfileops.c (_IO_wdo_write): Call __libio_codecvt_out.

> 	(_IO_wfile_underflow): Call __libio_codecvt_in.

> 	(_IO_wfile_underflow): Likewise.

> 	(_IO_wfile_underflow_mmap): Likewise.

> 	(_IO_wfile_sync): Call __libio_codecvt_encoding,

> 	__libio_codecvt_length.

> 	(adjust_wide_data): Call __libio_codecvt_encoding,

> 	__libio_codecvt_in.

> 	(do_ftell_wide): Call __libio_codecvt_length, __libio_codecvt_out.

> 	(_IO_wfile_seekoff): Call __libio_codecvt_encoding,

> 	__libio_codecvt_length.


LGTM as well.

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


> 

> diff --git a/libio/fileops.c b/libio/fileops.c

> index d2070a856e..daa5a05877 100644

> --- a/libio/fileops.c

> +++ b/libio/fileops.c

> @@ -331,9 +331,6 @@ _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode,

>  

>  	  cc = fp->_codecvt = &fp->_wide_data->_codecvt;

>  

> -	  /* The functions are always the same.  */

> -	  *cc = __libio_codecvt;

> -

>  	  cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;

>  	  cc->__cd_in.__cd.__steps = fcts.towc;

>  

> diff --git a/libio/iofgetpos.c b/libio/iofgetpos.c

> index 8032192440..388c4a0708 100644

> --- a/libio/iofgetpos.c

> +++ b/libio/iofgetpos.c

> @@ -70,8 +70,7 @@ _IO_new_fgetpos (FILE *fp, __fpos_t *posp)

>    else

>      {

>        posp->__pos = pos;

> -      if (fp->_mode > 0

> -	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)

> +      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)

>  	/* This is a stateful encoding, safe the state.  */

>  	posp->__state = fp->_wide_data->_IO_state;

>      }

> diff --git a/libio/iofgetpos64.c b/libio/iofgetpos64.c

> index 54de6a8205..6a0ba50d29 100644

> --- a/libio/iofgetpos64.c

> +++ b/libio/iofgetpos64.c

> @@ -54,8 +54,7 @@ _IO_new_fgetpos64 (FILE *fp, __fpos64_t *posp)

>    else

>      {

>        posp->__pos = pos;

> -      if (fp->_mode > 0

> -	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)

> +      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)

>  	/* This is a stateful encoding, safe the state.  */

>  	posp->__state = fp->_wide_data->_IO_state;

>      }

> diff --git a/libio/iofsetpos.c b/libio/iofsetpos.c

> index d7b1abbc61..4df1aae082 100644

> --- a/libio/iofsetpos.c

> +++ b/libio/iofsetpos.c

> @@ -58,8 +58,7 @@ _IO_new_fsetpos (FILE *fp, const __fpos_t *posp)

>    else

>      {

>        result = 0;

> -      if (fp->_mode > 0

> -	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)

> +      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)

>  	/* This is a stateful encoding, restore the state.  */

>  	fp->_wide_data->_IO_state = posp->__state;

>      }

> diff --git a/libio/iofsetpos64.c b/libio/iofsetpos64.c

> index d1865b728e..f382ba0dc1 100644

> --- a/libio/iofsetpos64.c

> +++ b/libio/iofsetpos64.c

> @@ -48,8 +48,7 @@ _IO_new_fsetpos64 (FILE *fp, const fpos64_t *posp)

>    else

>      {

>        result = 0;

> -      if (fp->_mode > 0

> -	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)

> +      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)

>  	/* This is a stateful encoding, safe the state.  */

>  	fp->_wide_data->_IO_state = posp->__state;

>      }

> diff --git a/libio/iofwide.c b/libio/iofwide.c

> index 247cfde3d0..80cb2d5074 100644

> --- a/libio/iofwide.c

> +++ b/libio/iofwide.c

> @@ -39,44 +39,6 @@

>  #include <sysdep.h>

>  

>  

> -/* Prototypes of libio's codecvt functions.  */

> -static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,

> -				     __mbstate_t *statep,

> -				     const wchar_t *from_start,

> -				     const wchar_t *from_end,

> -				     const wchar_t **from_stop, char *to_start,

> -				     char *to_end, char **to_stop);

> -static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,

> -					 __mbstate_t *statep, char *to_start,

> -					 char *to_end, char **to_stop);

> -static enum __codecvt_result do_in (struct _IO_codecvt *codecvt,

> -				    __mbstate_t *statep,

> -				    const char *from_start,

> -				    const char *from_end,

> -				    const char **from_stop, wchar_t *to_start,

> -				    wchar_t *to_end, wchar_t **to_stop);

> -static int do_encoding (struct _IO_codecvt *codecvt);

> -static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,

> -		      const char *from_start,

> -		      const char *from_end, size_t max);

> -static int do_max_length (struct _IO_codecvt *codecvt);

> -static int do_always_noconv (struct _IO_codecvt *codecvt);

> -

> -

> -/* The functions used in `codecvt' for libio are always the same.  */

> -const struct _IO_codecvt __libio_codecvt =

> -{

> -  .__codecvt_destr = NULL,		/* Destructor, never used.  */

> -  .__codecvt_do_out = do_out,

> -  .__codecvt_do_unshift = do_unshift,

> -  .__codecvt_do_in = do_in,

> -  .__codecvt_do_encoding = do_encoding,

> -  .__codecvt_do_always_noconv = do_always_noconv,

> -  .__codecvt_do_length = do_length,

> -  .__codecvt_do_max_length = do_max_length

> -};

> -

> -

>  /* Return orientation of stream.  If mode is nonzero try to change

>     the orientation first.  */

>  #undef _IO_fwide

> @@ -118,9 +80,6 @@ _IO_fwide (FILE *fp, int mode)

>  	assert (fcts.towc_nsteps == 1);

>  	assert (fcts.tomb_nsteps == 1);

>  

> -	/* The functions are always the same.  */

> -	*cc = __libio_codecvt;

> -

>  	cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;

>  	cc->__cd_in.__cd.__steps = fcts.towc;

>  

> @@ -150,11 +109,11 @@ _IO_fwide (FILE *fp, int mode)

>  }

>  

>  

> -static enum __codecvt_result

> -do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,

> -	const wchar_t *from_start, const wchar_t *from_end,

> -	const wchar_t **from_stop, char *to_start, char *to_end,

> -	char **to_stop)

> +enum __codecvt_result

> +__libio_codecvt_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,

> +		     const wchar_t *from_start, const wchar_t *from_end,

> +		     const wchar_t **from_stop, char *to_start, char *to_end,

> +		     char **to_stop)

>  {

>    enum __codecvt_result result;

>  

> @@ -202,57 +161,11 @@ do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,

>  }

>  

>  

> -static enum __codecvt_result

> -do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,

> -	    char *to_start, char *to_end, char **to_stop)

> -{

> -  enum __codecvt_result result;

> -

> -  struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;

> -  int status;

> -  size_t dummy;

> -

> -  codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;

> -  codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;

> -  codecvt->__cd_out.__cd.__data[0].__statep = statep;

> -

> -  __gconv_fct fct = gs->__fct;

> -#ifdef PTR_DEMANGLE

> -  if (gs->__shlib_handle != NULL)

> -    PTR_DEMANGLE (fct);

> -#endif

> -

> -  status = DL_CALL_FCT (fct,

> -			(gs, codecvt->__cd_out.__cd.__data, NULL, NULL,

> -			 NULL, &dummy, 1, 0));

> -

> -  *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;

> -

> -  switch (status)

> -    {

> -    case __GCONV_OK:

> -    case __GCONV_EMPTY_INPUT:

> -      result = __codecvt_ok;

> -      break;

> -

> -    case __GCONV_FULL_OUTPUT:

> -    case __GCONV_INCOMPLETE_INPUT:

> -      result = __codecvt_partial;

> -      break;

> -

> -    default:

> -      result = __codecvt_error;

> -      break;

> -    }

> -

> -  return result;

> -}

> -

> -

> -static enum __codecvt_result

> -do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,

> -       const char *from_start, const char *from_end, const char **from_stop,

> -       wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)

> +enum __codecvt_result

> +__libio_codecvt_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,

> +		    const char *from_start, const char *from_end,

> +		    const char **from_stop,

> +		    wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)

>  {

>    enum __codecvt_result result;

>  

> @@ -300,8 +213,8 @@ do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,

>  }

>  

>  

> -static int

> -do_encoding (struct _IO_codecvt *codecvt)

> +int

> +__libio_codecvt_encoding (struct _IO_codecvt *codecvt)

>  {

>    /* See whether the encoding is stateful.  */

>    if (codecvt->__cd_in.__cd.__steps[0].__stateful)

> @@ -317,16 +230,10 @@ do_encoding (struct _IO_codecvt *codecvt)

>  }

>  

>  

> -static int

> -do_always_noconv (struct _IO_codecvt *codecvt)

> -{

> -  return 0;

> -}

> -

> -

> -static int

> -do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,

> -	   const char *from_start, const char *from_end, size_t max)

> +int

> +__libio_codecvt_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,

> +			const char *from_start, const char *from_end,

> +			size_t max)

>  {

>    int result;

>    const unsigned char *cp = (const unsigned char *) from_start;

> @@ -353,10 +260,3 @@ do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,

>  

>    return result;

>  }

> -

> -

> -static int

> -do_max_length (struct _IO_codecvt *codecvt)

> -{

> -  return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;

> -}

> diff --git a/libio/libio.h b/libio/libio.h

> index c38095ff77..b985c386a2 100644

> --- a/libio/libio.h

> +++ b/libio/libio.h

> @@ -116,40 +116,8 @@ struct _IO_marker {

>    int _pos;

>  };

>  

> -/* This is the structure from the libstdc++ codecvt class.  */

> -enum __codecvt_result

> -{

> -  __codecvt_ok,

> -  __codecvt_partial,

> -  __codecvt_error,

> -  __codecvt_noconv

> -};

> -

> -/* The order of the elements in the following struct must match the order

> -   of the virtual functions in the libstdc++ codecvt class.  */

>  struct _IO_codecvt

>  {

> -  void (*__codecvt_destr) (struct _IO_codecvt *);

> -  enum __codecvt_result (*__codecvt_do_out) (struct _IO_codecvt *,

> -					     __mbstate_t *,

> -					     const wchar_t *,

> -					     const wchar_t *,

> -					     const wchar_t **, char *,

> -					     char *, char **);

> -  enum __codecvt_result (*__codecvt_do_unshift) (struct _IO_codecvt *,

> -						 __mbstate_t *, char *,

> -						 char *, char **);

> -  enum __codecvt_result (*__codecvt_do_in) (struct _IO_codecvt *,

> -					    __mbstate_t *,

> -					    const char *, const char *,

> -					    const char **, wchar_t *,

> -					    wchar_t *, wchar_t **);

> -  int (*__codecvt_do_encoding) (struct _IO_codecvt *);

> -  int (*__codecvt_do_always_noconv) (struct _IO_codecvt *);

> -  int (*__codecvt_do_length) (struct _IO_codecvt *, __mbstate_t *,

> -			      const char *, const char *, size_t);

> -  int (*__codecvt_do_max_length) (struct _IO_codecvt *);

> -

>    _IO_iconv_t __cd_in;

>    _IO_iconv_t __cd_out;

>  };

> diff --git a/libio/libioP.h b/libio/libioP.h

> index 7bdec86a62..66afaa8968 100644

> --- a/libio/libioP.h

> +++ b/libio/libioP.h

> @@ -476,7 +476,6 @@ extern const struct _IO_jump_t _IO_streambuf_jumps;

>  extern const struct _IO_jump_t _IO_old_proc_jumps attribute_hidden;

>  extern const struct _IO_jump_t _IO_str_jumps attribute_hidden;

>  extern const struct _IO_jump_t _IO_wstr_jumps attribute_hidden;

> -extern const struct _IO_codecvt __libio_codecvt attribute_hidden;

>  extern int _IO_do_write (FILE *, const char *, size_t);

>  libc_hidden_proto (_IO_do_write)

>  extern int _IO_new_do_write (FILE *, const char *, size_t);

> @@ -932,4 +931,32 @@ IO_validate_vtable (const struct _IO_jump_t *vtable)

>    return vtable;

>  }

>  

> +/* Character set conversion.  */

> +

> +enum __codecvt_result

> +{

> +  __codecvt_ok,

> +  __codecvt_partial,

> +  __codecvt_error,

> +  __codecvt_noconv

> +};

> +

> +enum __codecvt_result __libio_codecvt_out (struct _IO_codecvt *,

> +					   __mbstate_t *,

> +					   const wchar_t *,

> +					   const wchar_t *,

> +					   const wchar_t **, char *,

> +					   char *, char **)

> +  attribute_hidden;

> +enum __codecvt_result __libio_codecvt_in (struct _IO_codecvt *,

> +					  __mbstate_t *,

> +					  const char *, const char *,

> +					  const char **, wchar_t *,

> +					  wchar_t *, wchar_t **)

> +  attribute_hidden;

> +int __libio_codecvt_encoding (struct _IO_codecvt *) attribute_hidden;

> +int __libio_codecvt_length (struct _IO_codecvt *, __mbstate_t *,

> +			    const char *, const char *, size_t)

> +  attribute_hidden;

> +

>  #endif /* libioP.h.  */

> diff --git a/libio/wfileops.c b/libio/wfileops.c

> index 69fbb62a02..f1863db638 100644

> --- a/libio/wfileops.c

> +++ b/libio/wfileops.c

> @@ -72,11 +72,11 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do)

>  	    }

>  

>  	  /* Now convert from the internal format into the external buffer.  */

> -	  result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,

> -					    data, data + to_do, &new_data,

> -					    write_ptr,

> -					    buf_end,

> -					    &write_ptr);

> +	  result = __libio_codecvt_out (cc, &fp->_wide_data->_IO_state,

> +					data, data + to_do, &new_data,

> +					write_ptr,

> +					buf_end,

> +					&write_ptr);

>  

>  	  /* Write out what we produced so far.  */

>  	  if (_IO_new_do_write (fp, write_base, write_ptr - write_base) == EOF)

> @@ -140,12 +140,12 @@ _IO_wfile_underflow (FILE *fp)

>        fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;

>        fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =

>  	fp->_wide_data->_IO_buf_base;

> -      status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,

> -				       fp->_IO_read_ptr, fp->_IO_read_end,

> -				       &read_stop,

> -				       fp->_wide_data->_IO_read_ptr,

> -				       fp->_wide_data->_IO_buf_end,

> -				       &fp->_wide_data->_IO_read_end);

> +      status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,

> +				   fp->_IO_read_ptr, fp->_IO_read_end,

> +				   &read_stop,

> +				   fp->_wide_data->_IO_read_ptr,

> +				   fp->_wide_data->_IO_buf_end,

> +				   &fp->_wide_data->_IO_read_end);

>  

>        fp->_IO_read_base = fp->_IO_read_ptr;

>        fp->_IO_read_ptr = (char *) read_stop;

> @@ -266,11 +266,11 @@ _IO_wfile_underflow (FILE *fp)

>        naccbuf += to_copy;

>        from = accbuf;

>      }

> -  status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,

> -				   from, to, &read_ptr_copy,

> -				   fp->_wide_data->_IO_read_end,

> -				   fp->_wide_data->_IO_buf_end,

> -				   &fp->_wide_data->_IO_read_end);

> +  status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,

> +			       from, to, &read_ptr_copy,

> +			       fp->_wide_data->_IO_read_end,

> +			       fp->_wide_data->_IO_buf_end,

> +			       &fp->_wide_data->_IO_read_end);

>  

>    if (__glibc_unlikely (naccbuf != 0))

>      fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);

> @@ -372,12 +372,12 @@ _IO_wfile_underflow_mmap (FILE *fp)

>    fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;

>    fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =

>      fp->_wide_data->_IO_buf_base;

> -  (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,

> -			  fp->_IO_read_ptr, fp->_IO_read_end,

> -			  &read_stop,

> -			  fp->_wide_data->_IO_read_ptr,

> -			  fp->_wide_data->_IO_buf_end,

> -			  &fp->_wide_data->_IO_read_end);

> +  __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,

> +		      fp->_IO_read_ptr, fp->_IO_read_end,

> +		      &read_stop,

> +		      fp->_wide_data->_IO_read_ptr,

> +		      fp->_wide_data->_IO_buf_end,

> +		      &fp->_wide_data->_IO_read_end);

>  

>    fp->_IO_read_ptr = (char *) read_stop;

>  

> @@ -495,7 +495,7 @@ _IO_wfile_sync (FILE *fp)

>        struct _IO_codecvt *cv = fp->_codecvt;

>        off64_t new_pos;

>  

> -      int clen = (*cv->__codecvt_do_encoding) (cv);

> +      int clen = __libio_codecvt_encoding (cv);

>  

>        if (clen > 0)

>  	/* It is easy, a fixed number of input bytes are used for each

> @@ -511,9 +511,9 @@ _IO_wfile_sync (FILE *fp)

>  	  size_t wnread = (fp->_wide_data->_IO_read_ptr

>  			   - fp->_wide_data->_IO_read_base);

>  	  fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;

> -	  nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,

> -					      fp->_IO_read_base,

> -					      fp->_IO_read_end, wnread);

> +	  nread = __libio_codecvt_length (cv, &fp->_wide_data->_IO_state,

> +					  fp->_IO_read_base,

> +					  fp->_IO_read_end, wnread);

>  	  fp->_IO_read_ptr = fp->_IO_read_base + nread;

>  	  delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);

>  	}

> @@ -548,7 +548,7 @@ adjust_wide_data (FILE *fp, bool do_convert)

>  {

>    struct _IO_codecvt *cv = fp->_codecvt;

>  

> -  int clen = (*cv->__codecvt_do_encoding) (cv);

> +  int clen = __libio_codecvt_encoding (cv);

>  

>    /* Take the easy way out for constant length encodings if we don't need to

>       convert.  */

> @@ -565,12 +565,12 @@ adjust_wide_data (FILE *fp, bool do_convert)

>      {

>  

>        fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;

> -      status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,

> -				       fp->_IO_read_base, fp->_IO_read_ptr,

> -				       &read_stop,

> -				       fp->_wide_data->_IO_read_base,

> -				       fp->_wide_data->_IO_buf_end,

> -				       &fp->_wide_data->_IO_read_end);

> +      status = __libio_codecvt_in (cv, &fp->_wide_data->_IO_state,

> +				   fp->_IO_read_base, fp->_IO_read_ptr,

> +				   &read_stop,

> +				   fp->_wide_data->_IO_read_base,

> +				   fp->_wide_data->_IO_buf_end,

> +				   &fp->_wide_data->_IO_read_end);

>  

>        /* Should we return EILSEQ?  */

>        if (__glibc_unlikely (status == __codecvt_error))

> @@ -648,7 +648,7 @@ do_ftell_wide (FILE *fp)

>  	}

>  

>        struct _IO_codecvt *cv = fp->_codecvt;

> -      int clen = (*cv->__codecvt_do_encoding) (cv);

> +      int clen = __libio_codecvt_encoding (cv);

>  

>        if (!unflushed_writes)

>  	{

> @@ -663,9 +663,9 @@ do_ftell_wide (FILE *fp)

>  

>  	      size_t delta = wide_read_ptr - wide_read_base;

>  	      __mbstate_t state = fp->_wide_data->_IO_last_state;

> -	      nread = (*cv->__codecvt_do_length) (cv, &state,

> -						  fp->_IO_read_base,

> -						  fp->_IO_read_end, delta);

> +	      nread = __libio_codecvt_length (cv, &state,

> +					      fp->_IO_read_base,

> +					      fp->_IO_read_end, delta);

>  	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;

>  	    }

>  	}

> @@ -688,9 +688,8 @@ do_ftell_wide (FILE *fp)

>  	      enum __codecvt_result status;

>  

>  	      __mbstate_t state = fp->_wide_data->_IO_last_state;

> -	      status = (*cv->__codecvt_do_out) (cv, &state,

> -						in, in + delta, &in,

> -						out, out + outsize, &outstop);

> +	      status = __libio_codecvt_out (cv, &state, in, in + delta, &in,

> +					    out, out + outsize, &outstop);

>  

>  	      /* We don't check for __codecvt_partial because it can be

>  		 returned on one of two conditions: either the output

> @@ -801,7 +800,7 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)

>  	 find out which position in the external buffer corresponds to

>  	 the current position in the internal buffer.  */

>        cv = fp->_codecvt;

> -      clen = (*cv->__codecvt_do_encoding) (cv);

> +      clen = __libio_codecvt_encoding (cv);

>  

>        if (mode != 0 || !was_writing)

>  	{

> @@ -819,10 +818,10 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)

>  	      delta = (fp->_wide_data->_IO_read_ptr

>  		       - fp->_wide_data->_IO_read_base);

>  	      fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;

> -	      nread = (*cv->__codecvt_do_length) (cv,

> -						  &fp->_wide_data->_IO_state,

> -						  fp->_IO_read_base,

> -						  fp->_IO_read_end, delta);

> +	      nread = __libio_codecvt_length (cv,

> +					      &fp->_wide_data->_IO_state,

> +					      fp->_IO_read_base,

> +					      fp->_IO_read_end, delta);

>  	      fp->_IO_read_ptr = fp->_IO_read_base + nread;

>  	      fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;

>  	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;

>

Patch

diff --git a/libio/fileops.c b/libio/fileops.c
index d2070a856e..daa5a05877 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -331,9 +331,6 @@  _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode,
 
 	  cc = fp->_codecvt = &fp->_wide_data->_codecvt;
 
-	  /* The functions are always the same.  */
-	  *cc = __libio_codecvt;
-
 	  cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
 	  cc->__cd_in.__cd.__steps = fcts.towc;
 
diff --git a/libio/iofgetpos.c b/libio/iofgetpos.c
index 8032192440..388c4a0708 100644
--- a/libio/iofgetpos.c
+++ b/libio/iofgetpos.c
@@ -70,8 +70,7 @@  _IO_new_fgetpos (FILE *fp, __fpos_t *posp)
   else
     {
       posp->__pos = pos;
-      if (fp->_mode > 0
-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
+      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
 	/* This is a stateful encoding, safe the state.  */
 	posp->__state = fp->_wide_data->_IO_state;
     }
diff --git a/libio/iofgetpos64.c b/libio/iofgetpos64.c
index 54de6a8205..6a0ba50d29 100644
--- a/libio/iofgetpos64.c
+++ b/libio/iofgetpos64.c
@@ -54,8 +54,7 @@  _IO_new_fgetpos64 (FILE *fp, __fpos64_t *posp)
   else
     {
       posp->__pos = pos;
-      if (fp->_mode > 0
-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
+      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
 	/* This is a stateful encoding, safe the state.  */
 	posp->__state = fp->_wide_data->_IO_state;
     }
diff --git a/libio/iofsetpos.c b/libio/iofsetpos.c
index d7b1abbc61..4df1aae082 100644
--- a/libio/iofsetpos.c
+++ b/libio/iofsetpos.c
@@ -58,8 +58,7 @@  _IO_new_fsetpos (FILE *fp, const __fpos_t *posp)
   else
     {
       result = 0;
-      if (fp->_mode > 0
-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
+      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
 	/* This is a stateful encoding, restore the state.  */
 	fp->_wide_data->_IO_state = posp->__state;
     }
diff --git a/libio/iofsetpos64.c b/libio/iofsetpos64.c
index d1865b728e..f382ba0dc1 100644
--- a/libio/iofsetpos64.c
+++ b/libio/iofsetpos64.c
@@ -48,8 +48,7 @@  _IO_new_fsetpos64 (FILE *fp, const fpos64_t *posp)
   else
     {
       result = 0;
-      if (fp->_mode > 0
-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
+      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
 	/* This is a stateful encoding, safe the state.  */
 	fp->_wide_data->_IO_state = posp->__state;
     }
diff --git a/libio/iofwide.c b/libio/iofwide.c
index 247cfde3d0..80cb2d5074 100644
--- a/libio/iofwide.c
+++ b/libio/iofwide.c
@@ -39,44 +39,6 @@ 
 #include <sysdep.h>
 
 
-/* Prototypes of libio's codecvt functions.  */
-static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
-				     __mbstate_t *statep,
-				     const wchar_t *from_start,
-				     const wchar_t *from_end,
-				     const wchar_t **from_stop, char *to_start,
-				     char *to_end, char **to_stop);
-static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,
-					 __mbstate_t *statep, char *to_start,
-					 char *to_end, char **to_stop);
-static enum __codecvt_result do_in (struct _IO_codecvt *codecvt,
-				    __mbstate_t *statep,
-				    const char *from_start,
-				    const char *from_end,
-				    const char **from_stop, wchar_t *to_start,
-				    wchar_t *to_end, wchar_t **to_stop);
-static int do_encoding (struct _IO_codecvt *codecvt);
-static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
-		      const char *from_start,
-		      const char *from_end, size_t max);
-static int do_max_length (struct _IO_codecvt *codecvt);
-static int do_always_noconv (struct _IO_codecvt *codecvt);
-
-
-/* The functions used in `codecvt' for libio are always the same.  */
-const struct _IO_codecvt __libio_codecvt =
-{
-  .__codecvt_destr = NULL,		/* Destructor, never used.  */
-  .__codecvt_do_out = do_out,
-  .__codecvt_do_unshift = do_unshift,
-  .__codecvt_do_in = do_in,
-  .__codecvt_do_encoding = do_encoding,
-  .__codecvt_do_always_noconv = do_always_noconv,
-  .__codecvt_do_length = do_length,
-  .__codecvt_do_max_length = do_max_length
-};
-
-
 /* Return orientation of stream.  If mode is nonzero try to change
    the orientation first.  */
 #undef _IO_fwide
@@ -118,9 +80,6 @@  _IO_fwide (FILE *fp, int mode)
 	assert (fcts.towc_nsteps == 1);
 	assert (fcts.tomb_nsteps == 1);
 
-	/* The functions are always the same.  */
-	*cc = __libio_codecvt;
-
 	cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
 	cc->__cd_in.__cd.__steps = fcts.towc;
 
@@ -150,11 +109,11 @@  _IO_fwide (FILE *fp, int mode)
 }
 
 
-static enum __codecvt_result
-do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
-	const wchar_t *from_start, const wchar_t *from_end,
-	const wchar_t **from_stop, char *to_start, char *to_end,
-	char **to_stop)
+enum __codecvt_result
+__libio_codecvt_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+		     const wchar_t *from_start, const wchar_t *from_end,
+		     const wchar_t **from_stop, char *to_start, char *to_end,
+		     char **to_stop)
 {
   enum __codecvt_result result;
 
@@ -202,57 +161,11 @@  do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
 }
 
 
-static enum __codecvt_result
-do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
-	    char *to_start, char *to_end, char **to_stop)
-{
-  enum __codecvt_result result;
-
-  struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
-  int status;
-  size_t dummy;
-
-  codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;
-  codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;
-  codecvt->__cd_out.__cd.__data[0].__statep = statep;
-
-  __gconv_fct fct = gs->__fct;
-#ifdef PTR_DEMANGLE
-  if (gs->__shlib_handle != NULL)
-    PTR_DEMANGLE (fct);
-#endif
-
-  status = DL_CALL_FCT (fct,
-			(gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
-			 NULL, &dummy, 1, 0));
-
-  *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;
-
-  switch (status)
-    {
-    case __GCONV_OK:
-    case __GCONV_EMPTY_INPUT:
-      result = __codecvt_ok;
-      break;
-
-    case __GCONV_FULL_OUTPUT:
-    case __GCONV_INCOMPLETE_INPUT:
-      result = __codecvt_partial;
-      break;
-
-    default:
-      result = __codecvt_error;
-      break;
-    }
-
-  return result;
-}
-
-
-static enum __codecvt_result
-do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
-       const char *from_start, const char *from_end, const char **from_stop,
-       wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
+enum __codecvt_result
+__libio_codecvt_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+		    const char *from_start, const char *from_end,
+		    const char **from_stop,
+		    wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
 {
   enum __codecvt_result result;
 
@@ -300,8 +213,8 @@  do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
 }
 
 
-static int
-do_encoding (struct _IO_codecvt *codecvt)
+int
+__libio_codecvt_encoding (struct _IO_codecvt *codecvt)
 {
   /* See whether the encoding is stateful.  */
   if (codecvt->__cd_in.__cd.__steps[0].__stateful)
@@ -317,16 +230,10 @@  do_encoding (struct _IO_codecvt *codecvt)
 }
 
 
-static int
-do_always_noconv (struct _IO_codecvt *codecvt)
-{
-  return 0;
-}
-
-
-static int
-do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
-	   const char *from_start, const char *from_end, size_t max)
+int
+__libio_codecvt_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+			const char *from_start, const char *from_end,
+			size_t max)
 {
   int result;
   const unsigned char *cp = (const unsigned char *) from_start;
@@ -353,10 +260,3 @@  do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
 
   return result;
 }
-
-
-static int
-do_max_length (struct _IO_codecvt *codecvt)
-{
-  return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;
-}
diff --git a/libio/libio.h b/libio/libio.h
index c38095ff77..b985c386a2 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -116,40 +116,8 @@  struct _IO_marker {
   int _pos;
 };
 
-/* This is the structure from the libstdc++ codecvt class.  */
-enum __codecvt_result
-{
-  __codecvt_ok,
-  __codecvt_partial,
-  __codecvt_error,
-  __codecvt_noconv
-};
-
-/* The order of the elements in the following struct must match the order
-   of the virtual functions in the libstdc++ codecvt class.  */
 struct _IO_codecvt
 {
-  void (*__codecvt_destr) (struct _IO_codecvt *);
-  enum __codecvt_result (*__codecvt_do_out) (struct _IO_codecvt *,
-					     __mbstate_t *,
-					     const wchar_t *,
-					     const wchar_t *,
-					     const wchar_t **, char *,
-					     char *, char **);
-  enum __codecvt_result (*__codecvt_do_unshift) (struct _IO_codecvt *,
-						 __mbstate_t *, char *,
-						 char *, char **);
-  enum __codecvt_result (*__codecvt_do_in) (struct _IO_codecvt *,
-					    __mbstate_t *,
-					    const char *, const char *,
-					    const char **, wchar_t *,
-					    wchar_t *, wchar_t **);
-  int (*__codecvt_do_encoding) (struct _IO_codecvt *);
-  int (*__codecvt_do_always_noconv) (struct _IO_codecvt *);
-  int (*__codecvt_do_length) (struct _IO_codecvt *, __mbstate_t *,
-			      const char *, const char *, size_t);
-  int (*__codecvt_do_max_length) (struct _IO_codecvt *);
-
   _IO_iconv_t __cd_in;
   _IO_iconv_t __cd_out;
 };
diff --git a/libio/libioP.h b/libio/libioP.h
index 7bdec86a62..66afaa8968 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -476,7 +476,6 @@  extern const struct _IO_jump_t _IO_streambuf_jumps;
 extern const struct _IO_jump_t _IO_old_proc_jumps attribute_hidden;
 extern const struct _IO_jump_t _IO_str_jumps attribute_hidden;
 extern const struct _IO_jump_t _IO_wstr_jumps attribute_hidden;
-extern const struct _IO_codecvt __libio_codecvt attribute_hidden;
 extern int _IO_do_write (FILE *, const char *, size_t);
 libc_hidden_proto (_IO_do_write)
 extern int _IO_new_do_write (FILE *, const char *, size_t);
@@ -932,4 +931,32 @@  IO_validate_vtable (const struct _IO_jump_t *vtable)
   return vtable;
 }
 
+/* Character set conversion.  */
+
+enum __codecvt_result
+{
+  __codecvt_ok,
+  __codecvt_partial,
+  __codecvt_error,
+  __codecvt_noconv
+};
+
+enum __codecvt_result __libio_codecvt_out (struct _IO_codecvt *,
+					   __mbstate_t *,
+					   const wchar_t *,
+					   const wchar_t *,
+					   const wchar_t **, char *,
+					   char *, char **)
+  attribute_hidden;
+enum __codecvt_result __libio_codecvt_in (struct _IO_codecvt *,
+					  __mbstate_t *,
+					  const char *, const char *,
+					  const char **, wchar_t *,
+					  wchar_t *, wchar_t **)
+  attribute_hidden;
+int __libio_codecvt_encoding (struct _IO_codecvt *) attribute_hidden;
+int __libio_codecvt_length (struct _IO_codecvt *, __mbstate_t *,
+			    const char *, const char *, size_t)
+  attribute_hidden;
+
 #endif /* libioP.h.  */
diff --git a/libio/wfileops.c b/libio/wfileops.c
index 69fbb62a02..f1863db638 100644
--- a/libio/wfileops.c
+++ b/libio/wfileops.c
@@ -72,11 +72,11 @@  _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do)
 	    }
 
 	  /* Now convert from the internal format into the external buffer.  */
-	  result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
-					    data, data + to_do, &new_data,
-					    write_ptr,
-					    buf_end,
-					    &write_ptr);
+	  result = __libio_codecvt_out (cc, &fp->_wide_data->_IO_state,
+					data, data + to_do, &new_data,
+					write_ptr,
+					buf_end,
+					&write_ptr);
 
 	  /* Write out what we produced so far.  */
 	  if (_IO_new_do_write (fp, write_base, write_ptr - write_base) == EOF)
@@ -140,12 +140,12 @@  _IO_wfile_underflow (FILE *fp)
       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
       fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
 	fp->_wide_data->_IO_buf_base;
-      status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
-				       fp->_IO_read_ptr, fp->_IO_read_end,
-				       &read_stop,
-				       fp->_wide_data->_IO_read_ptr,
-				       fp->_wide_data->_IO_buf_end,
-				       &fp->_wide_data->_IO_read_end);
+      status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
+				   fp->_IO_read_ptr, fp->_IO_read_end,
+				   &read_stop,
+				   fp->_wide_data->_IO_read_ptr,
+				   fp->_wide_data->_IO_buf_end,
+				   &fp->_wide_data->_IO_read_end);
 
       fp->_IO_read_base = fp->_IO_read_ptr;
       fp->_IO_read_ptr = (char *) read_stop;
@@ -266,11 +266,11 @@  _IO_wfile_underflow (FILE *fp)
       naccbuf += to_copy;
       from = accbuf;
     }
-  status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
-				   from, to, &read_ptr_copy,
-				   fp->_wide_data->_IO_read_end,
-				   fp->_wide_data->_IO_buf_end,
-				   &fp->_wide_data->_IO_read_end);
+  status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
+			       from, to, &read_ptr_copy,
+			       fp->_wide_data->_IO_read_end,
+			       fp->_wide_data->_IO_buf_end,
+			       &fp->_wide_data->_IO_read_end);
 
   if (__glibc_unlikely (naccbuf != 0))
     fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
@@ -372,12 +372,12 @@  _IO_wfile_underflow_mmap (FILE *fp)
   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
     fp->_wide_data->_IO_buf_base;
-  (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
-			  fp->_IO_read_ptr, fp->_IO_read_end,
-			  &read_stop,
-			  fp->_wide_data->_IO_read_ptr,
-			  fp->_wide_data->_IO_buf_end,
-			  &fp->_wide_data->_IO_read_end);
+  __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
+		      fp->_IO_read_ptr, fp->_IO_read_end,
+		      &read_stop,
+		      fp->_wide_data->_IO_read_ptr,
+		      fp->_wide_data->_IO_buf_end,
+		      &fp->_wide_data->_IO_read_end);
 
   fp->_IO_read_ptr = (char *) read_stop;
 
@@ -495,7 +495,7 @@  _IO_wfile_sync (FILE *fp)
       struct _IO_codecvt *cv = fp->_codecvt;
       off64_t new_pos;
 
-      int clen = (*cv->__codecvt_do_encoding) (cv);
+      int clen = __libio_codecvt_encoding (cv);
 
       if (clen > 0)
 	/* It is easy, a fixed number of input bytes are used for each
@@ -511,9 +511,9 @@  _IO_wfile_sync (FILE *fp)
 	  size_t wnread = (fp->_wide_data->_IO_read_ptr
 			   - fp->_wide_data->_IO_read_base);
 	  fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
-	  nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
-					      fp->_IO_read_base,
-					      fp->_IO_read_end, wnread);
+	  nread = __libio_codecvt_length (cv, &fp->_wide_data->_IO_state,
+					  fp->_IO_read_base,
+					  fp->_IO_read_end, wnread);
 	  fp->_IO_read_ptr = fp->_IO_read_base + nread;
 	  delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
 	}
@@ -548,7 +548,7 @@  adjust_wide_data (FILE *fp, bool do_convert)
 {
   struct _IO_codecvt *cv = fp->_codecvt;
 
-  int clen = (*cv->__codecvt_do_encoding) (cv);
+  int clen = __libio_codecvt_encoding (cv);
 
   /* Take the easy way out for constant length encodings if we don't need to
      convert.  */
@@ -565,12 +565,12 @@  adjust_wide_data (FILE *fp, bool do_convert)
     {
 
       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
-      status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
-				       fp->_IO_read_base, fp->_IO_read_ptr,
-				       &read_stop,
-				       fp->_wide_data->_IO_read_base,
-				       fp->_wide_data->_IO_buf_end,
-				       &fp->_wide_data->_IO_read_end);
+      status = __libio_codecvt_in (cv, &fp->_wide_data->_IO_state,
+				   fp->_IO_read_base, fp->_IO_read_ptr,
+				   &read_stop,
+				   fp->_wide_data->_IO_read_base,
+				   fp->_wide_data->_IO_buf_end,
+				   &fp->_wide_data->_IO_read_end);
 
       /* Should we return EILSEQ?  */
       if (__glibc_unlikely (status == __codecvt_error))
@@ -648,7 +648,7 @@  do_ftell_wide (FILE *fp)
 	}
 
       struct _IO_codecvt *cv = fp->_codecvt;
-      int clen = (*cv->__codecvt_do_encoding) (cv);
+      int clen = __libio_codecvt_encoding (cv);
 
       if (!unflushed_writes)
 	{
@@ -663,9 +663,9 @@  do_ftell_wide (FILE *fp)
 
 	      size_t delta = wide_read_ptr - wide_read_base;
 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
-	      nread = (*cv->__codecvt_do_length) (cv, &state,
-						  fp->_IO_read_base,
-						  fp->_IO_read_end, delta);
+	      nread = __libio_codecvt_length (cv, &state,
+					      fp->_IO_read_base,
+					      fp->_IO_read_end, delta);
 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
 	    }
 	}
@@ -688,9 +688,8 @@  do_ftell_wide (FILE *fp)
 	      enum __codecvt_result status;
 
 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
-	      status = (*cv->__codecvt_do_out) (cv, &state,
-						in, in + delta, &in,
-						out, out + outsize, &outstop);
+	      status = __libio_codecvt_out (cv, &state, in, in + delta, &in,
+					    out, out + outsize, &outstop);
 
 	      /* We don't check for __codecvt_partial because it can be
 		 returned on one of two conditions: either the output
@@ -801,7 +800,7 @@  _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
 	 find out which position in the external buffer corresponds to
 	 the current position in the internal buffer.  */
       cv = fp->_codecvt;
-      clen = (*cv->__codecvt_do_encoding) (cv);
+      clen = __libio_codecvt_encoding (cv);
 
       if (mode != 0 || !was_writing)
 	{
@@ -819,10 +818,10 @@  _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
 	      delta = (fp->_wide_data->_IO_read_ptr
 		       - fp->_wide_data->_IO_read_base);
 	      fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
-	      nread = (*cv->__codecvt_do_length) (cv,
-						  &fp->_wide_data->_IO_state,
-						  fp->_IO_read_base,
-						  fp->_IO_read_end, delta);
+	      nread = __libio_codecvt_length (cv,
+					      &fp->_wide_data->_IO_state,
+					      fp->_IO_read_base,
+					      fp->_IO_read_end, delta);
 	      fp->_IO_read_ptr = fp->_IO_read_base + nread;
 	      fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;