Browse Source

[2572] handled solaris oddity: catch uncommon/buggy results of seekg/tellg.

JINMEI Tatuya 12 years ago
parent
commit
84ba4a728f
1 changed files with 20 additions and 4 deletions
  1. 20 4
      src/lib/dns/master_lexer_inputsource.cc

+ 20 - 4
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<std::streampos>(-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);
 }