summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2017-12-11 13:43:58 -0500
committerMathias Stearn <mathias@10gen.com>2018-01-04 14:52:27 -0500
commit6b1a6cfe77e3c5a3b2d62a3346d19d26694ed2ed (patch)
tree23460628b1bec0e0a96a926bc12f7b64a99b4f49
parentfdc48462ba15f6923df7b2be48a8176810ac17a4 (diff)
downloadmongo-6b1a6cfe77e3c5a3b2d62a3346d19d26694ed2ed.tar.gz
SERVER-31734 rewrite massert/uassert to preserve statuses
-rw-r--r--src/mongo/util/assert_util.cpp20
-rw-r--r--src/mongo/util/assert_util.h117
-rw-r--r--src/mongo/util/signal_handlers_synchronous_test.cpp7
3 files changed, 67 insertions, 77 deletions
diff --git a/src/mongo/util/assert_util.cpp b/src/mongo/util/assert_util.cpp
index 72cc16ab515..1049b359b81 100644
--- a/src/mongo/util/assert_util.cpp
+++ b/src/mongo/util/assert_util.cpp
@@ -197,24 +197,16 @@ MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTraceWithLocation(int msgi
quickExit(EXIT_ABRUPT);
}
-NOINLINE_DECL void uassertedWithLocation(int msgid,
- StringData msg,
- const char* file,
- unsigned line) {
+NOINLINE_DECL void uassertedWithLocation(const Status& status, const char* file, unsigned line) {
assertionCount.condrollover(++assertionCount.user);
- LOG(1) << "User Assertion: " << msgid << ":" << redact(msg) << ' ' << file << ' ' << dec << line
- << endl;
- error_details::throwExceptionForStatus(Status(ErrorCodes::Error(msgid), msg));
+ LOG(1) << "User Assertion: " << redact(status) << ' ' << file << ' ' << dec << line;
+ error_details::throwExceptionForStatus(status);
}
-NOINLINE_DECL void msgassertedWithLocation(int msgid,
- StringData msg,
- const char* file,
- unsigned line) {
+NOINLINE_DECL void msgassertedWithLocation(const Status& status, const char* file, unsigned line) {
assertionCount.condrollover(++assertionCount.msg);
- error() << "Assertion: " << msgid << ":" << redact(msg) << ' ' << file << ' ' << dec << line
- << endl;
- error_details::throwExceptionForStatus(Status(ErrorCodes::Error(msgid), msg));
+ error() << "Assertion: " << redact(status) << ' ' << file << ' ' << dec << line;
+ error_details::throwExceptionForStatus(status);
}
std::string causedBy(StringData e) {
diff --git a/src/mongo/util/assert_util.h b/src/mongo/util/assert_util.h
index 71ca9485dfc..0e571f3846a 100644
--- a/src/mongo/util/assert_util.h
+++ b/src/mongo/util/assert_util.h
@@ -228,25 +228,6 @@ MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTraceWithLocation(int msgi
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 uassertedWithLocation(int msgid,
- StringData msg,
- const char* file,
- unsigned line);
-
-/** msgassert and massert are for errors that are internal but have a well defined error text
- std::string.
-*/
-
-#define msgasserted MONGO_msgasserted
-#define MONGO_msgasserted(...) ::mongo::msgassertedWithLocation(__VA_ARGS__, __FILE__, __LINE__)
-MONGO_COMPILER_NORETURN void msgassertedWithLocation(int msgid,
- StringData msg,
- const char* file,
- unsigned line);
-
/* convert various types of exceptions to strings */
std::string causedBy(StringData e);
std::string causedBy(const char* e);
@@ -291,33 +272,44 @@ inline void fassertNoTraceWithLocation(int msgid,
}
/**
- * "user assert". if asserts, user did something wrong, not our code.
+ * Common implementation for assert and assertFailed macros. Not for direct use.
*
* Using an immediately invoked lambda to give the compiler an easy way to inline the check (expr)
* and out-of-line the error path. This is most helpful when the error path involves building a
* complex error message in the expansion of msg. The call to the lambda is followed by
* 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::uassertedWithLocation(msgid, msg, __FILE__, __LINE__); \
- }(); \
- MONGO_COMPILER_UNREACHABLE; \
- } \
+#define MONGO_BASE_ASSERT_FAILED(fail_func, code, msg) \
+ do { \
+ [&]() MONGO_COMPILER_COLD_FUNCTION { \
+ fail_func(Status(ErrorCodes::Error(code), msg), __FILE__, __LINE__); \
+ }(); \
+ MONGO_COMPILER_UNREACHABLE; \
+ } while (false)
+
+#define MONGO_BASE_ASSERT(fail_func, code, msg, cond) \
+ do { \
+ if (MONGO_unlikely(!(cond))) { \
+ MONGO_BASE_ASSERT_FAILED(fail_func, code, msg); \
+ } \
} while (false)
-#define uasserted MONGO_uasserted
-#define MONGO_uasserted(...) ::mongo::uassertedWithLocation(__VA_ARGS__, __FILE__, __LINE__)
+/**
+ * "user assert". if asserts, user did something wrong, not our code.
+ * On failure, throws an exception.
+ */
+#define uasserted(msgid, msg) MONGO_BASE_ASSERT_FAILED(::mongo::uassertedWithLocation, msgid, msg)
+#define uassert(msgid, msg, expr) \
+ MONGO_BASE_ASSERT(::mongo::uassertedWithLocation, msgid, msg, expr)
+
+MONGO_COMPILER_NORETURN void uassertedWithLocation(const Status& status,
+ const char* file,
+ unsigned line);
-#define uassertStatusOK MONGO_uassertStatusOK
-#define MONGO_uassertStatusOK(...) \
- ::mongo::uassertStatusOKWithLocation(__VA_ARGS__, __FILE__, __LINE__)
+#define 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.code(), status.reason(), file, line);
+ uassertedWithLocation(status, file, line);
}
}
@@ -327,6 +319,31 @@ inline T uassertStatusOKWithLocation(StatusWith<T> sw, const char* file, unsigne
return std::move(sw.getValue());
}
+/**
+ * massert is like uassert but it logs the message before throwing.
+ */
+#define massert(msgid, msg, expr) \
+ MONGO_BASE_ASSERT(::mongo::msgassertedWithLocation, msgid, msg, expr)
+
+#define msgasserted(msgid, msg) \
+ MONGO_BASE_ASSERT_FAILED(::mongo::msgassertedWithLocation, msgid, msg)
+MONGO_COMPILER_NORETURN void msgassertedWithLocation(const Status& status,
+ const char* file,
+ unsigned line);
+
+#define 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, file, line);
+ }
+}
+
+/**
+ * fassert is our fatal assert: if it fails, the process dies.
+ *
+ * Use this rather than invariant for cases that are possible, but we have chosen not to implement
+ * recovery logic for.
+ */
#define fassertStatusOK MONGO_fassertStatusOK
#define MONGO_fassertStatusOK(...) \
::mongo::fassertStatusOKWithLocation(__VA_ARGS__, __FILE__, __LINE__)
@@ -356,33 +373,9 @@ inline void fassertStatusOKWithLocation(int msgid,
} \
} while (false)
-/* display a message, no context, and throw assertionexception
-
- easy way to throw an exception and log something without our stack trace
- display happening.
-*/
-#define massert MONGO_massert
-#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)
-
-
-#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.code(), status.reason(), file, line);
- }
-}
-
-/* same as massert except no msgid */
+/**
+ * verify is deprecated. It is like invariant() in debug builds and massert() in release builds.
+ */
#define verify(expression) MONGO_verify(expression)
#define MONGO_verify(_Expression) \
do { \
diff --git a/src/mongo/util/signal_handlers_synchronous_test.cpp b/src/mongo/util/signal_handlers_synchronous_test.cpp
index aa1d7ee29d2..ab66b189190 100644
--- a/src/mongo/util/signal_handlers_synchronous_test.cpp
+++ b/src/mongo/util/signal_handlers_synchronous_test.cpp
@@ -97,7 +97,12 @@ DEATH_TEST(FatalTerminateTest,
uasserted(28721, "Fatal second exception");
}
} tid;
- uasserted(28719, "Non-fatal first exception");
+
+ // This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83400. We should delete
+ // this variable once we are on a compiler that doesn't require it.
+ volatile bool workaroundGCCBug = true; // NOLINT
+ if (workaroundGCCBug)
+ uasserted(28719, "Non-fatal first exception");
}
} // namespace