Consider the following example code:
#include <iostream>
using namespace std;
int main()
{
istreambuf_iterator<char> eos;
istreambuf_iterator<char> iit(cin.rdbuf());
int i;
for (i = 0; iit != eos; ++i, ++iit) {
cout << *iit;
}
cout << endl << i << endl;
}
And an input file containing the following: "foo\xffbar":
$ hexdump testin
0000000 66 6f 6f ff 62 61 72
0000007
Now for the test using clang libc++ vs gnu libstdc++:
$ make test
clang++ -std=c++11 -stdlib=libc++ -Wall -stdlib=libc++ -o bug-libcc bug.cpp
clang++ -std=c++11 -stdlib=libc++ -Wall -stdlib=libstdc++ -o bug-libstd bug.cpp
./bug-libcc < testin
foo
3
./bug-libstd < testin
foo�bar
7
As you can see the libc++ version thinks the 0xff is the end of stream and it stops reading. So this leads to a couple of questions.
1) Is this a bug in libc++ that I should report? My google searches for existing bugs have turned up nothing.
2) Is there a good way to work around this issue?
EDIT
The following code works:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream ifs ("testin", ios::binary);
istreambuf_iterator<char> eos;
istreambuf_iterator<char> iit(ifs.rdbuf());
int i;
for (i = 0; iit != eos; ++i, ++iit) {
cout << *iit;
}
cout << endl << i << endl;
}
Leading me to believe that it is a binary conversion issue, but that doesn't explain why libstdc++ works properly.
EDIT2
Using a file without binary works fine too:
ifstream ifs ("testin");
So there is definitely something fishy going on. It looks like it might be an issue in the implementation of cin though, not the iterator.
Unfortunately there is still a bug in libc++ (in addition to the one ecatmur pointed out). Here is the fix:
Index: include/__std_stream
===================================================================
--- include/__std_stream (revision 176092)
+++ include/__std_stream (working copy)
@@ -150,7 +150,7 @@
{
for (int __i = __nread; __i > 0;)
{
- if (ungetc(__extbuf[--__i], __file_) == EOF)
+ if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
return traits_type::eof();
}
}
I will get this checked in asap. Sorry for the bug. Thanks for bringing it to my attention.
Fix Committed revision 176822 to the libcxx public svn trunk. The fix requires a re-compiled dylib even though the fix is in a header.