summaryrefslogtreecommitdiff
path: root/src/mongo/bson
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2020-02-20 17:01:35 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-02-21 16:38:50 +0000
commit7d5a7b2afe99c12ff8260835bb6d80cbdc0ef48d (patch)
treeb05f3a241ee5f1133ea173e3e45cf0102b31d065 /src/mongo/bson
parent428ac6507118e58b6709e3dbae9fb4657e377637 (diff)
downloadmongo-7d5a7b2afe99c12ff8260835bb6d80cbdc0ef48d.tar.gz
SERVER-46071 Handle nan/inf/out-of-range inputs to integral set parameter values
Diffstat (limited to 'src/mongo/bson')
-rw-r--r--src/mongo/bson/bsonelement.h58
1 files changed, 58 insertions, 0 deletions
diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h
index e3a0e37a2bc..5ad7635ed25 100644
--- a/src/mongo/bson/bsonelement.h
+++ b/src/mongo/bson/bsonelement.h
@@ -771,6 +771,9 @@ public:
bool coerce(Decimal128* out) const;
bool coerce(std::vector<std::string>* out) const;
+ template <typename T>
+ Status tryCoerce(T* out) const;
+
/**
* Constant double representation of 2^63, the smallest value that will overflow a long long.
*
@@ -947,6 +950,61 @@ inline long long BSONElement::safeNumberLong() const {
}
/**
+ * Attempt to coerce the BSONElement to a primitive type.
+ * For integral targets, we do additional checking that the
+ * source file is a finite real number and fits within the
+ * target type.
+ */
+template <typename T>
+Status BSONElement::tryCoerce(T* out) const {
+ if constexpr (std::is_integral<T>::value && !std::is_same<bool, T>::value) {
+ if (type() == NumberDouble) {
+ double d = numberDouble();
+ if (!std::isfinite(d)) {
+ return {ErrorCodes::BadValue, "Unable to coerce NaN/Inf to integral type"};
+ }
+ if ((d > std::numeric_limits<T>::max()) || (d < std::numeric_limits<T>::lowest())) {
+ return {ErrorCodes::BadValue, "Out of bounds coercing to integral value"};
+ }
+ } else if (type() == NumberDecimal) {
+ Decimal128 d = numberDecimal();
+ if (!d.isFinite()) {
+ return {ErrorCodes::BadValue, "Unable to coerce NaN/Inf to integral type"};
+ }
+ if (d.isGreater(Decimal128(std::numeric_limits<T>::max())) ||
+ d.isLess(Decimal128(std::numeric_limits<T>::lowest()))) {
+ return {ErrorCodes::BadValue, "Out of bounds coercing to integral value"};
+ }
+ } else if (type() == mongo::Bool) {
+ *out = Bool();
+ return Status::OK();
+ }
+
+ long long val;
+ if (!coerce(&val)) {
+ return {ErrorCodes::BadValue, "Unable to coerce value to integral type"};
+ }
+
+ if (std::is_same<long long, T>::value) {
+ *out = val;
+ return Status::OK();
+ }
+
+ if ((val > std::numeric_limits<T>::max()) || (val < std::numeric_limits<T>::lowest())) {
+ return {ErrorCodes::BadValue, "Out of bounds coercing to integral value"};
+ }
+
+ *out = static_cast<T>(val);
+ return Status::OK();
+ }
+
+ if (!coerce(out)) {
+ return {ErrorCodes::BadValue, "Unable to coerce value to correct type"};
+ }
+
+ return Status::OK();
+}
+/**
* This safeNumberLongForHash() function does the same thing as safeNumberLong, but it preserves
* edge-case behavior from older versions. It's provided for use by hash functions that need to
* maintain compatibility with older versions. Don't make any changes to safeNumberLong() without