diff options
author | Andreas Nilsson <andreas.nilsson@mongodb.com> | 2016-07-08 16:13:15 -0400 |
---|---|---|
committer | Andreas Nilsson <andreas.nilsson@mongodb.com> | 2016-07-11 13:16:34 -0400 |
commit | c73a719b1c43e0b6b9c26e4e686ad5b1f940c67b (patch) | |
tree | 5bab18c0d07ae5bddd8acc9e0a733b0a7854bce0 /src/mongo/util | |
parent | 4d9e3e4cb09805dfb5e181536a8830f4f878275c (diff) | |
download | mongo-c73a719b1c43e0b6b9c26e4e686ad5b1f940c67b.tar.gz |
SERVER-24523 Include file and line numbers in assertions
Diffstat (limited to 'src/mongo/util')
-rw-r--r-- | src/mongo/util/SConscript | 10 | ||||
-rw-r--r-- | src/mongo/util/assert_util.cpp | 72 | ||||
-rw-r--r-- | src/mongo/util/assert_util.h | 200 | ||||
-rw-r--r-- | src/mongo/util/assert_util_test.cpp | 130 |
4 files changed, 337 insertions, 75 deletions
diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 1ccff28ecd7..b7767ee1563 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -509,3 +509,13 @@ env.CppUnitTest( LIBDEPS=[ '$BUILD_DIR/mongo/base', ]) + +env.CppUnitTest( + target='assert_util_test', + source=[ + 'assert_util_test.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + ] +) diff --git a/src/mongo/util/assert_util.cpp b/src/mongo/util/assert_util.cpp index 99b4ec6f5a0..c6ef9c7273c 100644 --- a/src/mongo/util/assert_util.cpp +++ b/src/mongo/util/assert_util.cpp @@ -165,39 +165,42 @@ NOINLINE_DECL void invariantOKFailed(const char* expr, std::abort(); } -NOINLINE_DECL void fassertFailed(int msgid) noexcept { - log() << "Fatal Assertion " << msgid << endl; +NOINLINE_DECL void fassertFailedWithLocation(int msgid, const char* file, unsigned line) noexcept { + log() << "Fatal Assertion " << msgid << " at " << file << " " << dec << line; breakpoint(); log() << "\n\n***aborting after fassert() failure\n\n" << endl; std::abort(); } -NOINLINE_DECL void fassertFailedNoTrace(int msgid) noexcept { - log() << "Fatal Assertion " << msgid << endl; +NOINLINE_DECL void fassertFailedNoTraceWithLocation(int msgid, + const char* file, + unsigned line) noexcept { + log() << "Fatal Assertion " << msgid << " at " << file << " " << dec << line; breakpoint(); log() << "\n\n***aborting after fassert() failure\n\n" << endl; quickExit(EXIT_ABRUPT); } -MONGO_COMPILER_NORETURN void fassertFailedWithStatus(int msgid, const Status& status) noexcept { - log() << "Fatal assertion " << msgid << " " << status; +MONGO_COMPILER_NORETURN void fassertFailedWithStatusWithLocation(int msgid, + const Status& status, + const char* file, + unsigned line) noexcept { + log() << "Fatal assertion " << msgid << " " << status << " at " << file << " " << dec << line; breakpoint(); log() << "\n\n***aborting after fassert() failure\n\n" << endl; std::abort(); } -MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTrace(int msgid, - const Status& status) noexcept { - log() << "Fatal assertion " << msgid << " " << status; +MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTraceWithLocation(int msgid, + const Status& status, + const char* file, + unsigned line) noexcept { + log() << "Fatal assertion " << msgid << " " << status << " at " << file << " " << dec << line; breakpoint(); log() << "\n\n***aborting after fassert() failure\n\n" << endl; quickExit(EXIT_ABRUPT); } -void uasserted(int msgid, const string& msg) { - uasserted(msgid, msg.c_str()); -} - void UserException::appendPrefix(stringstream& ss) const { ss << "userassert:"; } @@ -205,35 +208,54 @@ void MsgAssertionException::appendPrefix(stringstream& ss) const { ss << "massert:"; } -NOINLINE_DECL void uasserted(int msgid, const char* msg) { +void uassertedWithLocation(int msgid, const string& msg, const char* file, unsigned line) { + uassertedWithLocation(msgid, msg.c_str(), file, line); +} + +NOINLINE_DECL void uassertedWithLocation(int msgid, + const char* msg, + const char* file, + unsigned line) { assertionCount.condrollover(++assertionCount.user); - LOG(1) << "User Assertion: " << msgid << ":" << msg << endl; + log() << "User Assertion: " << msgid << ":" << msg << ' ' << file << ' ' << dec << line << endl; throw UserException(msgid, msg); } -void msgasserted(int msgid, const string& msg) { - msgasserted(msgid, msg.c_str()); +void msgassertedWithLocation(int msgid, const string& msg, const char* file, unsigned line) { + msgassertedWithLocation(msgid, msg.c_str(), file, line); } -NOINLINE_DECL void msgasserted(int msgid, const char* msg) { +NOINLINE_DECL void msgassertedWithLocation(int msgid, + const char* msg, + const char* file, + unsigned line) { assertionCount.condrollover(++assertionCount.warning); - log() << "Assertion: " << msgid << ":" << msg << endl; + log() << "Assertion: " << msgid << ":" << msg << ' ' << file << ' ' << dec << line << endl; logContext(); throw MsgAssertionException(msgid, msg); } -NOINLINE_DECL void msgassertedNoTrace(int msgid, const char* msg) { +NOINLINE_DECL void msgassertedNoTraceWithLocation(int msgid, + const char* msg, + const char* file, + unsigned line) { assertionCount.condrollover(++assertionCount.warning); - log() << "Assertion: " << msgid << ":" << msg << endl; + log() << "Assertion: " << msgid << ":" << msg << ' ' << file << ' ' << dec << line << endl; throw MsgAssertionException(msgid, msg); } -void msgassertedNoTrace(int msgid, const std::string& msg) { - msgassertedNoTrace(msgid, msg.c_str()); +void msgassertedNoTraceWithLocation(int msgid, + const std::string& msg, + const char* file, + unsigned line) { + msgassertedNoTraceWithLocation(msgid, msg.c_str(), file, line); } -void msgassertedNoTraceWithStatus(int msgid, const Status& status) { - msgassertedNoTrace(msgid, status.toString()); +void msgassertedNoTraceWithStatusWithLocation(int msgid, + const Status& status, + const char* file, + unsigned line) { + msgassertedNoTraceWithLocation(msgid, status.toString(), file, line); } std::string causedBy(const char* e) { diff --git a/src/mongo/util/assert_util.h b/src/mongo/util/assert_util.h index 3189639bb94..ab7dfab85a0 100644 --- a/src/mongo/util/assert_util.h +++ b/src/mongo/util/assert_util.h @@ -179,26 +179,82 @@ MONGO_COMPILER_NORETURN void invariantOKFailed(const char* expr, const char* file, unsigned line) noexcept; void wasserted(const char* expr, const char* file, unsigned line); -MONGO_COMPILER_NORETURN void fassertFailed(int msgid) noexcept; -MONGO_COMPILER_NORETURN void fassertFailedNoTrace(int msgid) noexcept; -MONGO_COMPILER_NORETURN void fassertFailedWithStatus(int msgid, const Status& status) noexcept; -MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTrace(int msgid, - const Status& status) noexcept; + +#define fassertFailed MONGO_fassertFailed +#define MONGO_fassertFailed(...) ::mongo::fassertFailedWithLocation(__VA_ARGS__, __FILE__, __LINE__) +MONGO_COMPILER_NORETURN void fassertFailedWithLocation(int msgid, + const char* file, + unsigned line) noexcept; + +#define fassertFailedNoTrace MONGO_fassertFailedNoTrace +#define MONGO_fassertFailedNoTrace(...) \ + ::mongo::fassertFailedNoTraceWithLocation(__VA_ARGS__, __FILE__, __LINE__) +MONGO_COMPILER_NORETURN void fassertFailedNoTraceWithLocation(int msgid, + const char* file, + unsigned line) noexcept; + +#define fassertFailedWithStatus MONGO_fassertFailedWithStatus +#define MONGO_fassertFailedWithStatus(...) \ + ::mongo::fassertFailedWithStatusWithLocation(__VA_ARGS__, __FILE__, __LINE__) +MONGO_COMPILER_NORETURN void fassertFailedWithStatusWithLocation(int msgid, + const Status& status, + const char* file, + unsigned line) noexcept; + +#define fassertFailedWithStatusNoTrace MONGO_fassertFailedWithStatusNoTrace +#define MONGO_fassertFailedWithStatusNoTrace(...) \ + ::mongo::fassertFailedWithStatusNoTraceWithLocation(__VA_ARGS__, __FILE__, __LINE__) +MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTraceWithLocation(int msgid, + const Status& status, + const char* file, + unsigned line) noexcept; /** a "user assertion". throws UserAssertion. logs. typically used for errors that a user could cause, such as duplicate key, disk full, etc. */ -MONGO_COMPILER_NORETURN void uasserted(int msgid, const char* msg); -MONGO_COMPILER_NORETURN void uasserted(int msgid, const std::string& msg); +MONGO_COMPILER_NORETURN void uassertedWithLocation(int msgid, + const char* msg, + const char* file, + unsigned line); +MONGO_COMPILER_NORETURN void uassertedWithLocation(int msgid, + const std::string& msg, + const char* file, + unsigned line); /** msgassert and massert are for errors that are internal but have a well defined error text std::string. a stack trace is logged. */ -MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char* msg); -MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const std::string& msg); -MONGO_COMPILER_NORETURN void msgassertedNoTraceWithStatus(int msgid, const Status& status); -MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char* msg); -MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string& msg); + +#define msgassertedNoTrace MONGO_msgassertedNoTrace +#define MONGO_msgassertedNoTrace(...) \ + ::mongo::msgassertedNoTraceWithLocation(__VA_ARGS__, __FILE__, __LINE__) +MONGO_COMPILER_NORETURN void msgassertedNoTraceWithLocation(int msgid, + const char* msg, + const char* file, + unsigned line); +MONGO_COMPILER_NORETURN void msgassertedNoTraceWithLocation(int msgid, + const std::string& msg, + const char* file, + unsigned line); + +#define msgassertedNoTraceWithStatus MONGO_msgassertedNoTraceWithStatus +#define MONGO_msgassertedNoTraceWithStatus(...) \ + ::mongo::msgassertedNoTraceWithStatusWithLocation(__VA_ARGS__, __FILE__, __LINE__) +MONGO_COMPILER_NORETURN void msgassertedNoTraceWithStatusWithLocation(int msgid, + const Status& status, + const char* file, + unsigned line); + +#define msgasserted MONGO_msgasserted +#define MONGO_msgasserted(...) ::mongo::msgassertedWithLocation(__VA_ARGS__, __FILE__, __LINE__) +MONGO_COMPILER_NORETURN void msgassertedWithLocation(int msgid, + const char* msg, + const char* file, + unsigned line); +MONGO_COMPILER_NORETURN void msgassertedWithLocation(int msgid, + const std::string& msg, + const char* file, + unsigned line); /* convert various types of exceptions to strings */ std::string causedBy(const char* e); @@ -208,27 +264,37 @@ std::string causedBy(const std::string& e); std::string causedBy(const std::string* e); std::string causedBy(const Status& e); +#define fassert MONGO_fassert +#define MONGO_fassert(...) ::mongo::fassertWithLocation(__VA_ARGS__, __FILE__, __LINE__) + /** aborts on condition failure */ -inline void fassert(int msgid, bool testOK) { - if (MONGO_unlikely(!testOK)) - fassertFailed(msgid); +inline void fassertWithLocation(int msgid, bool testOK, const char* file, unsigned line) { + if (MONGO_unlikely(!testOK)) { + fassertFailedWithLocation(msgid, file, line); + } } -inline void fassert(int msgid, const Status& status) { +inline void fassertWithLocation(int msgid, const Status& status, const char* file, unsigned line) { if (MONGO_unlikely(!status.isOK())) { - fassertFailedWithStatus(msgid, status); + fassertFailedWithStatusWithLocation(msgid, status, file, line); } } -inline void fassertNoTrace(int msgid, bool testOK) { +#define fassertNoTrace MONGO_fassertNoTrace +#define MONGO_fassertNoTrace(...) \ + ::mongo::fassertNoTraceWithLocation(__VA_ARGS__, __FILE__, __LINE__) +inline void fassertNoTraceWithLocation(int msgid, bool testOK, const char* file, unsigned line) { if (MONGO_unlikely(!testOK)) { - fassertFailedNoTrace(msgid); + fassertFailedNoTraceWithLocation(msgid, file, line); } } -inline void fassertNoTrace(int msgid, const Status& status) { +inline void fassertNoTraceWithLocation(int msgid, + const Status& status, + const char* file, + unsigned line) { if (MONGO_unlikely(!status.isOK())) { - fassertFailedWithStatusNoTrace(msgid, status); + fassertFailedWithStatusNoTraceWithLocation(msgid, status, file, line); } } @@ -241,37 +307,54 @@ inline void fassertNoTrace(int msgid, const Status& status) { * MONGO_COMPILER_UNREACHABLE as it is impossible to mark a lambda noreturn. */ #define uassert MONGO_uassert -#define MONGO_uassert(msgid, msg, expr) \ - do { \ - if (MONGO_unlikely(!(expr))) { \ - [&]() MONGO_COMPILER_COLD_FUNCTION { ::mongo::uasserted(msgid, msg); }(); \ - MONGO_COMPILER_UNREACHABLE; \ - } \ +#define MONGO_uassert(msgid, msg, expr) \ + do { \ + if (MONGO_unlikely(!(expr))) { \ + [&]() MONGO_COMPILER_COLD_FUNCTION { \ + ::mongo::uassertedWithLocation(msgid, msg, __FILE__, __LINE__); \ + }(); \ + MONGO_COMPILER_UNREACHABLE; \ + } \ } while (false) -inline void uassertStatusOK(const Status& status) { - uassert((status.location() != 0 ? status.location() : status.code()), - status.reason(), - status.isOK()); +#define uasserted MONGO_uasserted +#define MONGO_uasserted(...) ::mongo::uassertedWithLocation(__VA_ARGS__, __FILE__, __LINE__) + +#define uassertStatusOK MONGO_uassertStatusOK +#define MONGO_uassertStatusOK(...) \ + ::mongo::uassertStatusOKWithLocation(__VA_ARGS__, __FILE__, __LINE__) +inline void uassertStatusOKWithLocation(const Status& status, const char* file, unsigned line) { + if (MONGO_unlikely(!status.isOK())) { + uassertedWithLocation((status.location() != 0 ? status.location() : status.code()), + status.reason(), + file, + line); + } } template <typename T> -inline T uassertStatusOK(StatusWith<T> sw) { - uassertStatusOK(sw.getStatus()); +inline T uassertStatusOKWithLocation(StatusWith<T> sw, const char* file, unsigned line) { + uassertStatusOKWithLocation(sw.getStatus(), file, line); return std::move(sw.getValue()); } +#define fassertStatusOK MONGO_fassertStatusOK +#define MONGO_fassertStatusOK(...) \ + ::mongo::fassertStatusOKWithLocation(__VA_ARGS__, __FILE__, __LINE__) template <typename T> -inline T fassertStatusOK(int msgid, StatusWith<T> sw) { +inline T fassertStatusOKWithLocation(int msgid, StatusWith<T> sw, const char* file, unsigned line) { if (MONGO_unlikely(!sw.isOK())) { - fassertFailedWithStatus(msgid, sw.getStatus()); + fassertFailedWithStatusWithLocation(msgid, sw.getStatus(), file, line); } return std::move(sw.getValue()); } -inline void fassertStatusOK(int msgid, const Status& s) { +inline void fassertStatusOKWithLocation(int msgid, + const Status& s, + const char* file, + unsigned line) { if (MONGO_unlikely(!s.isOK())) { - fassertFailedWithStatus(msgid, s); + fassertFailedWithStatusWithLocation(msgid, s, file, line); } } @@ -290,25 +373,42 @@ inline void fassertStatusOK(int msgid, const Status& s) { display happening. */ #define massert MONGO_massert -#define MONGO_massert(msgid, msg, expr) \ - do { \ - if (MONGO_unlikely(!(expr))) { \ - [&]() MONGO_COMPILER_COLD_FUNCTION { ::mongo::msgasserted(msgid, msg); }(); \ - MONGO_COMPILER_UNREACHABLE; \ - } \ +#define MONGO_massert(msgid, msg, expr) \ + do { \ + if (MONGO_unlikely(!(expr))) { \ + [&]() MONGO_COMPILER_COLD_FUNCTION { \ + ::mongo::msgassertedWithLocation(msgid, msg, __FILE__, __LINE__); \ + }(); \ + MONGO_COMPILER_UNREACHABLE; \ + } \ } while (false) -inline void massertStatusOK(const Status& status) { - massert((status.location() != 0 ? status.location() : status.code()), - status.reason(), - status.isOK()); + +#define massertStatusOK MONGO_massertStatusOK +#define MONGO_massertStatusOK(...) \ + ::mongo::massertStatusOKWithLocation(__VA_ARGS__, __FILE__, __LINE__) +inline void massertStatusOKWithLocation(const Status& status, const char* file, unsigned line) { + if (MONGO_unlikely(!status.isOK())) { + msgassertedWithLocation((status.location() != 0 ? status.location() : status.code()), + status.reason(), + file, + line); + } } -inline void massertNoTraceStatusOK(const Status& status) { +#define massertNoTraceStatusOK MONGO_massertNoTraceStatusOK +#define MONGO_massertNoTraceStatusOK(...) \ + ::mongo::massertNoTraceStatusOKWithLocation(__VA_ARGS__, __FILE__, __LINE__) +inline void massertNoTraceStatusOKWithLocation(const Status& status, + const char* file, + unsigned line) { if (MONGO_unlikely(!status.isOK())) { [&]() MONGO_COMPILER_COLD_FUNCTION { - msgassertedNoTrace((status.location() != 0 ? status.location() : status.code()), - status.reason()); + msgassertedNoTraceWithLocation( + (status.location() != 0 ? status.location() : status.code()), + status.reason(), + file, + line); }(); MONGO_COMPILER_UNREACHABLE; } diff --git a/src/mongo/util/assert_util_test.cpp b/src/mongo/util/assert_util_test.cpp new file mode 100644 index 00000000000..a6a2f3a27c3 --- /dev/null +++ b/src/mongo/util/assert_util_test.cpp @@ -0,0 +1,130 @@ +/** + * Copyright (C) 2016 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault + +#include "mongo/platform/basic.h" + +#include "mongo/unittest/death_test.h" +#include "mongo/unittest/unittest.h" +#include "mongo/util/assert_util.h" + +namespace { +using namespace mongo; + +// uassert and its friends +DEATH_TEST(UassertionTerminationTest, uassert, "Terminating with uassert") { + uassert(40204, "Terminating with uassert", false); +} + +DEATH_TEST(UassertionTerminationTest, uasserted, "Terminating with uasserted") { + uasserted(40205, "Terminating with uasserted"); +} + +DEATH_TEST(UassertionTerminationTest, uassertStatusOK, "Terminating with uassertStatusOK") { + uassertStatusOK(Status(ErrorCodes::InternalError, "Terminating with uassertStatusOK")); +} + +DEATH_TEST(UassertionTerminationTest, uassertStatusOKOverload, "Terminating with uassertStatusOK") { + uassertStatusOK( + StatusWith<std::string>(ErrorCodes::InternalError, "Terminating with uassertStatusOK")); +} + +// fassert and its friends +DEATH_TEST(FassertionTerminationTest, fassert, "40206") { + fassert(40206, false); +} + +DEATH_TEST(FassertionTerminationTest, fassertOverload, "Terminating with fassert") { + fassert(40207, {ErrorCodes::InternalError, "Terminating with fassert"}); +} + +DEATH_TEST(FassertionTerminationTest, fassertStatusOK, "Terminating with fassertStatusOK") { + fassertStatusOK(40208, Status(ErrorCodes::InternalError, "Terminating with fassertStatusOK")); +} + +DEATH_TEST(FassertionTerminationTest, fassertStatusOKOverload, "Terminating with fassertStatusOK") { + fassertStatusOK( + 40209, + StatusWith<std::string>(ErrorCodes::InternalError, "Terminating with fassertStatusOK")); +} + +DEATH_TEST(FassertionTerminationTest, fassertFailed, "40210") { + fassertFailed(40210); +} + +DEATH_TEST(FassertionTerminationTest, fassertFailedNoTrace, "40211") { + fassertFailedNoTrace(40211); +} + +DEATH_TEST(FassertionTerminationTest, + fassertFailedWithStatus, + "Terminating with fassertFailedWithStatus") { + fassertFailedWithStatus( + 40212, {ErrorCodes::InternalError, "Terminating with fassertFailedWithStatus"}); +} + +DEATH_TEST(FassertionTerminationTest, + fassertFailedWithStatusNoTrace, + "Terminating with fassertFailedWithStatusNoTrace") { + fassertFailedWithStatusNoTrace( + 40213, {ErrorCodes::InternalError, "Terminating with fassertFailedWithStatusNoTrace"}); +} + +// massert and its friends +DEATH_TEST(MassertionTerminationTest, massert, "Terminating with massert") { + massert(40214, "Terminating with massert", false); +} + + +DEATH_TEST(MassertionTerminationTest, massertStatusOK, "Terminating with massertStatusOK") { + massertStatusOK(Status(ErrorCodes::InternalError, "Terminating with massertStatusOK")); +} + +DEATH_TEST(MassertionTerminationTest, + massertNoTraceStatusOK, + "Terminating with massertNoTraceStatusOK") { + massertNoTraceStatusOK( + Status(ErrorCodes::InternalError, "Terminating with massertNoTraceStatusOK")); +} + +DEATH_TEST(MassertionTerminationTest, msgasserted, "Terminating with msgasserted") { + msgasserted(40215, "Terminating with msgasserted"); +} + +DEATH_TEST(MassertionTerminationTest, msgassertedNoTrace, "Terminating with msgassertedNoTrace") { + msgassertedNoTrace(40216, "Terminating with msgassertedNoTrace"); +} + +DEATH_TEST(MassertionTerminationTest, + msgassertedNoTraceWithStatus, + "Terminating with msgassertedNoTraceWithStatus") { + msgassertedNoTraceWithStatus( + 40217, Status(ErrorCodes::InternalError, "Terminating with msgassertedNoTraceWithStatus")); +} +} // namespace |