BIND 10 #2371: define dns::MasterLexer class

BIND 10 Development do-not-reply at isc.org
Mon Nov 5 18:20:45 UTC 2012


#2371: define dns::MasterLexer class
-------------------------------------+-------------------------------------
                   Reporter:         |                 Owner:  jinmei
  jinmei                             |                Status:  reviewing
                       Type:  task   |             Milestone:
                   Priority:         |  Sprint-20121106
  medium                             |            Resolution:
                  Component:         |             Sensitive:  0
  libdns++                           |           Sub-Project:  DNS
                   Keywords:         |  Estimated Difficulty:  5
            Defect Severity:  N/A    |           Total Hours:  0
Feature Depending on Ticket:         |
  loadzone-ng                        |
        Add Hours to Ticket:  0      |
                  Internal?:  0      |
-------------------------------------+-------------------------------------

Comment (by jinmei):

 Replying to [comment:15 muks]:

 > * This can be removed from `master_lexer.cc` now I think:
 > {{{
 > -#include <sstream>
 > }}}

 Ah, good catch.  Removed.

 > * I am trying to follow why the `END_OF_STREAM` definition became a
 duplicate for you. It worked here on Fedora GCC 4.7.2, so I assume this is
 a difference among compiler implementations. What compiler and version did
 you use to compile it?

 First to be clear: #2369 itself compiles.  The problem happened when I
 integrated it to this branch, where two files include inputsource.h.
 I use clang++, a specialized version by apple based on LLVM 3.1.  I
 guess you can reproduce it yourself on the macmini buildbot if you're
 interested.

 My guess is that in your case the linker combines the two definitions
 of the same constants (as they are constant) as a kind of optimization.

 > Also, does it have to be defined in
 `master_lexer_inputsource_unittest.cc`? That place seems wrong to me. Is
 it not because while there are protos everywhere, there's no actual
 storage allocation for it anywhere? Was it the compiler or linker which
 complained?

 It's a linker error:
 {{{
 Undefined symbols for architecture x86_64:
   "isc::dns::master_lexer_internal::InputSource::END_OF_STREAM",
 referenced from:
       (anonymous
 namespace)::InputSourceTest_compactDuring_Test::TestBody() in
 run_unittests-master_lexer_inputsource_unittest.o
       (anonymous namespace)::InputSourceTest_compact_Test::TestBody() in
 run_unittests-master_lexer_inputsource_unittest.o
       (anonymous
 namespace)::checkGetAndUngetChar(isc::dns::master_lexer_internal::InputSource&,
 char const*, unsigned long) in run_unittests-
 master_lexer_inputsource_unittest.o
 ld: symbol(s) not found for architecture x86_64
 }}}

 This is a common problem we've seen, and we've applied the same
 workaround (see name_unittest.cc for example).  Note that we normally
 don't need the explicit definition - for example auth/name/query.c
 uses Name::MAX_WIRE but we don't need this hack there.

 I've now looked into it more deeply, and found that EXPECT_EQ tries to
 take a reference to the parameters:

 {{{#!cpp
   template <typename T1, typename T2>
   static AssertionResult Compare(const char* expected_expression,
                                  const char* actual_expression,
                                  const T1& expected,
                                  const T2& actual) {
     return CmpHelperEQ(expected_expression, actual_expression, expected,
                        actual);
   }
 }}}

 That should be why in some tests we need the explicit definition.
 Maybe depending on the compiler it optimizes when the expected or
 actual is essentially constant, or it actually creates an instance of
 the integer for the class constant (and so the test code can refer to
 its address).

 Now what should we actually do?  As you pointed out, defining it in
 the test is probably not a good hack.  Defining it in
 master_lexer_inputsource.cc could be one solution, but I'm not sure if
 this is the best solution, because we only need to take the address in
 tests, so by defining it in the main .cc we create one instance in
 memory that is not necessary for the production code.

 So, my latest suggestion would be to define a local variable in specific
 tests that require the definition of such class static constants and
 use it in EXPECT_xx:

 {{{#!cpp
 namespace {
 // explain why we define a separate variable here
 const int END_OF_STREAM = InputSource::END_OF_STREAM;
 ...
     // This should cause EOF to be set.
     EXPECT_EQ(END_OF_STREAM, source.getChar());
 }
 }}}

 Would that work for you too?

 > * Does this work for you instead, without complaining about duplicates:

 Yes.  But see above.

 > * The error condition reporting in `MasterLexer::pushSource()` seems
 inconsistent to me. For the two error conditions that may happen, we throw
 for one file-related problem, and we return `false` and an error string
 for another file-related problem, both in the same method to open a new
 file. Maybe we can simply document that it could throw
 `InputSource::OpenError` and let the caller handle both.

 Good point, and this is actually one of the things I intended to
 document but forgot.  After thinking about how we handle user errors
 in `MasterLexer`, I concluded the best is to report possible user
 errors via return value and some kind of error code, while throwing an
 exception for other "more-unexpected" events such as disk failure
 after opening a file.  It's different from what other classes of the
 library normally do, so we can discuss it if it really makes sense.
 For now, I've added the documentation about my considerations.

 BTW, if we decide to let the exception from `InputSource` go through
 the lexer, we should move it to the main master_lexer.h (whether it's
 in or `MasterLexer` class or defined at the isc::dns namespace level);
 we shouldn't disclose the existence of the InputSource class to the
 application in the first place...hmm, in that sense `ReadError` should
 actually be moved to master_lexer.h unless we decide to always catch
 it within `MasterLexer`.

-- 
Ticket URL: <https://bind10.isc.org/ticket/2371#comment:16>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list