1From 0d0dc9e42f27a743171700bcd2ba508ff6e760f9 Mon Sep 17 00:00:00 2001
2From: Florian Weimer <fweimer@redhat.com>
3Date: Mon, 20 May 2019 21:54:57 +0200
4Subject: [PATCH 08/20] libio: Remove codecvt vtable [BZ #24588]
5
6The codecvt vtable is not a real vtable because it also contains the
7conversion state data.  Furthermore, wide stream support was added to
8GCC 3.0, after a C++ ABI bump, so there is no compatibility
9requirement with libstdc++.
10
11This change removes several unmangled function pointers which could
12be used with a corrupted FILE object to redirect execution.  (libio
13vtable verification did not cover the codecvt vtable.)
14
15Reviewed-by: Yann Droneaud <ydroneaud@opteya.com>
16Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
17(cherry picked from commit 09e1b0e3f6facc1af2dbcfef204f0aaa8718772b)
18Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
19---
20 libio/fileops.c     |   3 -
21 libio/iofgetpos.c   |   3 +-
22 libio/iofgetpos64.c |   3 +-
23 libio/iofsetpos.c   |   3 +-
24 libio/iofsetpos64.c |   3 +-
25 libio/iofwide.c     | 132 ++++++--------------------------------------
26 libio/libio.h       |  32 -----------
27 libio/libioP.h      |  29 +++++++++-
28 libio/wfileops.c    |  89 +++++++++++++++--------------
29 9 files changed, 92 insertions(+), 205 deletions(-)
30
31diff --git a/libio/fileops.c b/libio/fileops.c
32index c9c5cbcc..dd66cc67 100644
33--- a/libio/fileops.c
34+++ b/libio/fileops.c
35@@ -331,9 +331,6 @@ _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode,
36
37 	  cc = fp->_codecvt = &fp->_wide_data->_codecvt;
38
39-	  /* The functions are always the same.  */
40-	  *cc = __libio_codecvt;
41-
42 	  cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
43 	  cc->__cd_in.__cd.__steps = fcts.towc;
44
45diff --git a/libio/iofgetpos.c b/libio/iofgetpos.c
46index 8177326c..808ddc47 100644
47--- a/libio/iofgetpos.c
48+++ b/libio/iofgetpos.c
49@@ -70,8 +70,7 @@ _IO_new_fgetpos (FILE *fp, __fpos_t *posp)
50   else
51     {
52       posp->__pos = pos;
53-      if (fp->_mode > 0
54-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
55+      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
56 	/* This is a stateful encoding, safe the state.  */
57 	posp->__state = fp->_wide_data->_IO_state;
58     }
59diff --git a/libio/iofgetpos64.c b/libio/iofgetpos64.c
60index 0ec54131..5a0d8bd7 100644
61--- a/libio/iofgetpos64.c
62+++ b/libio/iofgetpos64.c
63@@ -54,8 +54,7 @@ _IO_new_fgetpos64 (FILE *fp, __fpos64_t *posp)
64   else
65     {
66       posp->__pos = pos;
67-      if (fp->_mode > 0
68-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
69+      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
70 	/* This is a stateful encoding, safe the state.  */
71 	posp->__state = fp->_wide_data->_IO_state;
72     }
73diff --git a/libio/iofsetpos.c b/libio/iofsetpos.c
74index da48b27c..0cbe3b79 100644
75--- a/libio/iofsetpos.c
76+++ b/libio/iofsetpos.c
77@@ -58,8 +58,7 @@ _IO_new_fsetpos (FILE *fp, const __fpos_t *posp)
78   else
79     {
80       result = 0;
81-      if (fp->_mode > 0
82-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
83+      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
84 	/* This is a stateful encoding, restore the state.  */
85 	fp->_wide_data->_IO_state = posp->__state;
86     }
87diff --git a/libio/iofsetpos64.c b/libio/iofsetpos64.c
88index 29da9814..695a8328 100644
89--- a/libio/iofsetpos64.c
90+++ b/libio/iofsetpos64.c
91@@ -48,8 +48,7 @@ _IO_new_fsetpos64 (FILE *fp, const fpos64_t *posp)
92   else
93     {
94       result = 0;
95-      if (fp->_mode > 0
96-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
97+      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
98 	/* This is a stateful encoding, safe the state.  */
99 	fp->_wide_data->_IO_state = posp->__state;
100     }
101diff --git a/libio/iofwide.c b/libio/iofwide.c
102index d8ec6642..0e9e7dd5 100644
103--- a/libio/iofwide.c
104+++ b/libio/iofwide.c
105@@ -39,44 +39,6 @@
106 #include <sysdep.h>
107
108
109-/* Prototypes of libio's codecvt functions.  */
110-static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
111-				     __mbstate_t *statep,
112-				     const wchar_t *from_start,
113-				     const wchar_t *from_end,
114-				     const wchar_t **from_stop, char *to_start,
115-				     char *to_end, char **to_stop);
116-static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,
117-					 __mbstate_t *statep, char *to_start,
118-					 char *to_end, char **to_stop);
119-static enum __codecvt_result do_in (struct _IO_codecvt *codecvt,
120-				    __mbstate_t *statep,
121-				    const char *from_start,
122-				    const char *from_end,
123-				    const char **from_stop, wchar_t *to_start,
124-				    wchar_t *to_end, wchar_t **to_stop);
125-static int do_encoding (struct _IO_codecvt *codecvt);
126-static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
127-		      const char *from_start,
128-		      const char *from_end, size_t max);
129-static int do_max_length (struct _IO_codecvt *codecvt);
130-static int do_always_noconv (struct _IO_codecvt *codecvt);
131-
132-
133-/* The functions used in `codecvt' for libio are always the same.  */
134-const struct _IO_codecvt __libio_codecvt =
135-{
136-  .__codecvt_destr = NULL,		/* Destructor, never used.  */
137-  .__codecvt_do_out = do_out,
138-  .__codecvt_do_unshift = do_unshift,
139-  .__codecvt_do_in = do_in,
140-  .__codecvt_do_encoding = do_encoding,
141-  .__codecvt_do_always_noconv = do_always_noconv,
142-  .__codecvt_do_length = do_length,
143-  .__codecvt_do_max_length = do_max_length
144-};
145-
146-
147 /* Return orientation of stream.  If mode is nonzero try to change
148    the orientation first.  */
149 #undef _IO_fwide
150@@ -119,9 +81,6 @@ _IO_fwide (FILE *fp, int mode)
151 	assert (fcts.towc_nsteps == 1);
152 	assert (fcts.tomb_nsteps == 1);
153
154-	/* The functions are always the same.  */
155-	*cc = __libio_codecvt;
156-
157 	cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
158 	cc->__cd_in.__cd.__steps = fcts.towc;
159
160@@ -151,11 +110,11 @@ _IO_fwide (FILE *fp, int mode)
161 }
162
163
164-static enum __codecvt_result
165-do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
166-	const wchar_t *from_start, const wchar_t *from_end,
167-	const wchar_t **from_stop, char *to_start, char *to_end,
168-	char **to_stop)
169+enum __codecvt_result
170+__libio_codecvt_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
171+		     const wchar_t *from_start, const wchar_t *from_end,
172+		     const wchar_t **from_stop, char *to_start, char *to_end,
173+		     char **to_stop)
174 {
175   enum __codecvt_result result;
176
177@@ -203,57 +162,11 @@ do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
178 }
179
180
181-static enum __codecvt_result
182-do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
183-	    char *to_start, char *to_end, char **to_stop)
184-{
185-  enum __codecvt_result result;
186-
187-  struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
188-  int status;
189-  size_t dummy;
190-
191-  codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;
192-  codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;
193-  codecvt->__cd_out.__cd.__data[0].__statep = statep;
194-
195-  __gconv_fct fct = gs->__fct;
196-#ifdef PTR_DEMANGLE
197-  if (gs->__shlib_handle != NULL)
198-    PTR_DEMANGLE (fct);
199-#endif
200-
201-  status = DL_CALL_FCT (fct,
202-			(gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
203-			 NULL, &dummy, 1, 0));
204-
205-  *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;
206-
207-  switch (status)
208-    {
209-    case __GCONV_OK:
210-    case __GCONV_EMPTY_INPUT:
211-      result = __codecvt_ok;
212-      break;
213-
214-    case __GCONV_FULL_OUTPUT:
215-    case __GCONV_INCOMPLETE_INPUT:
216-      result = __codecvt_partial;
217-      break;
218-
219-    default:
220-      result = __codecvt_error;
221-      break;
222-    }
223-
224-  return result;
225-}
226-
227-
228-static enum __codecvt_result
229-do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
230-       const char *from_start, const char *from_end, const char **from_stop,
231-       wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
232+enum __codecvt_result
233+__libio_codecvt_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
234+		    const char *from_start, const char *from_end,
235+		    const char **from_stop,
236+		    wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
237 {
238   enum __codecvt_result result;
239
240@@ -301,8 +214,8 @@ do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
241 }
242
243
244-static int
245-do_encoding (struct _IO_codecvt *codecvt)
246+int
247+__libio_codecvt_encoding (struct _IO_codecvt *codecvt)
248 {
249   /* See whether the encoding is stateful.  */
250   if (codecvt->__cd_in.__cd.__steps[0].__stateful)
251@@ -318,16 +231,10 @@ do_encoding (struct _IO_codecvt *codecvt)
252 }
253
254
255-static int
256-do_always_noconv (struct _IO_codecvt *codecvt)
257-{
258-  return 0;
259-}
260-
261-
262-static int
263-do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
264-	   const char *from_start, const char *from_end, size_t max)
265+int
266+__libio_codecvt_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
267+			const char *from_start, const char *from_end,
268+			size_t max)
269 {
270   int result;
271   const unsigned char *cp = (const unsigned char *) from_start;
272@@ -354,10 +261,3 @@ do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
273
274   return result;
275 }
276-
277-
278-static int
279-do_max_length (struct _IO_codecvt *codecvt)
280-{
281-  return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;
282-}
283diff --git a/libio/libio.h b/libio/libio.h
284index 00f91696..5291bb8d 100644
285--- a/libio/libio.h
286+++ b/libio/libio.h
287@@ -118,40 +118,8 @@ struct _IO_marker {
288   int _pos;
289 };
290
291-/* This is the structure from the libstdc++ codecvt class.  */
292-enum __codecvt_result
293-{
294-  __codecvt_ok,
295-  __codecvt_partial,
296-  __codecvt_error,
297-  __codecvt_noconv
298-};
299-
300-/* The order of the elements in the following struct must match the order
301-   of the virtual functions in the libstdc++ codecvt class.  */
302 struct _IO_codecvt
303 {
304-  void (*__codecvt_destr) (struct _IO_codecvt *);
305-  enum __codecvt_result (*__codecvt_do_out) (struct _IO_codecvt *,
306-					     __mbstate_t *,
307-					     const wchar_t *,
308-					     const wchar_t *,
309-					     const wchar_t **, char *,
310-					     char *, char **);
311-  enum __codecvt_result (*__codecvt_do_unshift) (struct _IO_codecvt *,
312-						 __mbstate_t *, char *,
313-						 char *, char **);
314-  enum __codecvt_result (*__codecvt_do_in) (struct _IO_codecvt *,
315-					    __mbstate_t *,
316-					    const char *, const char *,
317-					    const char **, wchar_t *,
318-					    wchar_t *, wchar_t **);
319-  int (*__codecvt_do_encoding) (struct _IO_codecvt *);
320-  int (*__codecvt_do_always_noconv) (struct _IO_codecvt *);
321-  int (*__codecvt_do_length) (struct _IO_codecvt *, __mbstate_t *,
322-			      const char *, const char *, size_t);
323-  int (*__codecvt_do_max_length) (struct _IO_codecvt *);
324-
325   _IO_iconv_t __cd_in;
326   _IO_iconv_t __cd_out;
327 };
328diff --git a/libio/libioP.h b/libio/libioP.h
329index df2633d8..7ee71a63 100644
330--- a/libio/libioP.h
331+++ b/libio/libioP.h
332@@ -476,7 +476,6 @@ extern const struct _IO_jump_t _IO_streambuf_jumps;
333 extern const struct _IO_jump_t _IO_old_proc_jumps attribute_hidden;
334 extern const struct _IO_jump_t _IO_str_jumps attribute_hidden;
335 extern const struct _IO_jump_t _IO_wstr_jumps attribute_hidden;
336-extern const struct _IO_codecvt __libio_codecvt attribute_hidden;
337 extern int _IO_do_write (FILE *, const char *, size_t);
338 libc_hidden_proto (_IO_do_write)
339 extern int _IO_new_do_write (FILE *, const char *, size_t);
340@@ -839,4 +838,32 @@ IO_validate_vtable (const struct _IO_jump_t *vtable)
341   return vtable;
342 }
343
344+/* Character set conversion.  */
345+
346+enum __codecvt_result
347+{
348+  __codecvt_ok,
349+  __codecvt_partial,
350+  __codecvt_error,
351+  __codecvt_noconv
352+};
353+
354+enum __codecvt_result __libio_codecvt_out (struct _IO_codecvt *,
355+					   __mbstate_t *,
356+					   const wchar_t *,
357+					   const wchar_t *,
358+					   const wchar_t **, char *,
359+					   char *, char **)
360+  attribute_hidden;
361+enum __codecvt_result __libio_codecvt_in (struct _IO_codecvt *,
362+					  __mbstate_t *,
363+					  const char *, const char *,
364+					  const char **, wchar_t *,
365+					  wchar_t *, wchar_t **)
366+  attribute_hidden;
367+int __libio_codecvt_encoding (struct _IO_codecvt *) attribute_hidden;
368+int __libio_codecvt_length (struct _IO_codecvt *, __mbstate_t *,
369+			    const char *, const char *, size_t)
370+  attribute_hidden;
371+
372 #endif /* libioP.h.  */
373diff --git a/libio/wfileops.c b/libio/wfileops.c
374index 63cb6876..ddc96295 100644
375--- a/libio/wfileops.c
376+++ b/libio/wfileops.c
377@@ -72,11 +72,11 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do)
378 	    }
379
380 	  /* Now convert from the internal format into the external buffer.  */
381-	  result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
382-					    data, data + to_do, &new_data,
383-					    write_ptr,
384-					    buf_end,
385-					    &write_ptr);
386+	  result = __libio_codecvt_out (cc, &fp->_wide_data->_IO_state,
387+					data, data + to_do, &new_data,
388+					write_ptr,
389+					buf_end,
390+					&write_ptr);
391
392 	  /* Write out what we produced so far.  */
393 	  if (_IO_new_do_write (fp, write_base, write_ptr - write_base) == EOF)
394@@ -140,12 +140,12 @@ _IO_wfile_underflow (FILE *fp)
395       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
396       fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
397 	fp->_wide_data->_IO_buf_base;
398-      status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
399-				       fp->_IO_read_ptr, fp->_IO_read_end,
400-				       &read_stop,
401-				       fp->_wide_data->_IO_read_ptr,
402-				       fp->_wide_data->_IO_buf_end,
403-				       &fp->_wide_data->_IO_read_end);
404+      status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
405+				   fp->_IO_read_ptr, fp->_IO_read_end,
406+				   &read_stop,
407+				   fp->_wide_data->_IO_read_ptr,
408+				   fp->_wide_data->_IO_buf_end,
409+				   &fp->_wide_data->_IO_read_end);
410
411       fp->_IO_read_base = fp->_IO_read_ptr;
412       fp->_IO_read_ptr = (char *) read_stop;
413@@ -266,11 +266,11 @@ _IO_wfile_underflow (FILE *fp)
414       naccbuf += to_copy;
415       from = accbuf;
416     }
417-  status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
418-				   from, to, &read_ptr_copy,
419-				   fp->_wide_data->_IO_read_end,
420-				   fp->_wide_data->_IO_buf_end,
421-				   &fp->_wide_data->_IO_read_end);
422+  status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
423+			       from, to, &read_ptr_copy,
424+			       fp->_wide_data->_IO_read_end,
425+			       fp->_wide_data->_IO_buf_end,
426+			       &fp->_wide_data->_IO_read_end);
427
428   if (__glibc_unlikely (naccbuf != 0))
429     fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
430@@ -372,12 +372,12 @@ _IO_wfile_underflow_mmap (FILE *fp)
431   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
432   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
433     fp->_wide_data->_IO_buf_base;
434-  (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
435-			  fp->_IO_read_ptr, fp->_IO_read_end,
436-			  &read_stop,
437-			  fp->_wide_data->_IO_read_ptr,
438-			  fp->_wide_data->_IO_buf_end,
439-			  &fp->_wide_data->_IO_read_end);
440+  __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
441+		      fp->_IO_read_ptr, fp->_IO_read_end,
442+		      &read_stop,
443+		      fp->_wide_data->_IO_read_ptr,
444+		      fp->_wide_data->_IO_buf_end,
445+		      &fp->_wide_data->_IO_read_end);
446
447   fp->_IO_read_ptr = (char *) read_stop;
448
449@@ -495,7 +495,7 @@ _IO_wfile_sync (FILE *fp)
450       struct _IO_codecvt *cv = fp->_codecvt;
451       off64_t new_pos;
452
453-      int clen = (*cv->__codecvt_do_encoding) (cv);
454+      int clen = __libio_codecvt_encoding (cv);
455
456       if (clen > 0)
457 	/* It is easy, a fixed number of input bytes are used for each
458@@ -510,9 +510,9 @@ _IO_wfile_sync (FILE *fp)
459 	  int nread;
460
461 	  fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
462-	  nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
463-					      fp->_IO_read_base,
464-					      fp->_IO_read_end, delta);
465+	  nread = __libio_codecvt_length (cv, &fp->_wide_data->_IO_state,
466+					  fp->_IO_read_base,
467+					  fp->_IO_read_end, delta);
468 	  fp->_IO_read_ptr = fp->_IO_read_base + nread;
469 	  delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
470 	}
471@@ -547,7 +547,7 @@ adjust_wide_data (FILE *fp, bool do_convert)
472 {
473   struct _IO_codecvt *cv = fp->_codecvt;
474
475-  int clen = (*cv->__codecvt_do_encoding) (cv);
476+  int clen = __libio_codecvt_encoding (cv);
477
478   /* Take the easy way out for constant length encodings if we don't need to
479      convert.  */
480@@ -564,12 +564,12 @@ adjust_wide_data (FILE *fp, bool do_convert)
481     {
482
483       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
484-      status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
485-				       fp->_IO_read_base, fp->_IO_read_ptr,
486-				       &read_stop,
487-				       fp->_wide_data->_IO_read_base,
488-				       fp->_wide_data->_IO_buf_end,
489-				       &fp->_wide_data->_IO_read_end);
490+      status = __libio_codecvt_in (cv, &fp->_wide_data->_IO_state,
491+				   fp->_IO_read_base, fp->_IO_read_ptr,
492+				   &read_stop,
493+				   fp->_wide_data->_IO_read_base,
494+				   fp->_wide_data->_IO_buf_end,
495+				   &fp->_wide_data->_IO_read_end);
496
497       /* Should we return EILSEQ?  */
498       if (__glibc_unlikely (status == __codecvt_error))
499@@ -647,7 +647,7 @@ do_ftell_wide (FILE *fp)
500 	}
501
502       struct _IO_codecvt *cv = fp->_codecvt;
503-      int clen = (*cv->__codecvt_do_encoding) (cv);
504+      int clen = __libio_codecvt_encoding (cv);
505
506       if (!unflushed_writes)
507 	{
508@@ -662,9 +662,9 @@ do_ftell_wide (FILE *fp)
509
510 	      size_t delta = wide_read_ptr - wide_read_base;
511 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
512-	      nread = (*cv->__codecvt_do_length) (cv, &state,
513-						  fp->_IO_read_base,
514-						  fp->_IO_read_end, delta);
515+	      nread = __libio_codecvt_length (cv, &state,
516+					      fp->_IO_read_base,
517+					      fp->_IO_read_end, delta);
518 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
519 	    }
520 	}
521@@ -687,9 +687,8 @@ do_ftell_wide (FILE *fp)
522 	      enum __codecvt_result status;
523
524 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
525-	      status = (*cv->__codecvt_do_out) (cv, &state,
526-						in, in + delta, &in,
527-						out, out + outsize, &outstop);
528+	      status = __libio_codecvt_out (cv, &state, in, in + delta, &in,
529+					    out, out + outsize, &outstop);
530
531 	      /* We don't check for __codecvt_partial because it can be
532 		 returned on one of two conditions: either the output
533@@ -800,7 +799,7 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
534 	 find out which position in the external buffer corresponds to
535 	 the current position in the internal buffer.  */
536       cv = fp->_codecvt;
537-      clen = (*cv->__codecvt_do_encoding) (cv);
538+      clen = __libio_codecvt_encoding (cv);
539
540       if (mode != 0 || !was_writing)
541 	{
542@@ -818,10 +817,10 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
543 	      delta = (fp->_wide_data->_IO_read_ptr
544 		       - fp->_wide_data->_IO_read_base);
545 	      fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
546-	      nread = (*cv->__codecvt_do_length) (cv,
547-						  &fp->_wide_data->_IO_state,
548-						  fp->_IO_read_base,
549-						  fp->_IO_read_end, delta);
550+	      nread = __libio_codecvt_length (cv,
551+					      &fp->_wide_data->_IO_state,
552+					      fp->_IO_read_base,
553+					      fp->_IO_read_end, delta);
554 	      fp->_IO_read_ptr = fp->_IO_read_base + nread;
555 	      fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
556 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
557--
5582.20.1
559
560