summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@10gen.com>2013-01-09 11:57:29 -0500
committerAndy Schwerin <schwerin@10gen.com>2013-01-09 17:32:12 -0500
commitb2ab9737664420fbaeaf16c39f06bd53dfc13a4f (patch)
tree5b3fd835cb0a2224ecc58a30dcc950ab3b0234d1
parent641faecc1dfe888c1061b18d707665f027f221c4 (diff)
downloadmongo-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.cpp33
-rw-r--r--src/mongo/base/parse_number_test.cpp30
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() {