Last active
December 25, 2015 21:58
-
-
Save komiga/7045925 to your computer and use it in GitHub Desktop.
Bad seek behavior with libc++ (svn, rev 192988). There's a patch down there.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cassert> | |
#include <streambuf> | |
#include <iostream> | |
// Dummy stream buffer for testing. | |
// basic_streambuf defines seekoff() and seekpos() (virtuals) to | |
// return pos_type(off_type(-1)), which indicates a seek failure, so | |
// we don't really have to define them, but I've done so for the sake | |
// of pedantry. | |
class dummy_streambuf | |
: public std::basic_streambuf<char> | |
{ | |
private: | |
using base = std::basic_streambuf<char>; | |
using base::pos_type; | |
using base::off_type; | |
char m_sentinel; | |
public: | |
dummy_streambuf() | |
: base() | |
, m_sentinel(0x2A) | |
{ | |
this->setp(&m_sentinel, &m_sentinel + 1u); | |
this->setg(&m_sentinel, &m_sentinel, &m_sentinel + 1u); | |
} | |
private: | |
pos_type | |
seekoff( | |
off_type /*off*/, | |
std::ios_base::seekdir /*way*/, | |
std::ios_base::openmode /*which*/ | |
) override { | |
return pos_type{off_type{-1}}; | |
} | |
pos_type | |
seekpos( | |
pos_type /*pos*/, | |
std::ios_base::openmode /*which*/ | |
) override { | |
return pos_type{off_type{-1}}; | |
} | |
}; | |
void | |
testbits( | |
std::iostream const& stream | |
) { | |
using ios = std::ios_base; | |
ios::iostate const states = stream.rdstate(); | |
std::cout | |
<< "states: " << states << ' ' | |
<< (states & ios::badbit ? " " : "!") << "b " | |
<< (states & ios::failbit ? " " : "!") << "f " | |
<< (states & ios::eofbit ? " " : "!") << "e " | |
<< '\n' | |
; | |
} | |
signed | |
main() { | |
dummy_streambuf sb{}; | |
std::iostream stream{&sb}; | |
// All asserts here fail on libc++ rev 192988, but pass on | |
// libstdc++ 4.7.3. The standard mandates that seekp() and seekg() | |
// should set failbit if pubseekoff() or pubseekpos() fail. | |
// libc++'s implementations of seekp(off, which) and | |
// seekg(off, which) ignore the return value of pubseekoff() | |
// (see patch). | |
// seek beg: -1 (before beginning) | |
stream.clear(); | |
stream.seekp(-1, std::ios_base::beg); | |
testbits(stream); assert(!stream.good()); | |
stream.clear(); | |
stream.seekg(-1, std::ios_base::beg); | |
testbits(stream); assert(!stream.good()); | |
// seek cur: 0 (mandated failure because of dummy_streambuf | |
// implementation -- or rather: the lack thereof) | |
stream.clear(); | |
stream.seekp( 0, std::ios_base::cur); | |
testbits(stream); assert(!stream.good()); | |
stream.clear(); | |
stream.seekg( 0, std::ios_base::cur); | |
testbits(stream); assert(!stream.good()); | |
// seek end: +1 (past end) | |
stream.clear(); | |
stream.seekp(+1, std::ios_base::end); | |
testbits(stream); assert(!stream.good()); | |
stream.clear(); | |
stream.seekg(+1, std::ios_base::end); | |
testbits(stream); assert(!stream.good()); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: include/istream | |
=================================================================== | |
--- include/istream (revision 192988) | |
+++ include/istream (working copy) | |
@@ -1369,8 +1369,10 @@ | |
this->clear(this->rdstate() & ~ios_base::eofbit); | |
sentry __sen(*this, true); | |
if (__sen) | |
+ { | |
if (this->rdbuf()->pubseekpos(__pos, ios_base::in) == pos_type(-1)) | |
this->setstate(ios_base::failbit); | |
+ } | |
#ifndef _LIBCPP_NO_EXCEPTIONS | |
} | |
catch (...) | |
@@ -1391,7 +1393,10 @@ | |
#endif // _LIBCPP_NO_EXCEPTIONS | |
sentry __sen(*this, true); | |
if (__sen) | |
- this->rdbuf()->pubseekoff(__off, __dir, ios_base::in); | |
+ { | |
+ if (this->rdbuf()->pubseekoff(__off, __dir, ios_base::in) == pos_type(-1)) | |
+ this->setstate(ios_base::failbit); | |
+ } | |
#ifndef _LIBCPP_NO_EXCEPTIONS | |
} | |
catch (...) | |
Index: include/ostream | |
=================================================================== | |
--- include/ostream (revision 192988) | |
+++ include/ostream (working copy) | |
@@ -1173,7 +1173,10 @@ | |
basic_ostream<_CharT, _Traits>::seekp(off_type __off, ios_base::seekdir __dir) | |
{ | |
if (!this->fail()) | |
- this->rdbuf()->pubseekoff(__off, __dir, ios_base::out); | |
+ { | |
+ if (this->rdbuf()->pubseekoff(__off, __dir, ios_base::out) == pos_type(-1)) | |
+ this->setstate(ios_base::failbit); | |
+ } | |
return *this; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Apparently my skimming of the standard was insufficient (I blame the iostream library). The standard mis-specifies
seekp()
andseekg()
. LWG issue is forthcoming (thanks to marshall on irc.oftc.net/#llvm).