BIND 10 trac2572, updated. 54cbb54f358dd83e6c87f23ed17c5df754a28dc7 [2572] adjusted getTotalSourceSize() to handle unknown source size

BIND 10 source code commits bind10-changes at lists.isc.org
Thu Jan 10 23:37:08 UTC 2013


The branch, trac2572 has been updated
       via  54cbb54f358dd83e6c87f23ed17c5df754a28dc7 (commit)
       via  4baf3a4dcacaa5d2fe57dba1a8cb1eee68cd0f21 (commit)
      from  76ca31298b2e7f5d85904045aaa6560bcf7ff8d6 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 54cbb54f358dd83e6c87f23ed17c5df754a28dc7
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Jan 10 15:37:11 2013 -0800

    [2572] adjusted getTotalSourceSize() to handle unknown source size

commit 4baf3a4dcacaa5d2fe57dba1a8cb1eee68cd0f21
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Jan 10 15:23:29 2013 -0800

    [2572] introduced a special source size of "unknown".
    
    this will help handle special cases like using the lexer with stdin
    associated with a pipe.

-----------------------------------------------------------------------

Summary of changes:
 src/lib/dns/master_lexer.cc                        |   16 ++++++++++++++++
 src/lib/dns/master_lexer.h                         |   16 ++++++++++++++++
 src/lib/dns/master_lexer_inputsource.cc            |   15 +++++++++++++--
 src/lib/dns/master_lexer_inputsource.h             |    4 +++-
 .../dns/tests/master_lexer_inputsource_unittest.cc |   12 ++++++++++--
 src/lib/dns/tests/master_lexer_unittest.cc         |   18 ++++++++++++++++++
 6 files changed, 76 insertions(+), 5 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/lib/dns/master_lexer.cc b/src/lib/dns/master_lexer.cc
index b3a618f..518bea3 100644
--- a/src/lib/dns/master_lexer.cc
+++ b/src/lib/dns/master_lexer.cc
@@ -24,12 +24,22 @@
 
 #include <bitset>
 #include <cassert>
+#include <limits>
 #include <string>
 #include <vector>
 
 namespace isc {
 namespace dns {
 
+// The definition of SOURCE_SIZE_UNKNOWN.  Note that we initialize it using
+// a method of another library.  Technically, this could trigger a static
+// initialization fiasco.  But in this particular usage it's very unlikely
+// to happen because this value is expected to be used only as a return
+// value of a MasterLexer's method, and its constructor needs definitions
+// here.
+const size_t MasterLexer::SOURCE_SIZE_UNKNOWN =
+    std::numeric_limits<size_t>::max();
+
 namespace {
 typedef boost::shared_ptr<master_lexer_internal::InputSource> InputSourcePtr;
 } // end unnamed namespace
@@ -177,6 +187,12 @@ size_t
 MasterLexer::getTotalSourceSize() const {
     size_t total_size = 0;
     BOOST_FOREACH(InputSourcePtr& src, impl_->sources_) {
+        // If the size of any pushed source is unknown, the total is also
+        // considered unknown.
+        if (src->getSize() == SOURCE_SIZE_UNKNOWN) {
+            return (SOURCE_SIZE_UNKNOWN);
+        }
+
         total_size += src->getSize();
     }
     return (total_size);
diff --git a/src/lib/dns/master_lexer.h b/src/lib/dns/master_lexer.h
index cf46c53..6f6ce7d 100644
--- a/src/lib/dns/master_lexer.h
+++ b/src/lib/dns/master_lexer.h
@@ -331,6 +331,16 @@ public:
         const MasterToken token_;
     };
 
+    /// \brief Special value for input source size meaning "unknown".
+    ///
+    /// This constant value will be used as a return value of
+    /// \c getTotalSourceSize() when the size of one of the pushed sources
+    /// is unknown.  Note that this value itself is a valid integer in the
+    /// range of the type, so there's still a small possibility of
+    /// ambiguity.  In practice, however, the value should be sufficiently
+    /// large that should eliminate the possibility.
+    static const size_t SOURCE_SIZE_UNKNOWN;
+
     /// \brief Options for getNextToken.
     ///
     /// A compound option, indicating multiple options are set, can be
@@ -458,6 +468,12 @@ public:
     /// the size of the data available in the stream at the time of the
     /// source is pushed.
     ///
+    /// In some special cases, it's possible that the size of the file or
+    /// stream is unknown.  It happens, for example, if the standard input
+    /// is associated with a pipe from the output of another process and it's
+    /// specified as an input source.  If the size of some of the pushed
+    /// pushed source is unknown, this method returns SOURCE_SIZE_UNKNOWN.
+    ///
     /// If there is no source pushed in the lexer, it returns 0.
     ///
     /// \throw None
diff --git a/src/lib/dns/master_lexer_inputsource.cc b/src/lib/dns/master_lexer_inputsource.cc
index 10d637f..335a0dd 100644
--- a/src/lib/dns/master_lexer_inputsource.cc
+++ b/src/lib/dns/master_lexer_inputsource.cc
@@ -37,16 +37,27 @@ createStreamName(const std::istream& input_stream) {
 size_t
 getStreamSize(std::istream& is) {
     is.seekg(0, std::ios_base::end);
-    if (is.fail() || is.bad()) {
+    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()) {
+        // 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".
+        is.clear();   // clear this error not to confuse later ops.
+        return (MasterLexer::SOURCE_SIZE_UNKNOWN);
     }
     const std::streampos len = is.tellg();
     if (len == -1) {
         isc_throw(InputSource::OpenError, "failed to get input size");
     }
     is.seekg(0, std::ios::beg);
-    if (is.fail() || is.bad()) {
+    if (is.fail()) {
         isc_throw(InputSource::OpenError,
                   "failed to seek beginning of input source");
     }
diff --git a/src/lib/dns/master_lexer_inputsource.h b/src/lib/dns/master_lexer_inputsource.h
index 7935059..2ad0100 100644
--- a/src/lib/dns/master_lexer_inputsource.h
+++ b/src/lib/dns/master_lexer_inputsource.h
@@ -89,8 +89,10 @@ public:
 
     /// \brief Returns the size of the input source in bytes.
     ///
+    /// If the size is unknown, it returns \c MasterLexer::SOURCE_SIZE_UNKNOWN.
+    ///
     /// See \c MasterLexer::getTotalSourceSize() for the definition of
-    /// the size of sources.
+    /// the size of sources and for when the size can be unknown.
     ///
     /// \throw None
     size_t getSize() const { return (input_size_); }
diff --git a/src/lib/dns/tests/master_lexer_inputsource_unittest.cc b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
index 1dc3408..a26b02c 100644
--- a/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
+++ b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <dns/master_lexer_inputsource.h>
+#include <dns/master_lexer.h>
 #include <exceptions/exceptions.h>
 
 #include <gtest/gtest.h>
@@ -346,9 +347,16 @@ TEST_F(InputSourceTest, getSize) {
     istringstream iss("");
     EXPECT_EQ(0, InputSource(iss).getSize());
 
-    // Pretend there's an error in the stream.  The constructor will throw
-    // in the attempt of getting the input size.
+    // Pretend there's an error in seeking in the stream.  It will be
+    // considered a seek specific error, and getSize() returns "unknown".
     iss.setstate(std::ios_base::failbit);
+    EXPECT_EQ(MasterLexer::SOURCE_SIZE_UNKNOWN, InputSource(iss).getSize());
+    // The fail bit should have been cleared.
+    EXPECT_FALSE(iss.fail());
+
+    // Pretend there's a *critical* error in the stream.  The constructor will
+    // throw in the attempt of getting the input size.
+    iss.setstate(std::ios_base::badbit);
     EXPECT_THROW(InputSource isrc(iss), InputSource::OpenError);
 
     // Check with input source from file name.  We hardcode the file size
diff --git a/src/lib/dns/tests/master_lexer_unittest.cc b/src/lib/dns/tests/master_lexer_unittest.cc
index 65ca08a..c8ab61f 100644
--- a/src/lib/dns/tests/master_lexer_unittest.cc
+++ b/src/lib/dns/tests/master_lexer_unittest.cc
@@ -142,6 +142,24 @@ TEST_F(MasterLexerTest, nestedPush) {
     EXPECT_TRUE(lexer.getSourceName().empty());
 }
 
+TEST_F(MasterLexerTest, unknownSourceSize) {
+    // Similar to the previous case, but the size of the second source
+    // will be considered "unknown" (by emulating an error).
+    ss << "test";
+    lexer.pushSource(ss);
+    EXPECT_EQ(4, lexer.getTotalSourceSize());
+
+    stringstream ss2;
+    ss2.setstate(std::ios_base::failbit); // this will make the size unknown
+    lexer.pushSource(ss2);
+    // Then the total size is also unknown.
+    EXPECT_EQ(MasterLexer::SOURCE_SIZE_UNKNOWN, lexer.getTotalSourceSize());
+
+    // If we pop that source, the size becomes known again.
+    lexer.popSource();
+    EXPECT_EQ(4, lexer.getTotalSourceSize());
+}
+
 TEST_F(MasterLexerTest, invalidPop) {
     // popSource() cannot be called if the sources stack is empty.
     EXPECT_THROW(lexer.popSource(), isc::InvalidOperation);



More information about the bind10-changes mailing list