diff options
author | Andy Schwerin <schwerin@10gen.com> | 2013-01-09 11:57:29 -0500 |
---|---|---|
committer | Andy Schwerin <schwerin@10gen.com> | 2013-01-09 17:32:12 -0500 |
commit | b2ab9737664420fbaeaf16c39f06bd53dfc13a4f (patch) | |
tree | 5b3fd835cb0a2224ecc58a30dcc950ab3b0234d1 | |
parent | 641faecc1dfe888c1061b18d707665f027f221c4 (diff) | |
download | mongo-b2ab9737664420fbaeaf16c39f06bd53dfc13a4f.tar.gz |
Fix handling of short, invalid inputs to parseNumberFromString() and its ilk.
There were two notable bugs. The strings "+" and "-" were parsing successfully as the
number 0. The strings "0x" and "0X" were also parsing successfully as the number
0, when they should be an error.
-rw-r--r-- | src/mongo/base/parse_number.cpp | 33 | ||||
-rw-r--r-- | src/mongo/base/parse_number_test.cpp | 30 |
2 files changed, 43 insertions, 20 deletions
diff --git a/src/mongo/base/parse_number.cpp b/src/mongo/base/parse_number.cpp index 0ecb797670f..775727d7337 100644 --- a/src/mongo/base/parse_number.cpp +++ b/src/mongo/base/parse_number.cpp @@ -74,33 +74,32 @@ namespace mongo { * "inputBase" is not 0, *outputBase is set to "inputBase". Otherwise, if "stringValue" starts * with "0x" or "0X", sets outputBase to 16, or if it starts with 0, sets outputBase to 8. * - * Returns the substring of "stringValue" with the base-indicating prefix stripped off. + * Returns stringValue, unless it sets *outputBase to 16, in which case it will strip off the + * "0x" or "0X" prefix, if present. */ static inline StringData _extractBase( const StringData& stringValue, int inputBase, int* outputBase) { + const StringData hexPrefixLower("0x", StringData::LiteralTag()); + const StringData hexPrefixUpper("0X", StringData::LiteralTag()); if (inputBase == 0) { - if (stringValue.size() == 0) { - *outputBase = inputBase; - return stringValue; + if (stringValue.size() > 2 && (stringValue.startsWith(hexPrefixLower) || + stringValue.startsWith(hexPrefixUpper))) { + *outputBase = 16; + return stringValue.substr(2); } - if (stringValue[0] == '0') { - if (stringValue.size() > 1 && (stringValue[1] == 'x' || stringValue[1] == 'X')) { - *outputBase = 16; - return stringValue.substr(2); - } + if (stringValue.size() > 1 && stringValue[0] == '0') { *outputBase = 8; - return stringValue.substr(1); + return stringValue; } *outputBase = 10; return stringValue; } else { *outputBase = inputBase; - if (inputBase == 16) { - StringData prefix = stringValue.substr(0, 2); - if (prefix == "0x" || prefix == "0X") - return stringValue.substr(2); + if (inputBase == 16 && (stringValue.startsWith(hexPrefixLower) || + stringValue.startsWith(hexPrefixUpper))) { + return stringValue.substr(2); } return stringValue; } @@ -115,12 +114,12 @@ namespace mongo { if (base == 1 || base < 0 || base > 36) return Status(ErrorCodes::BadValue, "Invalid base", 0); - if (stringValue.size() == 0) - return Status(ErrorCodes::FailedToParse, "Empty string"); - bool isNegative = false; StringData str = _extractBase(_extractSign(stringValue, &isNegative), base, &base); + if (str.empty()) + return Status(ErrorCodes::FailedToParse, "No digits"); + NumberType n(0); if (isNegative) { if (limits::is_signed) { diff --git a/src/mongo/base/parse_number_test.cpp b/src/mongo/base/parse_number_test.cpp index 3a536a08fa0..e18066b742d 100644 --- a/src/mongo/base/parse_number_test.cpp +++ b/src/mongo/base/parse_number_test.cpp @@ -58,6 +58,7 @@ namespace { static void TestParsingNonNegatives() { ASSERT_PARSES(NumberType, "10", 10); ASSERT_PARSES(NumberType, "0", 0); + ASSERT_PARSES(NumberType, "1", 1); ASSERT_PARSES(NumberType, "0xff", 0xff); ASSERT_PARSES(NumberType, "077", 077); } @@ -93,15 +94,38 @@ namespace { ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1+10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1-10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("48*3", &ignored)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("0x", &ignored)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("+", &ignored)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-", &ignored)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("+0x", &ignored)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-0x", &ignored)); } static void TestParsingWithExplicitBase() { - NumberType ignored; + NumberType x; ASSERT_PARSES_WITH_BASE(NumberType, "15b", 16, 0x15b); ASSERT_PARSES_WITH_BASE(NumberType, "77", 8, 077); ASSERT_PARSES_WITH_BASE(NumberType, "z", 36, 35); - ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("1b", 10, &ignored)); - ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("80", 8, &ignored)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("1b", 10, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("80", 8, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0X", 16, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x", 16, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x", 8, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0X", 8, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x", 10, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0X", 10, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0X", 16, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0x", 16, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0x", 8, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0X", 8, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0x", 10, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0X", 10, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0X", 16, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0x", 16, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0x", 8, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0X", 8, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0x", 10, &x)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0X", 10, &x)); } static void TestParsingLimits() { |