summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmirsaman Memaripour <amirsaman.memaripour@10gen.com>2020-02-03 23:15:40 +0000
committerevergreen <evergreen@mongodb.com>2020-02-03 23:15:40 +0000
commit6527449a3c0d0acba0ace9c421fd0580b4afbffa (patch)
tree47fda59e385b1e7430b94f52a44dc8f31b6422c3
parent860b5fdf681581e211d3be50bfc67007c81530a9 (diff)
downloadmongo-6527449a3c0d0acba0ace9c421fd0580b4afbffa.tar.gz
SERVER-45920 Validate writeConcern.w
-rw-r--r--jstests/replsets/drop_db.js4
-rw-r--r--jstests/replsets/server_status_metrics.js3
-rw-r--r--src/mongo/db/repl/repl_set_config.cpp1
-rw-r--r--src/mongo/db/repl/repl_set_config.h6
-rw-r--r--src/mongo/db/write_concern_options.cpp10
-rw-r--r--src/mongo/db/write_concern_options_test.cpp9
6 files changed, 27 insertions, 6 deletions
diff --git a/jstests/replsets/drop_db.js b/jstests/replsets/drop_db.js
index 49ee3e04406..bebc101a7f9 100644
--- a/jstests/replsets/drop_db.js
+++ b/jstests/replsets/drop_db.js
@@ -49,10 +49,10 @@ checkWriteConcern(() => assert.commandWorked(primaryDB.dropDatabase({w: 1})), (c
});
primaryDB.createCollection(collName);
-checkWriteConcern(() => assert.commandFailedWithCode(primaryDB.dropDatabase({w: 100000}),
+checkWriteConcern(() => assert.commandFailedWithCode(primaryDB.dropDatabase({w: 45}),
ErrorCodes.UnsatisfiableWriteConcern),
(cmdObj) => {
- assert.eq(cmdObj.writeConcern, {w: 100000});
+ assert.eq(cmdObj.writeConcern, {w: 45});
});
rst.stopSet();
diff --git a/jstests/replsets/server_status_metrics.js b/jstests/replsets/server_status_metrics.js
index f3579a44a2d..28178a4711e 100644
--- a/jstests/replsets/server_status_metrics.js
+++ b/jstests/replsets/server_status_metrics.js
@@ -175,7 +175,8 @@ assert.commandWorked(testDB.a.insert({x: 1}, {writeConcern: {w: 1, wtimeout: 500
assert.eq(testDB.serverStatus().metrics.getLastError.wtime.totalMillis, startMillis);
assert.eq(testDB.serverStatus().metrics.getLastError.wtime.num, startNum);
-assert.commandWorked(testDB.a.insert({x: 1}, {writeConcern: {w: -11, wtimeout: 5000}}));
+assert.commandFailedWithCode(testDB.a.insert({x: 1}, {writeConcern: {w: -11, wtimeout: 5000}}),
+ ErrorCodes.FailedToParse);
assert.eq(testDB.serverStatus().metrics.getLastError.wtime.totalMillis, startMillis);
assert.eq(testDB.serverStatus().metrics.getLastError.wtime.num, startNum);
diff --git a/src/mongo/db/repl/repl_set_config.cpp b/src/mongo/db/repl/repl_set_config.cpp
index c19addc5cda..375e2a73d61 100644
--- a/src/mongo/db/repl/repl_set_config.cpp
+++ b/src/mongo/db/repl/repl_set_config.cpp
@@ -47,7 +47,6 @@ namespace repl {
// Allow the heartbeat interval to be forcibly overridden on this node.
MONGO_FAIL_POINT_DEFINE(forceHeartbeatIntervalMS);
-const size_t ReplSetConfig::kMaxMembers;
const size_t ReplSetConfig::kMaxVotingMembers;
const Milliseconds ReplSetConfig::kInfiniteCatchUpTimeout(-1);
const Milliseconds ReplSetConfig::kCatchUpDisabled(0);
diff --git a/src/mongo/db/repl/repl_set_config.h b/src/mongo/db/repl/repl_set_config.h
index 66075c5c105..d5f065d5f7b 100644
--- a/src/mongo/db/repl/repl_set_config.h
+++ b/src/mongo/db/repl/repl_set_config.h
@@ -63,7 +63,11 @@ public:
// should never be included in a valid configuration document.
static const std::string kRepairedFieldName;
- static const size_t kMaxMembers = 50;
+ /**
+ * Inline `kMaxMembers` to allow others (e.g, `WriteConcernOptions`) use
+ * the constant without linking to `repl_set_config.cpp`.
+ */
+ inline static const size_t kMaxMembers = 50;
static const size_t kMaxVotingMembers = 7;
static const Milliseconds kInfiniteCatchUpTimeout;
static const Milliseconds kCatchUpDisabled;
diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp
index 80e1c8bd0e4..f24ec703469 100644
--- a/src/mongo/db/write_concern_options.cpp
+++ b/src/mongo/db/write_concern_options.cpp
@@ -35,6 +35,7 @@
#include "mongo/base/string_data.h"
#include "mongo/bson/util/bson_extract.h"
#include "mongo/db/field_parser.h"
+#include "mongo/db/repl/repl_set_config.h"
#include "mongo/util/str.h"
namespace mongo {
@@ -151,7 +152,14 @@ StatusWith<WriteConcernOptions> WriteConcernOptions::parse(const BSONObj& obj) {
}
if (wEl.isNumber()) {
- writeConcern.wNumNodes = wEl.numberInt();
+ auto wNumNodes = wEl.safeNumberLong();
+ if (wNumNodes < 0 ||
+ wNumNodes > static_cast<decltype(wNumNodes)>(repl::ReplSetConfig::kMaxMembers)) {
+ return Status(ErrorCodes::FailedToParse,
+ str::stream() << "w has to be a non-negative number and not greater than "
+ << repl::ReplSetConfig::kMaxMembers);
+ }
+ writeConcern.wNumNodes = static_cast<decltype(writeConcern.wNumNodes)>(wNumNodes);
writeConcern.usedDefaultW = false;
} else if (wEl.type() == String) {
writeConcern.wNumNodes = 0;
diff --git a/src/mongo/db/write_concern_options_test.cpp b/src/mongo/db/write_concern_options_test.cpp
index d99eaab2204..70df61cb16a 100644
--- a/src/mongo/db/write_concern_options_test.cpp
+++ b/src/mongo/db/write_concern_options_test.cpp
@@ -110,6 +110,15 @@ TEST(WriteConcernOptionsTest, ParseReturnsFailedToParseIfWIsNotNumberOrString) {
ASSERT_EQUALS("w has to be a number or a string", status.reason());
}
+TEST(WriteConcernOptionsTest, ParseReturnsFailedToParseIfWIsNegativeOrExceedsMaxMembers) {
+ auto st1 = WriteConcernOptions::parse(BSON("w" << 123)).getStatus();
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, st1);
+
+ auto st2 = WriteConcernOptions::parse(BSON("w" << -1)).getStatus();
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, st2);
+ ASSERT_EQUALS(st1.reason(), st2.reason());
+}
+
TEST(WriteConcernOptionsTest, ParseSetsWNumNodesIfWIsANumber) {
auto sw = WriteConcernOptions::parse(BSON("w" << 3));
ASSERT_OK(sw.getStatus());