diff --git a/arangod/Replication2/ReplicatedLog/LogLeader.cpp b/arangod/Replication2/ReplicatedLog/LogLeader.cpp index d2905f5a65f0..0fc0ada8daf2 100644 --- a/arangod/Replication2/ReplicatedLog/LogLeader.cpp +++ b/arangod/Replication2/ReplicatedLog/LogLeader.cpp @@ -481,7 +481,8 @@ auto replicated_log::LogLeader::GuardedLeaderData::updateCommitIndexLeader( << "updating commit index to " << newIndex << "with quorum " << quorum->quorum; auto oldIndex = _commitIndex; - TRI_ASSERT(_commitIndex < newIndex); + TRI_ASSERT(_commitIndex < newIndex) + << "_commitIndex == " << _commitIndex << ", newIndex == " << newIndex; _commitIndex = newIndex; _lastQuorum = quorum; diff --git a/lib/Basics/CrashHandler.cpp b/lib/Basics/CrashHandler.cpp index ef2f5dc21470..92c29ec694c0 100644 --- a/lib/Basics/CrashHandler.cpp +++ b/lib/Basics/CrashHandler.cpp @@ -584,7 +584,7 @@ void CrashHandler::crash(char const* context) { } /// @brief logs an assertion failure and crashes the program -void CrashHandler::assertionFailure(char const* file, int line, char const* func, char const* context) { +void CrashHandler::assertionFailure(char const* file, int line, char const* func, char const* context, const char *message) { // assemble an "assertion failured in file:line: message" string char buffer[4096]; memset(&buffer[0], 0, sizeof(buffer)); @@ -601,6 +601,10 @@ void CrashHandler::assertionFailure(char const* file, int line, char const* func } appendNullTerminatedString(": ", p); appendNullTerminatedString(context, 256, p); + if (message != nullptr) { + appendNullTerminatedString(" ; ", p); + appendNullTerminatedString(message, p); + } crash(&buffer[0]); } diff --git a/lib/Basics/CrashHandler.h b/lib/Basics/CrashHandler.h index 7c5117f9a9d4..d81c41732898 100644 --- a/lib/Basics/CrashHandler.h +++ b/lib/Basics/CrashHandler.h @@ -33,7 +33,7 @@ class CrashHandler { [[noreturn]] static void crash(char const* context); /// @brief logs an assertion failure and crashes the program - [[noreturn]] static void assertionFailure(char const* file, int line, char const* func, char const* context); + [[noreturn]] static void assertionFailure(char const* file, int line, char const* func, char const* context, const char* message); /// @brief set flag to kill process hard using SIGKILL, in order to circumvent core /// file generation etc. diff --git a/lib/Basics/debugging.h b/lib/Basics/debugging.h index b987a0c4b3eb..a5557fe5c1c5 100644 --- a/lib/Basics/debugging.h +++ b/lib/Basics/debugging.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -199,6 +200,40 @@ enable_if_t::value, std::ostream&> operator<<(std::ostream& o, T return o; } +namespace debug { +struct NoOpStream { + template + auto operator<<(T const&) noexcept -> NoOpStream& { + return *this; + } +}; + +struct AssertionLogger { +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE + void operator&(std::ostringstream const& stream) const { + std::string message = stream.str(); + arangodb::CrashHandler::assertionFailure(file, line, function, expr, + message.empty() ? nullptr : message.c_str()); + } + // can be removed in C++20 because of LWG 1203 + void operator&(std::ostream const& stream) const { + operator&(static_cast(stream)); + } + + const char* file; + int line; + const char* function; + const char* expr; +#endif + void operator&(NoOpStream const&) const noexcept {} + static auto getOutputStream() -> std::ostringstream&& { + static thread_local std::ostringstream stream; + return std::move(stream); + } +}; + +} // namespace debug + } // namespace arangodb /// @brief assert @@ -206,24 +241,19 @@ enable_if_t::value, std::ostream&> operator<<(std::ostream& o, T #ifdef ARANGODB_ENABLE_MAINTAINER_MODE -#define TRI_ASSERT(expr) /*GCOVR_EXCL_LINE*/ \ - do { \ - if (!(ADB_LIKELY(expr))) { \ - arangodb::CrashHandler::assertionFailure(__FILE__, __LINE__, __FUNCTION__, #expr); \ - } else { \ - } \ - } while (false) +#define TRI_ASSERT(expr) /*GCOVR_EXCL_LINE*/ \ + (ADB_LIKELY(expr)) \ + ? (void)nullptr \ + : ::arangodb::debug::AssertionLogger{__FILE__, __LINE__, \ + ARANGODB_PRETTY_FUNCTION, #expr} & \ + ::arangodb::debug::AssertionLogger::getOutputStream() #else -#define TRI_ASSERT(expr) /*GCOVR_EXCL_LINE*/ \ - do { \ - if (false) { \ - (void)(expr); \ - } \ - } while (false) +#define TRI_ASSERT(expr) /*GCOVR_EXCL_LINE*/ \ + (true) ? ((false) ? (void)(expr) : (void)nullptr) \ + : ::arangodb::debug::AssertionLogger{} & ::arangodb::debug::NoOpStream {} #endif // #ifdef ARANGODB_ENABLE_MAINTAINER_MODE #endif // #ifndef TRI_ASSERT - diff --git a/lib/Basics/system-compiler.h b/lib/Basics/system-compiler.h index 090c2dd0fd5b..c586a3bcccc0 100644 --- a/lib/Basics/system-compiler.h +++ b/lib/Basics/system-compiler.h @@ -74,3 +74,11 @@ #endif #endif +// pretty function name macro +#if defined(__clang__) || defined(__GNUC__) +#define ARANGODB_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#elif defined(_MSC_VER) +#define ARANGODB_PRETTY_FUNCTION __FUNCSIG__ +#else +#define ARANGODB_PRETTY_FUNCTION __func__ +#endif