Bug 52169 - the ifstream readsome() method does not signal any bit on eof.
Summary: the ifstream readsome() method does not signal any bit on eof.
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.6.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-02-08 10:28 UTC by Lluís Batlle i Rossell
Modified: 2012-02-08 10:56 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Run it with "./c2 c2.cpp" and it will loop forever (226 bytes, application/octet-stream)
2012-02-08 10:28 UTC, Lluís Batlle i Rossell
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Lluís Batlle i Rossell 2012-02-08 10:28:43 UTC
Created attachment 26608 [details]
Run it with "./c2 c2.cpp" and it will loop forever

The ifstream readsome() method does not signal any bit on eof, and I think it should.

Therefore, these loops loop forever:
    while(f && !f.eof())
    {
        char b[5000];
        size_t read = f.readsome(b, sizeof b);
        cerr << "Read: " << read << " bytes" << endl;
        ostr.write(b, read);
    }

According to http://www.cplusplus.com/reference/iostream/istream/readsome/ :

Errors are signaled by modifying the internal state flags:

eofbit	The get pointer is at the end of the stream buffer's internal input array when the function is called, meaning that there are no positions to be read in the internal buffer (which may or not be the end of the input sequence). This happens when rdbuf()->in_avail() would return -1 before the first character is extracted.

failbit	The stream was at the end of the source of characters before the function was called.

badbit	An error other than the above happened.
Comment 1 Tomalak Geret'kal 2012-02-08 10:39:54 UTC
cplusplus.com is (a) not authoritative, (b) full of mistakes, and (c) otherwise just awful.

Instead, we'll quote the standard(s):

[C++11: 27.7.2.3]:
      streamsize readsome(char_type* s, streamsize n);
32/ Effects: Behaves as an unformatted input function (as described in 27.7.2.3, paragraph 1). After constructing a sentry object, if !good() calls setstate(failbit) which may throw an exception, and return. Otherwise extracts characters and stores them into successive locations of an array whose first element is designated by s. If rdbuf()->in_avail() == -1, calls setstate(eofbit) (which may throw ios_base::failure (27.5.5.4)), and extracts no characters;
— If rdbuf()->in_avail() == 0, extracts no characters
— If rdbuf()->in_avail() > 0, extracts min(rdbuf()->in_avail(),n)).
33/ Returns: The number of characters extracted.

[C++03: 27.6.1.3]:
      streamsize readsome(char_type* s, streamsize n);
30/ Effects: Behaves as an unformatted input function (as described in 27.6.1.3, paragraph 1). After constructing a sentry object, if !good() calls setstate(failbit) which may throw an exception, and return. Otherwise extracts characters and stores them into successive locations of an array whose first element is designated by s. If rdbuf()->in_avail() == -1, calls setstate(eofbit) (which may throw ios_base::failure (27.4.4.3)), and extracts no characters;
— If rdbuf()->in_avail() == 0, extracts no characters
— If rdbuf()->in_avail() > 0, extracts min(rdbuf()->in_avail(),n)).
31/ Returns: The number of characters extracted.
Comment 2 Tomalak Geret'kal 2012-02-08 10:45:17 UTC
Are you sure it's not just that in_avail is 0? Why should it be -1 here?

i.e. doesn't readsome become a noop when there's nothing to read?
Comment 3 Lluís Batlle i Rossell 2012-02-08 10:53:20 UTC
It looks also related to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8258 . The post from Tomalak and that made all clear.

Sorry for the noise!
Comment 4 Jonathan Wakely 2012-02-08 10:56:18 UTC
(In reply to comment #1)
> cplusplus.com is (a) not authoritative, (b) full of mistakes, and (c) otherwise
> just awful.

This, x 1000

(In reply to comment #2)
> i.e. doesn't readsome become a noop when there's nothing to read?

Yes, which makes it very useful for non-blocking reads from pipes or sockets.

The testcase is simply wrong, as you can see by checking in_avail:

    cerr << "avail: " << f.rdbuf()->in_avail() << endl;

Since in_avail() doesn't return -1, readsome should not set eofbit.

There are better ways to read a whole file anyway, e.g. ostr << f.rdbuf()