My previous fix for PR 94749 did fix the reported case, so that the next
character is not discarded if it happens to equal the delimiter when __n
characters have already been read. But it introduced a new bug, which is
that the delimiter character would *not* be discarded if the number of
characters discarded is numeric_limits<streamsize>::max() or more before
reaching the delimiter.
The new bug happens because I changed the code to check _M_gcount < __n.
But when __n == numeric_limits<streamsize>::max() that is false, and so
we don't discard the delimiter. It's not sufficient to check for the
delimiter when the __large_ignore condition is true, because there's an
edge case where the delimiter is reached when _M_gcount == __n and so
we break out of the loop without setting __large_ignore.
PR 96161 is a similar bug to the original PR 94749 report, where eofbit
is set after discarding __n characters if there happen to be no more
characters in the stream.
This patch fixes both cases (and the regression) by checking different
conditions for the __n == max case and the __n < max case. For the
former case, we know that we must have either reached the delimiter or
EOF, and the value of _M_gcount doesn't matter (except to avoid integer
overflow). For the latter case we need to check _M_gcount first and only
set eofbit or discard the delimiter if it didn't reach __n. For the
latter case overflow can't happen because _M_gcount <= __n < max.
libstdc++-v3/ChangeLog:
PR libstdc++/94749
PR libstdc++/96161
* include/bits/istream.tcc (basic_istream::ignore(streamsize))
[n == max]: Check overflow conditions on _M_gcount. Rely on
the fact that either EOF or the delimiter was reached.
[n < max]: Check _M_gcount < n before checking for EOF or
delimiter.
(basic_istream::ignore(streamsize, char_type): Likewise.
* src/c++98/compatibility.cc (istream::ignore(streamsize))
(wistream::ignore(streamsize)): Likewise.
* src/c++98/istream.cc (istream::ignore(streamsize, char_type))
(wistream::ignore(streamsize, char_type)): Likewise.
* testsuite/27_io/basic_istream/ignore/char/94749.cc: Check that
delimiter is discarded if the number of characters ignored
doesn't fit in streamsize.
* testsuite/27_io/basic_istream/ignore/wchar_t/94749.cc:
Likewise.
* testsuite/27_io/basic_istream/ignore/char/96161.cc: New test.
* testsuite/27_io/basic_istream/ignore/wchar_t/96161.cc: New test.