Why fixing 9533 doesn't fix 7774: revealed!

Nathan Myers ncm-nospam@cantrip.org
Wed Mar 5 17:57:00 GMT 2003


On Wed, Mar 05, 2003 at 02:13:01PM +0100, Paolo Carlini wrote:
> Hi,
> This is 7744 testcase: ...
> As Nathan explained, in_avail shouldn't call showmanyc but in
> fact it does. Why?
> 
> Because after the in.peek(), egptr == gptr! Indeed, in.peek()
> calls sgetc(), which calls underflow(), which does:
> 
>           __elen = _M_file.xsgetn(reinterpret_cast<char*>(_M_in_beg),
>                                   _M_buf_size);
>           __ilen = __elen;
> 
>           if (0 < __ilen)
>             {
>                _M_set_determinate(__ilen);
>                if (__testout)
>                  _M_out_cur = _M_in_cur;
>                __ret = traits_type::to_int_type(*_M_in_cur);
>                if (__bump)
>                  _M_in_cur_move(1);
>                else if (_M_buf_size == 1)
>                  {
>                    // If we are synced with stdio, we have to unget the
>                    // character we just read so that the file pointer
>                    // doesn't move.
>                    
> _M_file.sys_ungetc(traits_type::to_int_type(*_M_in_cur));
>                    _M_set_indeterminate();
>                  }
>             }         
> 
> There are no chances that 4 chars are put in the buffer (stdio is synced
> and _M_buf_size == 1) but we expect at least one!

Ick.

> That single char _is_ in fact put into the buffer, but, since 
> _M_buf_size == 1
> the char is unget and _M_set_indeterminate called, which basically reset
> all the get area pointers to _M_buf and the information on the char present
> in the buffer ends up _not_ being propagated (as egptr == gptr + 1) to 
> in_avail.
> 
> So, a few question:
> 1- Is that _M_set_indeterminate() call really necessary for other reasons?
> 2- Is it ok to have _M_buf_size == 1 when synced with stdio?

OK, syncing with stdio is a special case.  I am not surprised to see 
in_avail() call showmanyc() for that case, nor to find it reporting 0.  
The _M_set_indeterminate() call is necessary so that the next sgetc()
will call underflow(), and get the character out of stdin's putback
cell.  It is necessary to have _M_buf_size == 1 when synced with stdio.

If the program began with "std::ios::sync_with_stdio(false);" I would hope 
for different behavior.  In other words, 7744 is "not a bug" without a 
call to std::ios::sync_with_stdio(false).  However, I find that even when 
it has been called, in_avail() still returns zero on cin.  That's the bug.
When that call occurs before any input, then you would like to have a 
normal big buffer, so the next underflow will fill it as much as it can.

Pet?r's suggestion of a check for an empty buffer at the beginning of
underflow() fixes a grave bug.

Of course it would be much better if, when synchronizing with stdio, 
we could share their buffer and putback cell, and not need _M_buf_size 
equal to 1.  But that's a whole other project.  For now, if anybody
wants decent cin performance, they have to unsync, and then they 
should be able to get it.

Nathan Myers
ncm-nospam@cantrip.org



More information about the Libstdc++ mailing list