From 13ae13bf432bcf28e5b51fafc55b5460f128760c Mon Sep 17 00:00:00 2001 From: Teon Banek Date: Wed, 14 Jun 2017 17:22:26 +0200 Subject: [PATCH] Make asserts abort the program instead of exiting cleanly Summary: Since assertions should signify an abnormal program condition, it makes sense for them to call `std::abort`. This way, we'll get a core dump which can be inspected in a debugger. Update utils/assert.hpp documentation Reviewers: florijan, buda, mislav.bradac Reviewed By: buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D475 --- src/utils/assert.hpp | 100 +++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 27 deletions(-) diff --git a/src/utils/assert.hpp b/src/utils/assert.hpp index e9af9e246..d4528b513 100644 --- a/src/utils/assert.hpp +++ b/src/utils/assert.hpp @@ -1,19 +1,19 @@ /** - * Permanent Assert -> always active - * Debug Assert -> active only if DEBUG_ASSERT_ON is present + * @file + * This file defines @c permanent_assert and @c debug_assert. + * + * If @c STACKTRACE_ASSERT_ON is defined, when an assertion fails, the full + * stack trace will be printed to @c stderr, otherwise just the basic + * information will be printed out (message, file, line) */ #pragma once +#include #include #include #include "utils/stacktrace.hpp" -/** - * if STACKTRACE_ASSERT_ON is defined the full stacktrace will be printed on - * stderr otherwise just the basic information will be printed out (message, - * file, line) - */ #ifdef STACKTRACE_ASSERT_ON #define __handle_assert_message(message) \ Stacktrace stacktrace; \ @@ -26,38 +26,84 @@ #endif /** - * permanent assertion will always be active - * when condition is not satisfied program will exit + * Always check that the condition is satisfied, otherwise abort the program. * - * a good use-case for this type of assert is during unit testing because - * assert has to stay active all the time + * Unlike @c debug_assert, @c permanent_assert is always active. A good use-case + * for this type of assert is during unit testing, because assert has to be + * active regardless of the build type. + * + * @param condition Expression which has to evaluate to @c true. + * @param message Message that is to be displayed before aborting, if the + * evaluated @c condition is @c false. + * + * @sa permanent_fail + * @sa debug_assert + * @sa debug_fail */ #define permanent_assert(condition, message) \ if (!(condition)) { \ std::ostringstream s; \ s << message; \ __handle_assert_message(s.str()); \ - std::exit(EXIT_FAILURE); \ + std::abort(); \ } -#define permanent_fail(message) \ - { \ - std::ostringstream s; \ - s << message; \ - __handle_assert_message(s.str()); \ - std::exit(EXIT_FAILURE); \ - } -/** \ - * debug assertion is more like standard C assert but with custom \ - * define which controls when the assertion will be active \ - * \ - * could be used wherever the standard C assert is used but \ - * the user should not forget about DEBUG_ASSERT_ON define \ +/** + * Always abort the program with given message. + * + * Unlike @c debug_fail, @c permanent_fail is always active. This should be used + * like @c permanent_assert, but when the condition cannot be a simple + * expression. + * + * @param message Message to display before aborting. + * + * @sa permanent_assert + * @sa debug_assert + * @sa debug_fail */ +#define permanent_fail(message) \ + { \ + std::ostringstream s; \ + s << message; \ + __handle_assert_message(s.str()); \ + std::abort(); \ + } + +/** + * @def debug_assert(condition, message) + * Check that the condition is satisfied, otherwise abort the program. + * + * This is like @c permanent_assert, but the @c DEBUG_ASSERT_ON define controls + * whether this assertion is active. Without the define, @c debug_assert will do + * nothing. Therefore, this is more like the standard C @c assert facility and + * it should be used as such. For example, validating pre and post conditions of + * a function. + * + * @sa debug_fail + * @sa permanent_assert + * @sa permanent_fail + */ + +/** + * @def debug_fail(message) + * Abort the program with given message. + * + * This is like @c permanent_fail, but the @c DEBUG_ASSERT_ON define controls + * whether this assertion is active. Without the define, @c debug_fail will do + * nothing. This should be used like @c debug_assert, but when the condition + * cannot be a simple expression. + * + * @sa debug_assert + * @sa permanent_assert + * @sa permanent_fail + */ + #ifdef DEBUG_ASSERT_ON #define debug_assert(condition, message) permanent_assert(condition, message) #define debug_fail(message) permanent_fail(message) #else -#define debug_assert(condition, message) {} -#define debug_fail(message) {} +#define debug_assert(condition, message) \ + {} +#define debug_fail(message) \ + {} #endif