]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[master] Fix overflow catching in number lexer state
authorJelte Jansen <jelte@isc.org>
Tue, 27 Nov 2012 21:23:53 +0000 (22:23 +0100)
committerJelte Jansen <jelte@isc.org>
Tue, 27 Nov 2012 21:23:53 +0000 (22:23 +0100)
src/lib/dns/master_lexer.cc
src/lib/dns/master_lexer.h
src/lib/dns/tests/master_lexer_state_unittest.cc
src/lib/dns/tests/master_lexer_token_unittest.cc

index 8364f80b3ae486156571d0b3ebd708fbb42688f2..a68c36e9c9255e9ff2d51496f17e66ff2cb1efc0 100644 (file)
@@ -19,6 +19,7 @@
 #include <dns/master_lexer_state.h>
 
 #include <boost/shared_ptr.hpp>
+#include <boost/lexical_cast.hpp>
 
 #include <bitset>
 #include <cassert>
@@ -210,7 +211,8 @@ const char* const error_text[] = {
     "unbalanced parentheses",   // UNBALANCED_PAREN
     "unexpected end of input",  // UNEXPECTED_END
     "unbalanced quotes",        // UNBALANCED_QUOTES
-    "no token produced"         // NO_TOKEN_PRODUCED
+    "no token produced",        // NO_TOKEN_PRODUCED
+    "number out of range"       // NUMBER_RANGE
 };
 const size_t error_text_max_count = sizeof(error_text) / sizeof(error_text[0]);
 } // end unnamed namespace
@@ -449,8 +451,6 @@ QString::handle(MasterLexer& lexer) const {
 void
 Number::handle(MasterLexer& lexer) const {
     MasterLexer::Token& token = getLexerImpl(lexer)->token_;
-    // Do we want to support octal and/or hex here?
-    const int base = 10;
 
     // It may yet turn out to be a string, so we first
     // collect all the data
@@ -465,10 +465,17 @@ Number::handle(MasterLexer& lexer) const {
         if (getLexerImpl(lexer)->isTokenEnd(c, escaped)) {
             getLexerImpl(lexer)->source_->ungetChar();
             if (digits_only) {
-                // Close the string for strtoul
+                // Close the string for lexical_cast
                 data.push_back('\0');
-                token = MasterLexer::Token(strtoul(&data.at(0),
-                                                   NULL, base));
+                try {
+                    const uint32_t number32 =
+                        boost::lexical_cast<uint32_t, const char*>(&data.at(0));
+                    token = MasterLexer::Token(number32);
+                } catch (const boost::bad_lexical_cast&) {
+                    // Since we already know we have only digits,
+                    // range should be the only possible problem.
+                    token = Token(Token::NUMBER_RANGE);
+                }
             } else {
                 token = MasterLexer::Token(&data.at(0),
                                            data.size());
index 431e0ce9b14baec238df9fb7f83011dc9423c230..2717c87c017530e2513b0ed3b5bdf7f7d99c52d5 100644 (file)
@@ -292,6 +292,7 @@ public:
         UNBALANCED_QUOTES,      ///< Unbalanced quotations detected
         NO_TOKEN_PRODUCED, ///< No token was produced. This means programmer
                            /// error and should never get out of the lexer.
+        NUMBER_RANGE,    ///< Number was out of range
         MAX_ERROR_CODE ///< Max integer corresponding to valid error codes.
                        /// (excluding this one). Mainly for internal use.
     };
index aea28d40264896849ef0b1677323feddc5e037ac..b5c1c96c8ef81238cbfc43633801a087a5b04cc2 100644 (file)
@@ -457,12 +457,9 @@ TEST_F(MasterLexerStateTest, basicNumbers) {
     ss << "1 ";
     ss << "12345 ";
     ss << "4294967295 "; // 2^32-1
-    ss << "4294967296 "; // 2^32 (this overflows to 0, we
-                         // can consider failing on it, but
-                         // this is what bind9 does as well)
-    ss << "4294967297 "; // 2^32+1 (this overflows to 1, see
-                         // above)
-    ss << "1000000000000000000 "; // overflows to 2808348672
+    ss << "4294967296 "; // Out of range
+    ss << "340282366920938463463374607431768211456 ";
+                         // Very much out of range (2^128)
     ss << "005 ";        // Leading zeroes are ignored
     ss << "42;asdf\n";   // Number with comment
     ss << "37";          // Simple number again, here to make
@@ -484,19 +481,17 @@ TEST_F(MasterLexerStateTest, basicNumbers) {
 
     EXPECT_EQ(&s_number, State::start(lexer, common_options));
     s_number.handle(lexer);
-    EXPECT_EQ(4294967295u, s_number.getToken(lexer).getNumber());
+    EXPECT_EQ(4294967295, s_number.getToken(lexer).getNumber());
 
     EXPECT_EQ(&s_number, State::start(lexer, common_options));
     s_number.handle(lexer);
-    EXPECT_EQ(0, s_number.getToken(lexer).getNumber());
-
-    EXPECT_EQ(&s_number, State::start(lexer, common_options));
-    s_number.handle(lexer);
-    EXPECT_EQ(1, s_number.getToken(lexer).getNumber());
+    EXPECT_EQ(Token::NUMBER_RANGE,
+              s_number.getToken(lexer).getErrorCode());
 
     EXPECT_EQ(&s_number, State::start(lexer, common_options));
     s_number.handle(lexer);
-    EXPECT_EQ(2808348672u, s_number.getToken(lexer).getNumber());
+    EXPECT_EQ(Token::NUMBER_RANGE,
+              s_number.getToken(lexer).getErrorCode());
 
     EXPECT_EQ(&s_number, State::start(lexer, common_options));
     s_number.handle(lexer);
index 5f887f9df7e8cd94e0be9d0f37c63a68d2ddc12b..0c13658d38ef35061198b8b4e71ea50cb44faba2 100644 (file)
@@ -145,15 +145,18 @@ TEST_F(MasterLexerTokenTest, errors) {
     EXPECT_EQ("no token produced",
               MasterLexer::Token(MasterLexer::Token::NO_TOKEN_PRODUCED).
               getErrorText());
+    EXPECT_EQ("number out of range",
+              MasterLexer::Token(MasterLexer::Token::NUMBER_RANGE).
+              getErrorText());
 
     // getErrorCode/Text() isn't allowed for non number types
     EXPECT_THROW(token_num.getErrorCode(), isc::InvalidOperation);
     EXPECT_THROW(token_num.getErrorText(), isc::InvalidOperation);
 
-    // Only the pre-defined error code is accepted.  Hardcoding '5' (max code
+    // Only the pre-defined error code is accepted.  Hardcoding '6' (max code
     // + 1) is intentional; it'd be actually better if we notice it when we
     // update the enum list (which shouldn't happen too often).
-    EXPECT_THROW(MasterLexer::Token(MasterLexer::Token::ErrorCode(5)),
+    EXPECT_THROW(MasterLexer::Token(MasterLexer::Token::ErrorCode(6)),
                  isc::InvalidParameter);
 
     // Check the coexistence of "from number" and "from error-code"