Skip to content

Instantly share code, notes, and snippets.

@komiga
Last active December 25, 2015 21:58
Show Gist options
  • Save komiga/7045925 to your computer and use it in GitHub Desktop.
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.
#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;
}
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;
}
@komiga
Copy link
Author

komiga commented Oct 22, 2013

Apparently my skimming of the standard was insufficient (I blame the iostream library). The standard mis-specifies seekp() and seekg(). LWG issue is forthcoming (thanks to marshall on irc.oftc.net/#llvm).

@mclow
Copy link

mclow commented Oct 28, 2013

The LWG issue is #2341

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment