summaryrefslogtreecommitdiff
path: root/src/mongo/util/safe_num.cpp
diff options
context:
space:
mode:
authorAndrew Morrow <acm@10gen.com>2013-08-19 16:54:09 -0400
committerAndrew Morrow <acm@10gen.com>2013-08-20 11:48:46 -0400
commit95f78edec079e130c58bed831cfe341f45250784 (patch)
tree90b17d6e3d67740e39532ad5b47f46f7d2f204df /src/mongo/util/safe_num.cpp
parentfce3b4ce8fe848c332657f3accf596e6b087bce9 (diff)
downloadmongo-95f78edec079e130c58bed831cfe341f45250784.tar.gz
SERVER-375 Implement multiplication for SafeNum
Diffstat (limited to 'src/mongo/util/safe_num.cpp')
-rw-r--r--src/mongo/util/safe_num.cpp92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/mongo/util/safe_num.cpp b/src/mongo/util/safe_num.cpp
index 98864cdb550..4b26ca4f3e4 100644
--- a/src/mongo/util/safe_num.cpp
+++ b/src/mongo/util/safe_num.cpp
@@ -193,6 +193,70 @@ namespace mongo {
return SafeNum(sum);
}
+ SafeNum mulInt32Int32(int lInt32, int rInt32) {
+ // NOTE: Please see "Secure Coding in C and C++", Second Edition, page 264-265 for
+ // details on this algorithm (for an alternative resources, see
+ //
+ // https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow?showComments=false).
+ //
+ // We are using the "Downcast from a larger type" algorithm here. We always perform
+ // the arithmetic in 64-bit mode, which can never overflow for 32-bit
+ // integers. Then, if we fall within the allowable range of int, we downcast,
+ // otherwise, we retain the 64-bit result.
+
+ const long long int result =
+ static_cast<long long int>(lInt32) *
+ static_cast<long long int>(rInt32);
+
+ if (result <= std::numeric_limits<int>::max() &&
+ result >= std::numeric_limits<int>::min()) {
+ return SafeNum(static_cast<int>(result));
+ }
+
+ return SafeNum(result);
+ }
+
+ SafeNum mulInt64Int64(long long lInt64, long long rInt64) {
+ // NOTE: Please see notes in mulInt32Int32 above for references. In this case,
+ // since we have no larger integer size, if our precondition test detects overflow
+ // we must return an invalid SafeNum. Otherwise, the operation is safely performed
+ // by standard arithmetic.
+
+ if (lInt64 > 0) {
+ if (rInt64 > 0) {
+ if (lInt64 > (std::numeric_limits<long long>::max() / rInt64)) {
+ return SafeNum();
+ }
+ }
+ else {
+ if (rInt64 < (std::numeric_limits<long long>::min() / lInt64)) {
+ return SafeNum();
+ }
+ }
+ }
+ else {
+ if (rInt64 > 0) {
+ if (lInt64 < (std::numeric_limits<long long>::min() / rInt64)) {
+ return SafeNum();
+ }
+ }
+ else {
+ if ( (lInt64 != 0) &&
+ (rInt64 < (std::numeric_limits<long long>::max() / lInt64))) {
+ return SafeNum();
+ }
+ }
+ }
+
+ const long long result = lInt64 * rInt64;
+ return SafeNum(result);
+ }
+
+ SafeNum mulFloats(double lDouble, double rDouble) {
+ const double product = lDouble * rDouble;
+ return SafeNum(product);
+ }
+
} // namespace
SafeNum SafeNum::addInternal(const SafeNum& lhs, const SafeNum& rhs) {
@@ -223,6 +287,34 @@ namespace mongo {
return SafeNum();
}
+ SafeNum SafeNum::mulInternal(const SafeNum& lhs, const SafeNum& rhs) {
+ BSONType lType = lhs._type;
+ BSONType rType = rhs._type;
+
+ if (lType == NumberInt && rType == NumberInt) {
+ return mulInt32Int32(lhs._value.int32Val, rhs._value.int32Val);
+ }
+
+ if (lType == NumberInt && rType == NumberLong) {
+ return mulInt64Int64(lhs._value.int32Val, rhs._value.int64Val);
+ }
+
+ if (lType == NumberLong && rType == NumberInt) {
+ return mulInt64Int64(lhs._value.int64Val, rhs._value.int32Val);
+ }
+
+ if (lType == NumberLong && rType == NumberLong) {
+ return mulInt64Int64(lhs._value.int64Val, rhs._value.int64Val);
+ }
+
+ if ((lType == NumberInt || lType == NumberLong || lType == NumberDouble) &&
+ (rType == NumberInt || rType == NumberLong || rType == NumberDouble)) {
+ return mulFloats(getDouble(lhs), getDouble(rhs));
+ }
+
+ return SafeNum();
+ }
+
SafeNum SafeNum::andInternal(const SafeNum& lhs, const SafeNum& rhs) {
const BSONType lType = lhs._type;
const BSONType rType = rhs._type;