/* * SPDX-FileCopyrightText: 2015 INRIA * SPDX-FileCopyrightText: 2016 Freie Universität Berlin * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once /** * @ingroup core_util * * @{ * @file * @brief POSIX.1-2008 compliant version of the assert macro * * @author Oliver Hahm * @author René Kijewski * @author Martine Lenders */ #include #ifdef __cplusplus extern "C" { #endif #ifdef DOXYGEN /** * @brief Activate verbose output for @ref assert() when defined. * * Without this macro defined, @ref assert() will just print the address of the * code line the assertion failed in. With this macro defined, @ref assert() * will also print the file and the code line of the failed assertion. * * Enabling verbose output will on the other hand lead to an increased size of * the binary, since it needs to contain the names of all files with assertions. * * To define just add it to your `CFLAGS` in your application's Makefile: * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk} * CFLAGS += -DDEBUG_ASSERT_VERBOSE * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ # define DEBUG_ASSERT_VERBOSE /** * @brief Activate breakpoints for @ref assert() when defined * * Without this macro defined the @ref assert() macro will just print some * information about the failed assertion, see @ref assert() and * @ref DEBUG_ASSERT_VERBOSE. * If @ref DEBUG_ASSERT_BREAKPOINT is defined, the execution will stop on a * failed assertion instead of producing the output. If the architecture * defines the macro @ref DEBUG_BREAKPOINT, a breakpoint is inserted and the * execution is stopped directly in the debugger. Otherwise the execution stops * in an endless while loop. */ # define DEBUG_ASSERT_BREAKPOINT #else /* we should not include custom headers in standard headers */ # define _likely(x) __builtin_expect((uintptr_t)(x), 1) #endif #ifndef __NORETURN # if defined(__GNUC__) || defined(DOXYGEN) /** * @brief Same as @ref NORETURN * @internal * * We are not using @ref NORETURN from `compiler_hints.h` here to avoid RIOT * dependencies for standard C headers */ # define __NORETURN __attribute__((noreturn)) # else # define __NORETURN # endif #endif /** * @brief Internal function to trigger a panic with a failed assertion as * identifying cause * @internal * @warning This is an internal function. API changes may happen without regard * for out-of tree uses. * * The implementation will identify the cause of the panic as a blown assertion, * e.g. via a log output. */ __NORETURN void _assert_panic(void); /** * @brief Function to handle failed assertion * * @note This function was introduced for memory size optimization * * @warning this function **NEVER** returns! * * @param[in] file The file name of the file the assertion failed in * @param[in] line The code line of @p file the assertion failed in */ __NORETURN void _assert_failure(const char *file, unsigned line); #ifdef NDEBUG # define assert(ignore)((void)0) #elif defined(DEBUG_ASSERT_VERBOSE) /** * @brief abort the program if assertion is false * * If the macro NDEBUG was defined at the moment was last included, * the macro assert() generates no code, and hence does nothing at all. * * Otherwise, the macro assert() prints an error message to standard error and * terminates the application by calling core_panic(). * * The purpose of this macro is to help programmers find bugs in their * programs. * * A failed assertion generates output similar to: * * 0x89abcdef => FAILED ASSERTION. * * Where 0x89abcdef is an address. This address can be used with tools like * `addr2line` (or e.g. `arm-none-eabi-addr2line` for ARM-based code), `objdump`, * or `gdb` (with the command `info line *(0x89abcdef)`) to identify the line * the assertion failed in. * * With @ref DEBUG_ASSERT_VERBOSE defined this will instead directly print the * file and the line the assertion failed in: * * example/file.c:42 => FAILED ASSERTION. * * If the `backtrace` module is enabled (and implemented for the architecture in use) * a backtrace will be printed in addition to the location of the failed assertion. * * If @ref DEBUG_ASSERT_BREAKPOINT is defined, the execution will stop on a * failed assertion instead of producing the above output. If the architecture * defines the macro @ref DEBUG_BREAKPOINT, a breakpoint is inserted and the * execution is stopped directly in the debugger. Otherwise the execution stops * in an endless while loop. * * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/assert.html */ # define assert(cond) (_likely(cond) ? (void)0 : _assert_failure(__FILE__, __LINE__)) #else /* DEBUG_ASSERT_VERBOSE */ # define assert(cond) (_likely(cond) ? (void)0 : _assert_panic()) #endif /* DEBUG_ASSERT_VERBOSE */ #if !defined __cplusplus # if __STDC_VERSION__ >= 201112L /** * @brief c11 static_assert() macro */ # define static_assert(...) _Static_assert(__VA_ARGS__) # else /** * @brief static_assert for c-version < c11 * * Generates a division by zero compile error when cond is false */ # define static_assert(cond, ...) \ { enum { static_assert_failed_on_div_by_0 = 1 / (!!(cond)) }; } # endif #endif /** * @brief Don't panic on a failed assertion, just halt the running thread. * * If the assertion failed in an interrupt, the system will still panic. */ #ifndef DEBUG_ASSERT_NO_PANIC # define DEBUG_ASSERT_NO_PANIC (1) #endif #ifdef __cplusplus } #endif /** @} */