Ambiguous interpretation of -1 among char_traits::eof, char_traits::to_int_type and streambuf::underflow
Jonathan Wakely
jwakely.gcc@gmail.com
Wed Feb 19 15:36:00 GMT 2014
On 10 February 2014 16:26, Brent Lewis <coder0xff@gmail.com> wrote:
> In certain circumstances, a 0xFF read from a stream buffer may be
> erroneously interpreted as the EOF value.
>
> Example from boost iostreams (
> iostreams\detail\streambuf\indirect_streambuf.hpp ) :
>
> template<typename T, typename Tr, typename Alloc, typename Mode>
> typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
> indirect_streambuf<T, Tr, Alloc, Mode>::underflow()
> {
> //... code removed for brevity
> return chars != 0 ?
> traits_type::to_int_type(*gptr()) :
> traits_type::eof();
> }
>
> In the event that the parameter to to_int_type is a signed char (which
> is the case with istream)
No, std::istream is std::basic_istream<char> not
std::basic_istream<signed char>. The difference is significant.
> with the value -1, sign extension will cause
> it to return (int_type) -1. Thusly, when underflow() is called by
>
> std::basic_streambuf<signed char, std::char_traits<signed char> >::uflow()
> {
> //...
> int_type __ret = traits_type::eof();
> const bool __testeof = traits_type::eq_int_type(this->underflow(), __ret);
> //...
> }
>
> It erroneously interprets this -1 as eof.
It shouldn't do, because underflow() is supposed to use
char_traits<C>::to_int_type(const C&) to disambiguate char(0xff) and
char_traits<C>::eof().
I had to read your mail a couple of times to notice you're using
'signed char' above.
If you're using streams of 'signed char' then you need to use a custom
traits class because std::char_traits<signed char> is not specialized
and doesn't necessarily do the right thing.
> Though not optimal, a possible workaround is to ensure EOF is a value
> that is not ambiguous. In char_traits.h:
>
> template<typename _CharT>
> struct char_traits {
> //...
> static _GLIBCXX_CONSTEXPR int_type
> eof() { //if char_type is signed, to_int_type may return -1, so -1
> is NOT a suitable value for EOF
> static_assert(sizeof(char_type) < sizeof(int_type), "Please choose a
> char_type with a size that is smaller than int_type.");
> return static_cast<int_type>(std::numeric_limits<int_type>::max());
> }
> }
>
> and whatever other corresponding changes might need to be made.
> Perhaps instead, changing the EOF define would be enough. Another
> solution might be to make char_traits::to_int_type circumvent sign
> extension, so (char)-1 becomes (int)255, though once again I don't
> know what implications this might have elsewhere.
I don't think we want to change char_traits<_CharT>::eof().
The problem shouldn't exist assuming a correct traits type and if
underflow() correctly uses to_int_type() to ensure that when a
char(0xff) is read it is returned as a value distinct from
char_traits<char>::eof().
> In my case (on Android using boost) 4kb are read for each underflow,
> so the 0xFF has to fall exactly on one of these boundaries for the
> buggy behavior to be occur.
Do you have a testcase reproducing the problem?
More information about the Libstdc++
mailing list