From 1f9f5b4d1def78f948fab510e065bc5ca01c8147 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Fri, 28 Jun 2019 15:55:56 -0400 Subject: [PATCH] lib: internal: add BT_ASSERT_POST() BT_ASSERT_POST() is just like BT_ASSERT_PRE(), but it is used to validate the returned values of user functions and methods. The only difference with BT_ASSERT_PRE() is that its error message indicates that a postcondition was not satisfied instead of a precondition. This is simply more accurate. Signed-off-by: Philippe Proulx Change-Id: I91815301ada19b42ba58f32db7b9c412cbe641e0 Reviewed-on: https://review.lttng.org/c/babeltrace/+/1574 Tested-by: jenkins Reviewed-by: Simon Marchi --- CONTRIBUTING.adoc | 1 + src/common/assert.h | 5 +- src/lib/Makefile.am | 1 + src/lib/assert-post.h | 115 ++++++++++++++++++++++++++++++++++++++++++ src/lib/assert-pre.h | 21 +++++--- 5 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 src/lib/assert-post.h diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index fbda663a..13c5b583 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -1250,6 +1250,7 @@ A _FATAL_-level logging statement should always be followed by `switch` statement. * Failed assertion (within `BT_ASSERT()`). * Unsatisfied library precondition (within `BT_ASSERT_PRE()`). +* Unsatisfied library postcondition (within `BT_ASSERT_POST()`). |Almost none: should be executed in production. |_ERROR_ diff --git a/src/common/assert.h b/src/common/assert.h index e24231a9..4e7151de 100644 --- a/src/common/assert.h +++ b/src/common/assert.h @@ -36,8 +36,9 @@ extern void bt_common_assert_failed(const char *file, int line, /* * Internal assertion (to detect logic errors on which the library user - * has no influence). Use BT_ASSERT_PRE() to check a precondition which - * must be directly or indirectly satisfied by the library user. + * has no influence). Use BT_ASSERT_PRE() or BT_ASSERT_POST() to check + * preconditions or postconditions which must be directly or indirectly + * satisfied by the library user. */ #define BT_ASSERT(_cond) \ do { \ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 84e05257..db80b960 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = trace-ir prio-heap plugin graph lib_LTLIBRARIES = libbabeltrace2.la libbabeltrace2_la_SOURCES = \ + assert-post.h \ assert-pre.h \ babeltrace2.c \ lib-logging.c \ diff --git a/src/lib/assert-post.h b/src/lib/assert-post.h new file mode 100644 index 00000000..3e1a25d7 --- /dev/null +++ b/src/lib/assert-post.h @@ -0,0 +1,115 @@ +#ifndef BABELTRACE_ASSERT_POST_INTERNAL_H +#define BABELTRACE_ASSERT_POST_INTERNAL_H + +/* + * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2019 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * The macros in this header use macros defined in "lib/logging.h". + * We don't want this header to automatically include + * "lib/logging.h" because you need to manually define BT_LOG_TAG + * before including "lib/logging.h" and it is unexpected that you + * also need to define it before including this header. + * + * This is a reminder that in order to use "lib/assert-post.h", you also + * need to use logging explicitly. + */ + +#ifndef BT_LIB_LOG_SUPPORTED +# error Include "lib/logging.h" before this header. +#endif + +#include +#include +#include "common/macros.h" + +#ifdef BT_DEV_MODE +/* + * Prints the details of an unsatisfied postcondition without + * immediately aborting. You should use this within a function which + * checks postconditions, but which is called from a BT_ASSERT_POST() + * context, so that the function can still return its result for + * BT_ASSERT_POST() to evaluate it. + * + * Example: + * + * BT_ASSERT_POST_FUNC + * static inline bool check_complex_postcond(...) + * { + * ... + * + * if (...) { + * BT_ASSERT_POST_MSG("Unexpected status: ...", ...); + * return false; + * } + * + * ... + * } + * + * ... + * + * BT_ASSERT_POST(check_complex_postcond(...), + * "Postcondition is not satisfied: ...", ...); + */ +# define BT_ASSERT_POST_MSG(_fmt, ...) \ + do { \ + bt_lib_log(_BT_LOG_SRCLOC_FUNCTION, __FILE__, \ + __LINE__, BT_LOG_FATAL, BT_LOG_TAG, \ + (_fmt), ##__VA_ARGS__); \ + } while (0) + +/* + * Developer mode: asserts that the library postcondition `_cond` is + * satisfied. + * + * If `_cond` is false, log a fatal statement using `_fmt` and the + * optional arguments (same usage as BT_LIB_LOGF()), and abort. + * + * To assert that a library precondition is satisfied (parameters from + * the user), use BT_ASSERT_PRE(). + * + * To assert that an internal postcondition is satisfied, use + * BT_ASSERT(). + */ +# define BT_ASSERT_POST(_cond, _fmt, ...) \ + do { \ + if (!(_cond)) { \ + BT_ASSERT_POST_MSG("Babeltrace 2 library postcondition not satisfied; error is:"); \ + BT_ASSERT_POST_MSG((_fmt), ##__VA_ARGS__); \ + BT_ASSERT_POST_MSG("Aborting..."); \ + abort(); \ + } \ + } while (0) + +/* + * Marks a function as being only used within a BT_ASSERT_POST() + * context. + */ +# define BT_ASSERT_POST_FUNC +#else +# define BT_ASSERT_POST(_cond, _fmt, ...) ((void) sizeof((void) (_cond), 0)) +# define BT_ASSERT_POST_FUNC __attribute__((unused)) +# define BT_ASSERT_POST_MSG(_fmt, ...) +#endif /* BT_DEV_MODE */ + +#endif /* BABELTRACE_ASSERT_POST_INTERNAL_H */ diff --git a/src/lib/assert-pre.h b/src/lib/assert-pre.h index 48fe9598..2aae8f79 100644 --- a/src/lib/assert-pre.h +++ b/src/lib/assert-pre.h @@ -79,13 +79,17 @@ } while (0) /* - * Asserts that the library precondition _cond is satisfied. + * Developer mode: asserts that the library precondition `_cond` is + * satisfied. * * If `_cond` is false, log a fatal statement using `_fmt` and the * optional arguments (same usage as BT_LIB_LOGF()), and abort. * - * To assert that a postcondition is satisfied or that some internal - * object/context/value is in the expected state, use BT_ASSERT(). + * To assert that a library postcondition is satisfied (return from user + * code), use BT_ASSERT_POST(). + * + * To assert that an internal postcondition is satisfied, use + * BT_ASSERT(). */ # define BT_ASSERT_PRE(_cond, _fmt, ...) \ do { \ @@ -108,21 +112,24 @@ #endif /* BT_DEV_MODE */ /* - * Developer mode: asserts that a given variable is not NULL. + * Developer mode: asserts that a given variable `_obj` named + * `_obj_name` (capitalized) is not `NULL`. */ #define BT_ASSERT_PRE_NON_NULL(_obj, _obj_name) \ BT_ASSERT_PRE((_obj) != NULL, "%s is NULL: ", _obj_name) /* - * Developer mode: asserts that a given object is NOT frozen. This macro - * checks the `frozen` field of _obj. + * Developer mode: asserts that a given object `_obj` named `_obj_name` + * (capitalized) is NOT frozen. This macro checks the `frozen` field of + * `_obj`. */ #define BT_ASSERT_PRE_HOT(_obj, _obj_name, _fmt, ...) \ BT_ASSERT_PRE(!(_obj)->frozen, "%s is frozen" _fmt, _obj_name, \ ##__VA_ARGS__) /* - * Developer mode: asserts that a given index is less than a given size. + * Developer mode: asserts that a given index `_index` is less than a + * given length `_length`. */ #define BT_ASSERT_PRE_VALID_INDEX(_index, _length) \ BT_ASSERT_PRE((_index) < (_length), \ -- 2.34.1