Bug 19416 - ftell on wide-oriented stream can crash (in OOM case) or fail (in any case)
Summary: ftell on wide-oriented stream can crash (in OOM case) or fail (in any case)
Status: NEW
Alias: None
Product: glibc
Classification: Unclassified
Component: stdio (show other bugs)
Version: 2.22
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Depends on:
Reported: 2015-12-29 21:35 UTC by Alexander Cherepanov
Modified: 2015-12-29 21:37 UTC (History)
0 users

See Also:
Last reconfirmed:

ftell returns wrong result and then crashes (606 bytes, text/x-csrc)
2015-12-29 21:35 UTC, Alexander Cherepanov
Patch (462 bytes, patch)
2015-12-29 21:37 UTC, Alexander Cherepanov
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Cherepanov 2015-12-29 21:35:04 UTC
Created attachment 8869 [details]
ftell returns wrong result and then crashes

There are several problems when ftell is called for a stream and the following conditions are met:
- the stream is wide-oriented,
- it has unflushed data,
- the current locale uses a variable-length encoding.

The problems are illustrated by the attached sample program and are described below. Quick-n-dirty patch is attached too.

When the conditions are met, at some point, the execution is passed to this fragment:


 697             {
 698               size_t delta = (fp->_wide_data->_IO_write_ptr
 699                               - fp->_wide_data->_IO_write_base);

Apparently, this is the number of wide chars not yet written to the stream.

 701               /* Allocate enough space for the conversion.  */
 702               size_t outsize = delta * sizeof (wchar_t);

Problem 1: to get the size of output buffer you have to multiply the number of chars by something like MB_LEN_MAX instead of sizeof (wchar_t). If there is not enough space conversion will fail.

 703               char *out = malloc (outsize);

Problem 2: the result of malloc is checked. In out of memory condition the program will crash.

 704               char *outstop = out;
 705               const wchar_t *in = fp->_wide_data->_IO_write_base;
 707               enum __codecvt_result status;
 709               __mbstate_t state = fp->_wide_data->_IO_last_state;
 710               status = (*cv->__codecvt_do_out) (cv, &state,
 711                                                 in, in + delta, &in,
 712                                                 out, out + outsize, &outstop);
 714               /* We don't check for __codecvt_partial because it can be
 715                  returned on one of two conditions: either the output
 716                  buffer is full or the input sequence is incomplete.  We
 717                  take care to allocate enough buffer and our input
 718                  sequences must be complete since they are accepted as
 719                  wchar_t; if not, then that is an error.  */
 720               if (__glibc_unlikely (status != __codecvt_ok))
 721                 {
 722                   free (out);
 723                   return WEOF;

Problem 3: WEOF is invalid error code for ftell. It prints 4294967295 on my x86-64 machine.

 724                 }
 726               offset += outstop - out;
 727               free (out);
 728             }


Introduced in https://sourceware.org/git/?p=glibc.git;a=commit;h=000232b9bcbf194f1e5fd0ff380000f341505405 .
Comment 1 Alexander Cherepanov 2015-12-29 21:37:16 UTC
Created attachment 8870 [details]