diff options
34 files changed, 210 insertions, 180 deletions
diff --git a/src/mongo/base/status_test.cpp b/src/mongo/base/status_test.cpp index a8896c046b1..c473c24b3e0 100644 --- a/src/mongo/base/status_test.cpp +++ b/src/mongo/base/status_test.cpp @@ -209,7 +209,7 @@ TEST(Transformers, ExceptionToStatus) { Status fromDBExcept = [=]() { try { - throw DBException(ErrorCodes::TypeMismatch, reason); + uasserted(ErrorCodes::TypeMismatch, reason); } catch (...) { return exceptionToStatus(); } diff --git a/src/mongo/bson/json.cpp b/src/mongo/bson/json.cpp index 5e132e1e5b3..f5909e6c3ff 100644 --- a/src/mongo/bson/json.cpp +++ b/src/mongo/bson/json.cpp @@ -1302,13 +1302,13 @@ BSONObj fromjson(const char* jsonString, int* len) { } catch (std::exception& e) { std::ostringstream message; message << "caught exception from within JSON parser: " << e.what(); - throw AssertionException(17031, message.str()); + uasserted(17031, message.str()); } if (ret != Status::OK()) { ostringstream message; message << "code " << ret.code() << ": " << ret.codeString() << ": " << ret.reason(); - throw AssertionException(16619, message.str()); + uasserted(16619, message.str()); } if (len) *len = jparse.offset(); diff --git a/src/mongo/client/dbclient_rs.cpp b/src/mongo/client/dbclient_rs.cpp index 84d0b2a48cf..a3fc233ab21 100644 --- a/src/mongo/client/dbclient_rs.cpp +++ b/src/mongo/client/dbclient_rs.cpp @@ -645,9 +645,9 @@ unique_ptr<DBClientCursor> DBClientReplicaSet::checkSlaveQueryResult( BSONElement code = error["code"]; if (code.isNumber() && code.Int() == ErrorCodes::NotMasterOrSecondary) { isntSecondary(); - throw DBException(14812, - str::stream() << "slave " << _lastSlaveOkHost.toString() - << " is no longer secondary"); + uasserted(14812, + str::stream() << "slave " << _lastSlaveOkHost.toString() + << " is no longer secondary"); } return result; diff --git a/src/mongo/client/mongo_uri.cpp b/src/mongo/client/mongo_uri.cpp index e7c500d719b..ba2bbbc1384 100644 --- a/src/mongo/client/mongo_uri.cpp +++ b/src/mongo/client/mongo_uri.cpp @@ -131,10 +131,10 @@ MongoURI::OptionsMap parseOptions(StringData options, StringData url) { } if (options.find('?') != std::string::npos) { - throw DBException(ErrorCodes::FailedToParse, - str::stream() - << "URI Cannot Contain multiple questions marks for mongodb:// URL: " - << url); + uasserted( + ErrorCodes::FailedToParse, + str::stream() << "URI Cannot Contain multiple questions marks for mongodb:// URL: " + << url); } const auto optionsStr = options.toString(); @@ -144,24 +144,23 @@ MongoURI::OptionsMap parseOptions(StringData options, StringData url) { ++i) { const auto opt = boost::copy_range<std::string>(*i); if (opt.empty()) { - throw DBException(ErrorCodes::FailedToParse, - str::stream() - << "Missing a key/value pair in the options for mongodb:// URL: " - << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() + << "Missing a key/value pair in the options for mongodb:// URL: " + << url); } const auto kvPair = partitionForward(opt, '='); const auto keyRaw = kvPair.first; if (keyRaw.empty()) { - throw DBException( - ErrorCodes::FailedToParse, - str::stream() - << "Missing a key for key/value pair in the options for mongodb:// URL: " - << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() + << "Missing a key for key/value pair in the options for mongodb:// URL: " + << url); } const auto key = uriDecode(keyRaw); if (!key.isOK()) { - throw DBException( + uasserted( ErrorCodes::FailedToParse, str::stream() << "Key '" << keyRaw << "' in options cannot properly be URL decoded for mongodb:// URL: " @@ -169,14 +168,14 @@ MongoURI::OptionsMap parseOptions(StringData options, StringData url) { } const auto valRaw = kvPair.second; if (valRaw.empty()) { - throw DBException(ErrorCodes::FailedToParse, - str::stream() << "Missing value for key '" << keyRaw - << "' in the options for mongodb:// URL: " - << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() << "Missing value for key '" << keyRaw + << "' in the options for mongodb:// URL: " + << url); } const auto val = uriDecode(valRaw); if (!val.isOK()) { - throw DBException( + uasserted( ErrorCodes::FailedToParse, str::stream() << "Value '" << valRaw << "' for key '" << keyRaw << "' in options cannot properly be URL decoded for mongodb:// URL: " @@ -232,7 +231,7 @@ MongoURI MongoURI::parseImpl(const std::string& url) { // 2.b Make sure that there are no question marks in the left side of the / // as any options after the ? must still have the / delimeter if (databaseAndOptions.empty() && userAndHostInfo.find('?') != std::string::npos) { - throw DBException( + uasserted( ErrorCodes::FailedToParse, str::stream() << "URI must contain slash delimeter between hosts and options for mongodb:// URL: " @@ -259,32 +258,30 @@ MongoURI MongoURI::parseImpl(const std::string& url) { }; if (containsColonOrAt(usernameSD)) { - throw DBException(ErrorCodes::FailedToParse, - str::stream() << "Username must be URL Encoded for mongodb:// URL: " - << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() << "Username must be URL Encoded for mongodb:// URL: " << url); } if (containsColonOrAt(passwordSD)) { - throw DBException(ErrorCodes::FailedToParse, - str::stream() << "Password must be URL Encoded for mongodb:// URL: " - << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() << "Password must be URL Encoded for mongodb:// URL: " << url); } // Get the username and make sure it did not fail to decode const auto usernameWithStatus = uriDecode(usernameSD); if (!usernameWithStatus.isOK()) { - throw DBException( - ErrorCodes::FailedToParse, - str::stream() << "Username cannot properly be URL decoded for mongodb:// URL: " << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() << "Username cannot properly be URL decoded for mongodb:// URL: " + << url); } const auto username = usernameWithStatus.getValue(); // Get the password and make sure it did not fail to decode const auto passwordWithStatus = uriDecode(passwordSD); if (!passwordWithStatus.isOK()) - throw DBException( - ErrorCodes::FailedToParse, - str::stream() << "Password cannot properly be URL decoded for mongodb:// URL: " << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() << "Password cannot properly be URL decoded for mongodb:// URL: " + << url); const auto password = passwordWithStatus.getValue(); // 5. Validate, split, and URL decode the host identifiers. @@ -296,9 +293,9 @@ MongoURI MongoURI::parseImpl(const std::string& url) { ++i) { const auto hostWithStatus = uriDecode(boost::copy_range<std::string>(*i)); if (!hostWithStatus.isOK()) { - throw DBException( - ErrorCodes::FailedToParse, - str::stream() << "Host cannot properly be URL decoded for mongodb:// URL: " << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() << "Host cannot properly be URL decoded for mongodb:// URL: " + << url); } const auto host = hostWithStatus.getValue(); @@ -307,7 +304,7 @@ MongoURI MongoURI::parseImpl(const std::string& url) { } if ((host.find('/') != std::string::npos) && !StringData(host).endsWith(".sock")) { - throw DBException( + uasserted( ErrorCodes::FailedToParse, str::stream() << "'" << host << "' in '" << url << "' appears to be a unix socket, but does not end in '.sock'"); @@ -316,7 +313,7 @@ MongoURI MongoURI::parseImpl(const std::string& url) { servers.push_back(uassertStatusOK(HostAndPort::parse(host))); } if (servers.empty()) { - throw DBException(ErrorCodes::FailedToParse, "No server(s) specified"); + uasserted(ErrorCodes::FailedToParse, "No server(s) specified"); } const std::string canonicalHost = servers.front().host(); @@ -324,8 +321,8 @@ MongoURI MongoURI::parseImpl(const std::string& url) { // domain name. Take that list of servers as the new list of servers. if (isSeedlist) { if (servers.size() > 1) { - throw DBException(ErrorCodes::FailedToParse, - "Only a single server may be specified with a mongo+srv:// url."); + uasserted(ErrorCodes::FailedToParse, + "Only a single server may be specified with a mongo+srv:// url."); } auto srvEntries = dns::lookupSRVRecords("_mongodb._tcp." + canonicalHost); servers.clear(); @@ -343,10 +340,10 @@ MongoURI MongoURI::parseImpl(const std::string& url) { const auto connectionOptions = dbAndOpts.second; const auto databaseWithStatus = uriDecode(databaseSD); if (!databaseWithStatus.isOK()) { - throw DBException(ErrorCodes::FailedToParse, - str::stream() << "Database name cannot properly be URL " - "decoded for mongodb:// URL: " - << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() << "Database name cannot properly be URL " + "decoded for mongodb:// URL: " + << url); } const auto database = databaseWithStatus.getValue(); @@ -357,10 +354,10 @@ MongoURI MongoURI::parseImpl(const std::string& url) { if (!database.empty() && !NamespaceString::validDBName(database, NamespaceString::DollarInDbNameBehavior::Disallow)) { - throw DBException(ErrorCodes::FailedToParse, - str::stream() << "Database name cannot have reserved " - "characters for mongodb:// URL: " - << url); + uasserted(ErrorCodes::FailedToParse, + str::stream() << "Database name cannot have reserved " + "characters for mongodb:// URL: " + << url); } // 8. Validate, split, and URL decode the connection options diff --git a/src/mongo/db/commands/eval.cpp b/src/mongo/db/commands/eval.cpp index 68589d6b7b3..6a83aadfcc0 100644 --- a/src/mongo/db/commands/eval.cpp +++ b/src/mongo/db/commands/eval.cpp @@ -214,7 +214,7 @@ public: uasserted(ErrorCodes::BadValue, str::stream() << "can't use sharded collection from db.eval"); } - throw ex; + throw; } } diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index c6ff02b154c..7f39b45a3c9 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -1663,10 +1663,10 @@ public: // *requires* rethrow AssertionExceptions - should probably fix. catch (AssertionException& e) { log() << "mr failed, removing collection" << redact(e); - throw e; + throw; } catch (std::exception& e) { log() << "mr failed, removing collection" << causedBy(e); - throw e; + throw; } catch (...) { log() << "mr failed for unknown reason, removing collection"; throw; diff --git a/src/mongo/db/concurrency/write_conflict_exception.h b/src/mongo/db/concurrency/write_conflict_exception.h index 3a6c7074a04..7b7e1cc1e9a 100644 --- a/src/mongo/db/concurrency/write_conflict_exception.h +++ b/src/mongo/db/concurrency/write_conflict_exception.h @@ -43,7 +43,7 @@ namespace mongo { * For example if two operations get the same version of a document, and then both try to * modify that document, this exception will get thrown by one of them. */ -class WriteConflictException : public DBException { +class WriteConflictException final : public DBException { public: WriteConflictException(); @@ -60,6 +60,9 @@ public: * Can be set via setParameter named traceWriteConflictExceptions. */ static AtomicBool trace; + +private: + void defineOnlyInFinalSubclassToPreventSlicing() final {} }; /** diff --git a/src/mongo/db/keys_collection_manager_sharding.cpp b/src/mongo/db/keys_collection_manager_sharding.cpp index 13bac7a5359..10c983d661b 100644 --- a/src/mongo/db/keys_collection_manager_sharding.cpp +++ b/src/mongo/db/keys_collection_manager_sharding.cpp @@ -190,8 +190,8 @@ void KeysCollectionManagerSharding::PeriodicRunner::refreshNow(OperationContext* stdx::lock_guard<stdx::mutex> lk(_mutex); if (_inShutdown) { - throw DBException(ErrorCodes::ShutdownInProgress, - "aborting keys cache refresh because node is shutting down"); + uasserted(ErrorCodes::ShutdownInProgress, + "aborting keys cache refresh because node is shutting down"); } if (_refreshRequest) { @@ -207,7 +207,7 @@ void KeysCollectionManagerSharding::PeriodicRunner::refreshNow(OperationContext* // waitFor also throws if timeout, so also throw when notification was not satisfied after // waiting. if (!refreshRequest->waitFor(opCtx, kDefaultRefreshWaitTime)) { - throw DBException(ErrorCodes::ExceededTimeLimit, "timed out waiting for refresh"); + uasserted(ErrorCodes::ExceededTimeLimit, "timed out waiting for refresh"); } } diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index 4cf25eafbad..27e53a898c9 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -509,12 +509,13 @@ WriteResult performInserts(OperationContext* opCtx, const write_ops::Insert& who if (canContinue && !fixedDoc.isOK()) { globalOpCounters.gotInsert(); - canContinue = handleError( - opCtx, - AssertionException(fixedDoc.getStatus().code(), fixedDoc.getStatus().reason()), - wholeOp.getNamespace(), - wholeOp.getWriteCommandBase(), - &out); + try { + uassertStatusOK(fixedDoc.getStatus()); + MONGO_UNREACHABLE; + } catch (const DBException& ex) { + canContinue = handleError( + opCtx, ex, wholeOp.getNamespace(), wholeOp.getWriteCommandBase(), &out); + } } if (!canContinue) diff --git a/src/mongo/db/pipeline/close_change_stream_exception.h b/src/mongo/db/pipeline/close_change_stream_exception.h index 782255e2f92..b3216d9c8a4 100644 --- a/src/mongo/db/pipeline/close_change_stream_exception.h +++ b/src/mongo/db/pipeline/close_change_stream_exception.h @@ -37,10 +37,13 @@ namespace mongo { * An exception used to signal to the aggregate and getMore commands that a change stream has been * invalidated, and the cursor should not be left open. */ -class CloseChangeStreamException : public DBException { +class CloseChangeStreamException final : public DBException { public: CloseChangeStreamException() : DBException(ErrorCodes::CloseChangeStream, "CloseChangeStream") {} + +private: + void defineOnlyInFinalSubclassToPreventSlicing() final {} }; } // namespace mongo diff --git a/src/mongo/db/repl/apply_ops.cpp b/src/mongo/db/repl/apply_ops.cpp index f6651330cbe..68fa9eba81a 100644 --- a/src/mongo/db/repl/apply_ops.cpp +++ b/src/mongo/db/repl/apply_ops.cpp @@ -165,10 +165,9 @@ Status _applyOps(OperationContext* opCtx, if (!db) { // Retry in non-atomic mode, since MMAP cannot implicitly create a new database // within an active WriteUnitOfWork. - throw DBException( - ErrorCodes::AtomicityFailure, - "cannot create a database in atomic applyOps mode; will retry without " - "atomicity"); + uasserted(ErrorCodes::AtomicityFailure, + "cannot create a database in atomic applyOps mode; will retry without " + "atomicity"); } // When processing an update on a non-existent collection, applyOperation_inlock() @@ -178,7 +177,7 @@ Status _applyOps(OperationContext* opCtx, // Additionally for inserts, we fail early on non-existent collections. auto collection = db->getCollection(opCtx, nss); if (!collection && !nss.isSystemDotIndexes() && (*opType == 'i' || *opType == 'u')) { - throw DBException( + uasserted( ErrorCodes::AtomicityFailure, str::stream() << "cannot apply insert or update operation on a non-existent namespace " @@ -189,9 +188,9 @@ Status _applyOps(OperationContext* opCtx, // Cannot specify timestamp values in an atomic applyOps. if (opObj.hasField("ts")) { - throw DBException(ErrorCodes::AtomicityFailure, - "cannot apply an op with a timestamp in atomic applyOps mode; " - "will retry without atomicity"); + uasserted(ErrorCodes::AtomicityFailure, + "cannot apply an op with a timestamp in atomic applyOps mode; " + "will retry without atomicity"); } OldClientContext ctx(opCtx, nss.ns()); @@ -218,13 +217,13 @@ Status _applyOps(OperationContext* opCtx, if (*opType == 'd') { return Status::OK(); } - throw DBException(ErrorCodes::NamespaceNotFound, - str::stream() - << "cannot apply insert or update operation on a " - "non-existent namespace " - << nss.ns() - << ": " - << mongo::redact(opObj)); + uasserted(ErrorCodes::NamespaceNotFound, + str::stream() + << "cannot apply insert or update operation on a " + "non-existent namespace " + << nss.ns() + << ": " + << mongo::redact(opObj)); } OldClientContext ctx(opCtx, nss.ns()); diff --git a/src/mongo/db/repl/master_slave.h b/src/mongo/db/repl/master_slave.h index e404a3fb0ec..cc7f9cce13a 100644 --- a/src/mongo/db/repl/master_slave.h +++ b/src/mongo/db/repl/master_slave.h @@ -59,9 +59,12 @@ extern AtomicInt32 syncing; extern const char* replInfo; /* A replication exception */ -class SyncException : public DBException { +class SyncException final : public DBException { public: SyncException() : DBException(10001, "sync exception") {} + +private: + void defineOnlyInFinalSubclassToPreventSlicing() final {} }; /* A Source is a source from which we can pull (replicate) data. diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index e91fa140176..5c023bd022c 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -588,7 +588,7 @@ void createOplog(OperationContext* opCtx, const std::string& oplogCollectionName ss << "cmdline oplogsize (" << n << ") different than existing (" << o << ") see: http://dochub.mongodb.org/core/increase-oplog"; log() << ss.str() << endl; - throw AssertionException(13257, ss.str()); + uasserted(13257, ss.str()); } } acquireOplogCollectionForLogging(opCtx); @@ -1394,8 +1394,7 @@ Status applyOperation_inlock(OperationContext* opCtx, } } else { invariant(*opType != 'c'); // commands are processed in applyCommand_inlock() - throw AssertionException( - 14825, str::stream() << "error in applyOperation : unknown opType " << *opType); + uasserted(14825, str::stream() << "error in applyOperation : unknown opType " << *opType); } return Status::OK(); diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index 0c1fc3ebb4c..d74bc54437c 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -1331,7 +1331,7 @@ void rollback_internal::syncFixUp(OperationContext* opCtx, wunit.commit(); }); } else { - throw e; + throw; } } } diff --git a/src/mongo/db/repl/rs_rollback_no_uuid.cpp b/src/mongo/db/repl/rs_rollback_no_uuid.cpp index 5c56c4f3101..b1a633abf7e 100644 --- a/src/mongo/db/repl/rs_rollback_no_uuid.cpp +++ b/src/mongo/db/repl/rs_rollback_no_uuid.cpp @@ -789,7 +789,7 @@ void syncFixUp(OperationContext* opCtx, wunit.commit(); }); } else { - throw e; + throw; } } } diff --git a/src/mongo/db/storage/mmap_v1/catalog/namespace_details.cpp b/src/mongo/db/storage/mmap_v1/catalog/namespace_details.cpp index 78bda18e878..df75d2ba8aa 100644 --- a/src/mongo/db/storage/mmap_v1/catalog/namespace_details.cpp +++ b/src/mongo/db/storage/mmap_v1/catalog/namespace_details.cpp @@ -125,7 +125,7 @@ IndexDetails& NamespaceDetails::idx(int idxNo, bool missingExpected) { Extra* e = extra(); if (!e) { if (missingExpected) - throw AssertionException(13283, "Missing Extra"); + uasserted(13283, "Missing Extra"); massert(14045, "missing Extra", e); } int i = idxNo - NIndexesBase; @@ -133,7 +133,7 @@ IndexDetails& NamespaceDetails::idx(int idxNo, bool missingExpected) { e = e->next(this); if (!e) { if (missingExpected) - throw AssertionException(14823, "missing extra"); + uasserted(14823, "missing extra"); massert(14824, "missing Extra", e); } i -= NIndexesExtra; @@ -150,7 +150,7 @@ const IndexDetails& NamespaceDetails::idx(int idxNo, bool missingExpected) const const Extra* e = extra(); if (!e) { if (missingExpected) - throw AssertionException(17421, "Missing Extra"); + uasserted(17421, "Missing Extra"); massert(17422, "missing Extra", e); } int i = idxNo - NIndexesBase; @@ -158,7 +158,7 @@ const IndexDetails& NamespaceDetails::idx(int idxNo, bool missingExpected) const e = e->next(this); if (!e) { if (missingExpected) - throw AssertionException(17423, "missing extra"); + uasserted(17423, "missing extra"); massert(17424, "missing Extra", e); } i -= NIndexesExtra; diff --git a/src/mongo/db/storage/mmap_v1/dur_journal.cpp b/src/mongo/db/storage/mmap_v1/dur_journal.cpp index 364948e3226..bfb39a0bc6c 100644 --- a/src/mongo/db/storage/mmap_v1/dur_journal.cpp +++ b/src/mongo/db/storage/mmap_v1/dur_journal.cpp @@ -417,7 +417,7 @@ void checkFreeSpace() { log() << "Please make at least " << spaceNeeded / (1024 * 1024) << "MB available in " << getJournalDir().string() << " or use --smallfiles" << endl; log() << endl; - throw AssertionException(15926, "Insufficient free space for journals"); + uasserted(15926, "Insufficient free space for journals"); } } diff --git a/src/mongo/dbtests/jsobjtests.cpp b/src/mongo/dbtests/jsobjtests.cpp index a02f611fe1b..b670cab1dae 100644 --- a/src/mongo/dbtests/jsobjtests.cpp +++ b/src/mongo/dbtests/jsobjtests.cpp @@ -2041,7 +2041,7 @@ public: void good(BSONObj o) { if (o.storageValidEmbedded().isOK()) return; - throw AssertionException(12528, (string) "should be ok for storage:" + o.toString()); + uasserted(12528, (string) "should be ok for storage:" + o.toString()); } void bad(string s) { @@ -2051,7 +2051,7 @@ public: void bad(BSONObj o) { if (!o.storageValidEmbedded().isOK()) return; - throw AssertionException(12529, (string) "should NOT be ok for storage:" + o.toString()); + uasserted(12529, (string) "should NOT be ok for storage:" + o.toString()); } void run() { diff --git a/src/mongo/logger/redaction_test.cpp b/src/mongo/logger/redaction_test.cpp index e1f12d6c4ab..7674d9e449b 100644 --- a/src/mongo/logger/redaction_test.cpp +++ b/src/mongo/logger/redaction_test.cpp @@ -53,14 +53,17 @@ TEST(RedactStatusTest, StatusOK) { TEST(RedactExceptionTest, NoRedact) { logger::globalLogDomain()->setShouldRedactLogs(false); - DBException ex(ErrorCodes::InternalError, kMsg); - ASSERT_EQ(redact(ex), ex.toString()); + ASSERT_THROWS_WITH_CHECK(uasserted(ErrorCodes::InternalError, kMsg), + DBException, + [](const DBException& ex) { ASSERT_EQ(redact(ex), ex.toString()); }); } TEST(RedactExceptionTest, BasicException) { logger::globalLogDomain()->setShouldRedactLogs(true); - DBException ex(ErrorCodes::InternalError, kMsg); - ASSERT_EQ(redact(ex), "InternalError ###"); + ASSERT_THROWS_WITH_CHECK( + uasserted(ErrorCodes::InternalError, kMsg), DBException, [](const DBException& ex) { + ASSERT_EQ(redact(ex), "InternalError ###"); + }); } TEST(RedactBSONTest, NoRedact) { diff --git a/src/mongo/s/client/parallel.cpp b/src/mongo/s/client/parallel.cpp index 5ba651ec1b6..a697d830bf8 100644 --- a/src/mongo/s/client/parallel.cpp +++ b/src/mongo/s/client/parallel.cpp @@ -68,7 +68,7 @@ void throwCursorError(DBClientCursor* cursor) { if (cursor->hasResultFlag(ResultFlag_ErrSet)) { BSONObj o = cursor->next(); - throw AssertionException(o["code"].numberInt(), o["$err"].str()); + uasserted(o["code"].numberInt(), o["$err"].str()); } } @@ -1160,7 +1160,7 @@ void ParallelSortClusteredCursor::_oldInit() { throw StaleConfigException( _ns, errMsg.str(), ChunkVersion(0, 0, OID()), ChunkVersion(0, 0, OID())); } else if (throwException) { - throw DBException(14827, errMsg.str()); + uasserted(14827, errMsg.str()); } else { warning() << redact(errMsg.str()); } diff --git a/src/mongo/s/client/sharding_connection_hook.cpp b/src/mongo/s/client/sharding_connection_hook.cpp index f2325d4c88a..94e19f2ee4e 100644 --- a/src/mongo/s/client/sharding_connection_hook.cpp +++ b/src/mongo/s/client/sharding_connection_hook.cpp @@ -54,8 +54,7 @@ ShardingConnectionHook::ShardingConnectionHook(bool shardedConnections, void ShardingConnectionHook::onCreate(DBClientBase* conn) { if (conn->type() == ConnectionString::INVALID) { - throw AssertionException(ErrorCodes::BadValue, - str::stream() << "Unrecognized connection string."); + uasserted(ErrorCodes::BadValue, str::stream() << "Unrecognized connection string."); } // Authenticate as the first thing we do diff --git a/src/mongo/s/stale_exception.h b/src/mongo/s/stale_exception.h index c340656c550..906b9e3a668 100644 --- a/src/mongo/s/stale_exception.h +++ b/src/mongo/s/stale_exception.h @@ -100,6 +100,8 @@ public: } private: + void defineOnlyInFinalSubclassToPreventSlicing() final {} + std::string _ns; ChunkVersion _received; ChunkVersion _wanted; diff --git a/src/mongo/shell/bench.cpp b/src/mongo/shell/bench.cpp index 19529f4ba04..1877ae1d078 100644 --- a/src/mongo/shell/bench.cpp +++ b/src/mongo/shell/bench.cpp @@ -1024,9 +1024,9 @@ void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) { if (!result["err"].eoo() && result["err"].type() == String && (_config->throwGLE || op.throwGLE)) - throw DBException(result["code"].eoo() ? 0 : result["code"].Int(), - (std::string) "From benchRun GLE" + - causedBy(result["err"].String())); + uasserted(result["code"].eoo() ? 0 : result["code"].Int(), + (std::string) "From benchRun GLE" + + causedBy(result["err"].String())); } } break; case OpType::INSERT: { @@ -1098,9 +1098,9 @@ void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) { if (!result["err"].eoo() && result["err"].type() == String && (_config->throwGLE || op.throwGLE)) - throw DBException(result["code"].eoo() ? 0 : result["code"].Int(), - (std::string) "From benchRun GLE" + - causedBy(result["err"].String())); + uasserted(result["code"].eoo() ? 0 : result["code"].Int(), + (std::string) "From benchRun GLE" + + causedBy(result["err"].String())); } } break; case OpType::REMOVE: { @@ -1153,9 +1153,9 @@ void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) { if (!result["err"].eoo() && result["err"].type() == String && (_config->throwGLE || op.throwGLE)) - throw DBException(result["code"].eoo() ? 0 : result["code"].Int(), - (std::string) "From benchRun GLE " + - causedBy(result["err"].String())); + uasserted(result["code"].eoo() ? 0 : result["code"].Int(), + (std::string) "From benchRun GLE " + + causedBy(result["err"].String())); } } break; case OpType::CREATEINDEX: diff --git a/src/mongo/shell/shell_options.cpp b/src/mongo/shell/shell_options.cpp index 32dcf89bef0..7898fc6fa1b 100644 --- a/src/mongo/shell/shell_options.cpp +++ b/src/mongo/shell/shell_options.cpp @@ -348,20 +348,18 @@ Status storeMongoShellOptions(const moe::Environment& params, if (params.count("writeMode")) { std::string mode = params["writeMode"].as<string>(); if (mode != "commands" && mode != "legacy" && mode != "compatibility") { - throw AssertionException( - 17396, mongoutils::str::stream() << "Unknown writeMode option: " << mode); + uasserted(17396, mongoutils::str::stream() << "Unknown writeMode option: " << mode); } shellGlobalParams.writeMode = mode; } if (params.count("readMode")) { std::string mode = params["readMode"].as<string>(); if (mode != "commands" && mode != "compatibility" && mode != "legacy") { - throw AssertionException( - 17397, - mongoutils::str::stream() - << "Unknown readMode option: '" - << mode - << "'. Valid modes are: {commands, compatibility, legacy}"); + uasserted(17397, + mongoutils::str::stream() + << "Unknown readMode option: '" + << mode + << "'. Valid modes are: {commands, compatibility, legacy}"); } shellGlobalParams.readMode = mode; } @@ -369,10 +367,10 @@ Status storeMongoShellOptions(const moe::Environment& params, std::string protos = params["rpcProtocols"].as<string>(); auto parsedRPCProtos = rpc::parseProtocolSet(protos); if (!parsedRPCProtos.isOK()) { - throw AssertionException(28653, - str::stream() << "Unknown RPC Protocols: '" << protos - << "'. Valid values are {none, opQueryOnly, " - << "opCommandOnly, all}"); + uasserted(28653, + str::stream() << "Unknown RPC Protocols: '" << protos + << "'. Valid values are {none, opQueryOnly, " + << "opCommandOnly, all}"); } shellGlobalParams.rpcProtocols = parsedRPCProtos.getValue(); } diff --git a/src/mongo/util/assert_util.cpp b/src/mongo/util/assert_util.cpp index b1433b0e3b4..bd1bc9f986a 100644 --- a/src/mongo/util/assert_util.cpp +++ b/src/mongo/util/assert_util.cpp @@ -55,6 +55,22 @@ using namespace std; namespace mongo { +namespace { + +/** + * This type is used for all exceptions that don't have a more specific type. It is defined locally + * in this file to prevent anyone from catching it specifically separately from AssertionException. + */ +class NonspecificAssertionException final : public AssertionException { +public: + using AssertionException::AssertionException; + +private: + void defineOnlyInFinalSubclassToPreventSlicing() final {} +}; + +} // namespace + AssertionCount assertionCount; AssertionCount::AssertionCount() : regular(0), warning(0), msg(0), user(0), rollovers(0) {} @@ -113,14 +129,14 @@ NOINLINE_DECL void verifyFailed(const char* expr, const char* file, unsigned lin logContext(); stringstream temp; temp << "assertion " << file << ":" << line; - AssertionException e(0, temp.str()); + breakpoint(); #if defined(MONGO_CONFIG_DEBUG_BUILD) // this is so we notice in buildbot severe() << "\n\n***aborting after verify() failure as this is a debug/test build\n\n" << endl; std::abort(); #endif - throw e; + throw NonspecificAssertionException(ErrorCodes::UnknownError, temp.str()); } NOINLINE_DECL void invariantFailed(const char* expr, const char* file, unsigned line) noexcept { @@ -186,7 +202,7 @@ NOINLINE_DECL void uassertedWithLocation(int msgid, assertionCount.condrollover(++assertionCount.user); LOG(1) << "User Assertion: " << msgid << ":" << redact(msg) << ' ' << file << ' ' << dec << line << endl; - throw AssertionException(msgid, msg); + throw NonspecificAssertionException(msgid, msg); } NOINLINE_DECL void msgassertedWithLocation(int msgid, @@ -196,7 +212,7 @@ NOINLINE_DECL void msgassertedWithLocation(int msgid, assertionCount.condrollover(++assertionCount.msg); error() << "Assertion: " << msgid << ":" << redact(msg) << ' ' << file << ' ' << dec << line << endl; - throw AssertionException(msgid, msg); + throw NonspecificAssertionException(msgid, msg); } std::string causedBy(StringData e) { diff --git a/src/mongo/util/assert_util.h b/src/mongo/util/assert_util.h index ac8713f4b22..d562799a47e 100644 --- a/src/mongo/util/assert_util.h +++ b/src/mongo/util/assert_util.h @@ -65,15 +65,7 @@ std::string causedBy(const std::string& e); /** Most mongo exceptions inherit from this; this is commonly caught in most threads */ class DBException : public std::exception { public: - DBException(const Status& status) : _status(status) { - invariant(!status.isOK()); - traceIfNeeded(*this); - } - DBException(int code, StringData msg) - : DBException(Status(code ? ErrorCodes::fromInt(code) : ErrorCodes::UnknownError, msg)) {} - virtual ~DBException() throw() {} - - virtual const char* what() const throw() { + const char* what() const throw() final { return reason().c_str(); } @@ -100,13 +92,30 @@ public: return _status.code(); } -private: - static void traceIfNeeded(const DBException& e); + std::string codeString() const { + return _status.codeString(); + } -public: static AtomicBool traceExceptions; protected: + DBException(const Status& status) : _status(status) { + invariant(!status.isOK()); + traceIfNeeded(*this); + } + + DBException(int code, StringData msg) + : DBException(Status(code ? ErrorCodes::fromInt(code) : ErrorCodes::UnknownError, msg)) {} + +private: + static void traceIfNeeded(const DBException& e); + + /** + * This method exists only to make all non-final types in this hierarchy abstract to prevent + * accidental slicing. + */ + virtual void defineOnlyInFinalSubclassToPreventSlicing() = 0; + Status _status; }; @@ -114,8 +123,6 @@ class AssertionException : public DBException { public: AssertionException(const Status& status) : DBException(status) {} AssertionException(int code, StringData msg) : DBException(code, msg) {} - - virtual ~AssertionException() throw() {} }; MONGO_COMPILER_NORETURN void verifyFailed(const char* expr, const char* file, unsigned line); diff --git a/src/mongo/util/dns_query.cpp b/src/mongo/util/dns_query.cpp index 9ce9e8743c6..3eef7240851 100644 --- a/src/mongo/util/dns_query.cpp +++ b/src/mongo/util/dns_query.cpp @@ -67,8 +67,8 @@ std::vector<std::string> dns::lookupARecords(const std::string& service) { auto response = dnsQuery.lookup(service, DNSQueryClass::kInternet, DNSQueryType::kAddress); if (response.size() == 0) { - throw DBException(ErrorCodes::DNSProtocolError, - "Looking up " + service + " A record yielded no results."); + uasserted(ErrorCodes::DNSProtocolError, + "Looking up " + service + " A record yielded no results."); } std::vector<std::string> rv; diff --git a/src/mongo/util/dns_query_posix-impl.h b/src/mongo/util/dns_query_posix-impl.h index 259135e2735..d19958010c8 100644 --- a/src/mongo/util/dns_query_posix-impl.h +++ b/src/mongo/util/dns_query_posix-impl.h @@ -100,15 +100,13 @@ public: std::vector<std::string> txtEntry() const { const auto data = this->_rawData(); if (data.empty()) { - throw DBException(ErrorCodes::DNSProtocolError, - "DNS TXT Record is not correctly sized"); + uasserted(ErrorCodes::DNSProtocolError, "DNS TXT Record is not correctly sized"); } const std::size_t amount = data.front(); const auto first = begin(data) + 1; std::vector<std::string> rv; if (data.size() - 1 < amount) { - throw DBException(ErrorCodes::DNSProtocolError, - "DNS TXT Record is not correctly sized"); + uasserted(ErrorCodes::DNSProtocolError, "DNS TXT Record is not correctly sized"); } rv.emplace_back(first, first + amount); return rv; @@ -122,7 +120,7 @@ public: auto data = _rawData(); if (data.size() != 4) { - throw DBException(ErrorCodes::DNSProtocolError, "DNS A Record is not correctly sized"); + uasserted(ErrorCodes::DNSProtocolError, "DNS A Record is not correctly sized"); } for (const std::uint8_t& ch : data) { std::ostringstream oss; @@ -145,7 +143,7 @@ public: std::ostringstream oss; oss << "Invalid record " << this->_pos << " of SRV answer for \"" << this->_service << "\": Incorrect result size"; - throw DBException(ErrorCodes::DNSProtocolError, oss.str()); + uasserted(ErrorCodes::DNSProtocolError, oss.str()); } const std::uint16_t port = [data] { std::uint16_t tmp; @@ -180,7 +178,7 @@ private: std::ostringstream oss; oss << "Invalid record " << this->_pos << " of DNS answer for \"" << this->_service << "\": \"" << strerror(errno) << "\""; - throw DBException(ErrorCodes::DNSProtocolError, oss.str()); + uasserted(ErrorCodes::DNSProtocolError, oss.str()); }; std::vector<std::uint8_t> _rawData() const { @@ -208,7 +206,7 @@ public: if (ns_initparse(this->_data.data(), this->_data.size(), &this->_ns_answer)) { std::ostringstream oss; oss << "Invalid SRV answer for \"" << this->_service << "\""; - throw DBException(ErrorCodes::DNSProtocolError, oss.str()); + uasserted(ErrorCodes::DNSProtocolError, oss.str()); } this->_nRecords = ns_msg_count(this->_ns_answer, ns_s_an); @@ -216,7 +214,7 @@ public: if (!this->_nRecords) { std::ostringstream oss; oss << "No SRV records for \"" << this->_service << "\""; - throw DBException(ErrorCodes::DNSProtocolError, oss.str()); + uasserted(ErrorCodes::DNSProtocolError, oss.str()); } } @@ -322,7 +320,7 @@ public: if (size < 0) { std::ostringstream oss; oss << "Failed to look up service \"" << service << "\": " << strerror(errno); - throw DBException(ErrorCodes::DNSHostNotFound, oss.str()); + uasserted(ErrorCodes::DNSHostNotFound, oss.str()); } result.resize(size); diff --git a/src/mongo/util/dns_query_windows-impl.h b/src/mongo/util/dns_query_windows-impl.h index 04fe778c5eb..974cb558efe 100644 --- a/src/mongo/util/dns_query_windows-impl.h +++ b/src/mongo/util/dns_query_windows-impl.h @@ -81,7 +81,7 @@ public: std::ostringstream oss; oss << "Incorrect record format for \"" << this->_service << "\": expected TXT record, found something else"; - throw DBException(ErrorCodes::DNSProtocolError, oss.str()); + uasserted(ErrorCodes::DNSProtocolError, oss.str()); } std::vector<std::string> rv; @@ -100,7 +100,7 @@ public: std::ostringstream oss; oss << "Incorrect record format for \"" << this->_service << "\": expected A record, found something else"; - throw DBException(ErrorCodes::DNSProtocolError, oss.str()); + uasserted(ErrorCodes::DNSProtocolError, oss.str()); } std::string rv; @@ -124,7 +124,7 @@ public: std::ostringstream oss; oss << "Incorrect record format for \"" << this->_service << "\": expected SRV record, found something else"; - throw DBException(ErrorCodes::DNSProtocolError, oss.str()); + uasserted(ErrorCodes::DNSProtocolError, oss.str()); } const auto& data = this->_record->Data.SRV; @@ -244,8 +244,8 @@ public: nullptr); if (ec) { - throw DBException(ErrorCodes::DNSHostNotFound, - "Failed to look up service \""s + "\":"s + errnoWithDescription(ec)); + uasserted(ErrorCodes::DNSHostNotFound, + "Failed to look up service \""s + "\":"s + errnoWithDescription(ec)); } return DNSResponse{queryResults}; } diff --git a/src/mongo/util/net/socket_exception.cpp b/src/mongo/util/net/socket_exception.cpp index 88b75fd1873..522fc8b960f 100644 --- a/src/mongo/util/net/socket_exception.cpp +++ b/src/mongo/util/net/socket_exception.cpp @@ -75,7 +75,7 @@ bool SocketException::shouldPrint() const { std::string SocketException::toString() const { std::stringstream ss; - ss << _status.codeString() << " socket exception [" << getStringType(_type) << "] "; + ss << codeString() << " socket exception [" << getStringType(_type) << "] "; if (_server.size()) ss << "server [" << _server << "] "; diff --git a/src/mongo/util/net/socket_exception.h b/src/mongo/util/net/socket_exception.h index b610e754bb3..e6e5ac25c2d 100644 --- a/src/mongo/util/net/socket_exception.h +++ b/src/mongo/util/net/socket_exception.h @@ -37,7 +37,7 @@ namespace mongo { /** * A special class of DBException thrown by Sockets. */ -class SocketException : public DBException { +class SocketException final : public DBException { public: const enum Type { CLOSED, @@ -61,6 +61,8 @@ public: std::string toString() const override; private: + void defineOnlyInFinalSubclassToPreventSlicing() final {} + std::string _server; std::string _extra; }; diff --git a/src/mongo/util/options_parser/option_description.cpp b/src/mongo/util/options_parser/option_description.cpp index 857b359b6b7..ae0b22965af 100644 --- a/src/mongo/util/options_parser/option_description.cpp +++ b/src/mongo/util/options_parser/option_description.cpp @@ -128,14 +128,14 @@ OptionDescription::OptionDescription(const std::string& dottedName, if (std::count(_deprecatedDottedNames.begin(), _deprecatedDottedNames.end(), "")) { StringBuilder sb; sb << "Attempted to register option with empty string for deprecated dotted name"; - throw DBException(ErrorCodes::BadValue, sb.str()); + uasserted(ErrorCodes::BadValue, sb.str()); } // Should not be the same as _dottedName. if (std::count(_deprecatedDottedNames.begin(), _deprecatedDottedNames.end(), dottedName)) { StringBuilder sb; sb << "Attempted to register option with conflict between dottedName and deprecated " << "dotted name: " << _dottedName; - throw DBException(ErrorCodes::BadValue, sb.str()); + uasserted(ErrorCodes::BadValue, sb.str()); } } @@ -151,7 +151,7 @@ OptionDescription& OptionDescription::setDefault(Value defaultValue) { StringBuilder sb; sb << "Could not register option \"" << _dottedName << "\": " << "Cannot register a default value for a composing option"; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } // Make sure the type of our default value matches our declared type @@ -160,7 +160,7 @@ OptionDescription& OptionDescription::setDefault(Value defaultValue) { StringBuilder sb; sb << "Could not register option \"" << _dottedName << "\": " << "mismatch between declared type and type of default value: " << ret.toString(); - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } _default = defaultValue; @@ -174,7 +174,7 @@ OptionDescription& OptionDescription::setImplicit(Value implicitValue) { StringBuilder sb; sb << "Could not register option \"" << _dottedName << "\": " << "Cannot register an implicit value for a composing option"; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } // Make sure the type of our implicit value matches our declared type @@ -183,7 +183,7 @@ OptionDescription& OptionDescription::setImplicit(Value implicitValue) { StringBuilder sb; sb << "Could not register option \"" << _dottedName << "\": " << "mismatch between declared type and type of implicit value: " << ret.toString(); - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } // It doesn't make sense to set an "implicit value" for switch options since they can never @@ -192,7 +192,7 @@ OptionDescription& OptionDescription::setImplicit(Value implicitValue) { StringBuilder sb; sb << "Could not register option \"" << _dottedName << "\": " << "the implicit value of a Switch option is true and cannot be changed"; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } _implicit = implicitValue; @@ -204,7 +204,7 @@ OptionDescription& OptionDescription::composing() { StringBuilder sb; sb << "Could not register option \"" << _dottedName << "\": " << "only options registered as StringVector or StringMap can be composing"; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } // Disallow registering a default value for a composing option since the interaction @@ -213,7 +213,7 @@ OptionDescription& OptionDescription::composing() { StringBuilder sb; sb << "Could not register option \"" << _dottedName << "\": " << "Cannot make an option with an default value composing"; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } // Disallow registering an implicit value for a composing option since the interaction @@ -222,7 +222,7 @@ OptionDescription& OptionDescription::composing() { StringBuilder sb; sb << "Could not register option \"" << _dottedName << "\": " << "Cannot make an option with an implicit value composing"; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } _isComposing = true; @@ -239,7 +239,7 @@ OptionDescription& OptionDescription::positional(int start, int end) { StringBuilder sb; sb << "Could not register option \"" << _dottedName << "\": " << "Invalid positional specification: \"start\": " << start << ", \"end\": " << end; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } if ((end - start) > 0) { @@ -248,7 +248,7 @@ OptionDescription& OptionDescription::positional(int start, int end) { sb << "Could not register option \"" << _dottedName << "\": " << "Positional range implies that multiple values are allowed, " << "but option is not registered as type StringVector"; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } } @@ -269,7 +269,7 @@ OptionDescription& OptionDescription::validRange(long min, long max) { sb << "Could not register option \"" << _dottedName << "\": " << "only options registered as a numeric type can have a valid range, " << "but option has type: " << _type; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } return addConstraint(new NumericKeyConstraint(_dottedName, min, max)); @@ -290,7 +290,7 @@ OptionDescription& OptionDescription::format(const std::string& regexFormat, sb << "Could not register option \"" << _dottedName << "\": " << "only options registered as a string type can have a required format, " << "but option has type: " << _type; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } return addConstraint(new StringFormatKeyConstraint(_dottedName, regexFormat, displayFormat)); diff --git a/src/mongo/util/options_parser/option_section.cpp b/src/mongo/util/options_parser/option_section.cpp index 4bdbb1e28c1..ff77ab0be10 100644 --- a/src/mongo/util/options_parser/option_section.cpp +++ b/src/mongo/util/options_parser/option_section.cpp @@ -90,14 +90,14 @@ OptionDescription& OptionSection::addOptionChaining( if (option._dottedName == oditerator->_dottedName) { StringBuilder sb; sb << "Attempted to register option with duplicate dottedName: " << option._dottedName; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } // Allow options with empty singleName since some options are not allowed on the command // line if (!option._singleName.empty() && option._singleName == oditerator->_singleName) { StringBuilder sb; sb << "Attempted to register option with duplicate singleName: " << option._singleName; - throw DBException(ErrorCodes::InternalError, sb.str()); + uasserted(ErrorCodes::InternalError, sb.str()); } // Deprecated dotted names should not conflict with dotted names or deprecated dotted // names of any other options. @@ -107,7 +107,7 @@ OptionDescription& OptionSection::addOptionChaining( StringBuilder sb; sb << "Attempted to register option with duplicate deprecated dotted name " << "(with another option's dotted name): " << option._dottedName; - throw DBException(ErrorCodes::BadValue, sb.str()); + uasserted(ErrorCodes::BadValue, sb.str()); } for (std::vector<std::string>::const_iterator i = oditerator->_deprecatedDottedNames.begin(); @@ -119,7 +119,7 @@ OptionDescription& OptionSection::addOptionChaining( StringBuilder sb; sb << "Attempted to register option with duplicate deprecated dotted name " << *i << " (other option " << oditerator->_dottedName << ")"; - throw DBException(ErrorCodes::BadValue, sb.str()); + uasserted(ErrorCodes::BadValue, sb.str()); } } } diff --git a/src/mongo/util/options_parser/value.h b/src/mongo/util/options_parser/value.h index 42818f60f2b..73880f63d61 100644 --- a/src/mongo/util/options_parser/value.h +++ b/src/mongo/util/options_parser/value.h @@ -171,7 +171,7 @@ T Value::as() const { if (!ret.isOK()) { StringBuilder message; message << "failed to extract typed value from Value container: " << ret.toString(); - throw AssertionException(17114, message.str()); + uasserted(17114, message.str()); } return valueType; |