diff --git a/src/lib/dns/master_lexer_inputsource.cc b/src/lib/dns/master_lexer_inputsource.cc index ec642a23d8..7157c50a2e 100644 --- a/src/lib/dns/master_lexer_inputsource.cc +++ b/src/lib/dns/master_lexer_inputsource.cc @@ -36,32 +36,48 @@ createStreamName(const std::istream& input_stream) { size_t getStreamSize(std::istream& is) { + errno = 0; // see below is.seekg(0, std::ios_base::end); if (is.bad()) { // This means the istream has an integrity error. It doesn't make // sense to continue from this point, so we treat it as a fatal error. isc_throw(InputSource::OpenError, "failed to seek end of input source"); - } else if (is.fail()) { + } else if (is.fail() || errno != 0) { // This is an error specific to seekg(). There can be several // reasons, but the most likely cause in this context is that the // stream is associated with a special type of file such as a pipe. // In this case, it's more likely that other main operations of // the input source work fine, so we continue with just setting // the stream size to "unknown". + // + // (At least some versions of) Solaris + SunStudio shows deviant + // behavior here: It apparently calls lseek(2) internally, but even if + // it fails it doesn't set the error bits of istream. That will + // confuse the rest of this function, so, as a heuristic workaround + // we check errno and handle any non 0 value as fail(). is.clear(); // clear this error not to confuse later ops. return (MasterLexer::SOURCE_SIZE_UNKNOWN); } - const std::streampos len = is.tellg(); + std::streampos len = is.tellg(); if (len == static_cast(-1)) { // cast for some compilers - isc_throw(InputSource::OpenError, "failed to get input size"); + if (!is.fail()) { + // tellg() returns -1 if istream::fail() would be true, but it's + // not guaranteed that it shouldn't be returned in other cases. + // In fact, with the combination of SunStudio and stlport, + // an stringstream created by the default constructor showed that + // behavior. We treat such cases as an unknown size. + len = MasterLexer::SOURCE_SIZE_UNKNOWN; + } else { + isc_throw(InputSource::OpenError, "failed to get input size"); + } } is.seekg(0, std::ios::beg); if (is.fail()) { isc_throw(InputSource::OpenError, "failed to seek beginning of input source"); } - assert(len >= 0); + assert(len >= 0 || len == MasterLexer::SOURCE_SIZE_UNKNOWN); return (len); }