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