summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGeert Bosch <geert.bosch@mongodb.com>2019-12-22 14:15:44 +0000
committerevergreen <evergreen@mongodb.com>2019-12-22 14:15:44 +0000
commit230c60a4f74e09bd5b5dd55112e4ae37be4e94f3 (patch)
tree5ac3d6cb9935205f6b92e77447bf7f1cb79c45bc /src
parent8add28c5da7d9906aa3625fce074612f634e1619 (diff)
downloadmongo-230c60a4f74e09bd5b5dd55112e4ae37be4e94f3.tar.gz
SERVER-45214 FieldParser::extractNumber fails ubsan for NaNs
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/field_parser.cpp7
-rw-r--r--src/mongo/db/field_parser_test.cpp68
2 files changed, 73 insertions, 2 deletions
diff --git a/src/mongo/db/field_parser.cpp b/src/mongo/db/field_parser.cpp
index a72c03b81d2..94207bf7d22 100644
--- a/src/mongo/db/field_parser.cpp
+++ b/src/mongo/db/field_parser.cpp
@@ -294,7 +294,10 @@ FieldParser::FieldState FieldParser::extractNumber(BSONElement elem,
}
if (elem.isNumber()) {
- *out = elem.numberInt();
+ auto num = std::clamp(elem.safeNumberLong(),
+ static_cast<long long>(std::numeric_limits<int>::min()),
+ static_cast<long long>(std::numeric_limits<int>::max()));
+ *out = static_cast<int>(num);
return FIELD_SET;
}
@@ -352,7 +355,7 @@ FieldParser::FieldState FieldParser::extractNumber(BSONElement elem,
}
if (elem.isNumber()) {
- *out = elem.numberLong();
+ *out = elem.safeNumberLong();
return FIELD_SET;
}
diff --git a/src/mongo/db/field_parser_test.cpp b/src/mongo/db/field_parser_test.cpp
index dfb0b7f0d7a..adf8e2c59dc 100644
--- a/src/mongo/db/field_parser_test.cpp
+++ b/src/mongo/db/field_parser_test.cpp
@@ -27,12 +27,14 @@
* it in the license file.
*/
+#include <limits>
#include <map>
#include <string>
#include <vector>
#include "mongo/db/field_parser.h"
#include "mongo/db/jsobj.h"
+#include "mongo/platform/decimal128.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/time_support.h"
@@ -466,4 +468,70 @@ TEST(EdgeCases, EmbeddedNullStrings) {
ASSERT_EQUALS(errMsg, "");
}
+TEST(ExtractNumber, IntCases) {
+ const int initialNum = 123;
+ const int defaultNum = 42;
+ const int minNum = INT_MIN;
+ const int maxNum = INT_MAX;
+ const auto decimalNum = mongo::Decimal128("-1.50");
+ auto numbers = BSON("tooSmall" << LLONG_MIN << "tooLarge" << (1LL << 31) << "infinity"
+ << std::numeric_limits<double>::infinity() << "minusInfinity"
+ << -std::numeric_limits<double>::infinity() << "NaN"
+ << std::numeric_limits<double>::quiet_NaN() << "hugeDouble"
+ << 9.9E+99 << "decimal" << decimalNum << "int" << defaultNum);
+
+ int num = initialNum;
+ auto tooSmallField = BSONField<int>("tooSmall");
+ auto tooLargeField = BSONField<int>("tooLarge");
+ auto infinityField = BSONField<int>("infinity");
+ auto minusInfinityField = BSONField<int>("minusInfinity");
+ auto NaNField = BSONField<int>("NaN");
+ auto hugeField = BSONField<int>("hugeDouble");
+ auto decimalField = BSONField<int>("decimal");
+ auto intField = BSONField<int>("int");
+ auto missingField = BSONField<int>("missing");
+ auto defaultedField = BSONField<int>("defaulted", defaultNum);
+
+ // Failure case.
+ FieldParser::FieldState fs = FieldParser::extractNumber(numbers, missingField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_NONE);
+ ASSERT_EQ(num, initialNum);
+
+ // Success cases.
+ fs = FieldParser::extractNumber(numbers, defaultedField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_DEFAULT);
+ ASSERT_EQ(num, defaultNum);
+
+ fs = FieldParser::extractNumber(numbers, tooSmallField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_SET);
+ ASSERT_EQ(num, minNum);
+
+ fs = FieldParser::extractNumber(numbers, tooLargeField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_SET);
+ ASSERT_EQ(num, maxNum);
+
+ fs = FieldParser::extractNumber(numbers, hugeField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_SET);
+ ASSERT_EQ(num, maxNum);
+
+ fs = FieldParser::extractNumber(numbers, minusInfinityField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_SET);
+ ASSERT_EQ(num, minNum);
+
+ fs = FieldParser::extractNumber(numbers, infinityField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_SET);
+ ASSERT_EQ(num, maxNum);
+
+ fs = FieldParser::extractNumber(numbers, intField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_SET);
+ ASSERT_EQ(num, defaultNum);
+
+ fs = FieldParser::extractNumber(numbers, NaNField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_SET);
+ ASSERT_EQ(num, 0);
+
+ fs = FieldParser::extractNumber(numbers, decimalField, &num);
+ ASSERT_EQ(fs, FieldParser::FieldState::FIELD_SET);
+ ASSERT_EQ(num, -2);
+}
} // unnamed namespace