Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/assert: check assert at compile time, if possible #17390

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion boards/lora-e5-dev/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@

void board_init(void)
{
if(IS_ACTIVE(CONFIG_LORA_E5_DEV_ENABLE_3P3V)) {

Check warning on line 33 in boards/lora-e5-dev/board.c

View workflow job for this annotation

GitHub Actions / static-tests

keyword 'if' not followed by a single space
gpio_init(LORA_E5_DEV_3P3V_ENABLE_PIN, GPIO_OUT);
gpio_set(LORA_E5_DEV_3P3V_ENABLE_PIN);
}

if(IS_ACTIVE(CONFIG_LORA_E5_DEV_ENABLE_5V)) {

Check warning on line 38 in boards/lora-e5-dev/board.c

View workflow job for this annotation

GitHub Actions / static-tests

keyword 'if' not followed by a single space
gpio_init(LORA_E5_DEV_5V_ENABLE_PIN, GPIO_OUT);
gpio_set(LORA_E5_DEV_5V_ENABLE_PIN);
}
Expand Down Expand Up @@ -68,7 +68,7 @@
break;
default:
/* SX126X_RF_MODE_TX_LPA is not supported */
assert(0);
assert_unreachable();
break;
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/lib/assert.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include "backtrace.h"
#endif

__NORETURN void _assert_failure(const char *file, unsigned line)
__NORETURN void _assert_panic_verbose(const char *file, unsigned line)
{
printf("%s:%u => ", file, line);
#if IS_USED(MODULE_BACKTRACE)
Expand All @@ -37,7 +37,7 @@ __NORETURN void _assert_failure(const char *file, unsigned line)
core_panic(PANIC_ASSERT_FAIL, "FAILED ASSERTION.");
}

__NORETURN void _assert_panic(void)
__NORETURN void _assert_panic_concise(void)
{
printf("%" PRIxTXTPTR "\n", cpu_get_caller_pc());
#if IS_USED(MODULE_BACKTRACE)
Expand Down
149 changes: 105 additions & 44 deletions core/lib/include/assert.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,44 +58,23 @@
* 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

/**
* @def __NORETURN
* @brief hidden (__) NORETURN definition
* @internal
* @brief abort the program if assertion is false
*
* Duplicating the definitions of kernel_defines.h as these are unsuitable for
* system header files like the assert.h.
* kernel_defines.h would define symbols that are not reserved.
*/
#ifndef __NORETURN
#ifdef __GNUC__
#define __NORETURN __attribute__((noreturn))
#else /*__GNUC__*/
#define __NORETURN
#endif /*__GNUC__*/
#endif /*__NORETURN*/

#ifdef NDEBUG
#define assert(ignore)((void)0)
#elif defined(DEBUG_ASSERT_VERBOSE)
/**
* @brief Function to handle failed assertion
* @warning Do not use `assert(0);` to assert that a line of code is
* unreachable, @ref assert_unreachable instead.
*
* @note This function was introduced for memory size optimization
* @note This implementation has a special twist: It will fail at link time
* if the condition can be proven to be never true at compile time.
* If linking fails due to the symbol
* `__assertion_is_known_to_fail_at_compile_time` being undefined,
* an assertion has been proven to always blow by the optimizer.
*
* @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);
/**
* @brief abort the program if assertion is false
* @note Further note that when packages include this header, the check
* will always be performed at runtime, as replacing all
* `assert(0);` in packages with `assert_unreachable();` are not
* maintainable.
*
* If the macro NDEBUG was defined at the moment <assert.h> was last included,
* the macro assert() generates no code, and hence does nothing at all.
Expand Down Expand Up @@ -134,27 +113,109 @@
*
* @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 */
__NORETURN void _assert_panic(void);
#define assert(cond) (_likely(cond) ? (void)0 : _assert_panic())
#endif /* DEBUG_ASSERT_VERBOSE */
# define assert(cond) /* implementation */

/**
* @brief abort the program if this line is reached, unless `NDEBUG` is
* defined
*/
# define assert_unreachable() /* implementation */
#else
/* we should not include custom headers in standard headers */
# define _likely(x) __builtin_expect((uintptr_t)(x), 1)
#endif

/**
* @def __NORETURN
* @brief hidden (__) NORETURN definition
* @internal
*
* Duplicating the definitions of kernel_defines.h as these are unsuitable for
* system header files like the assert.h.
* kernel_defines.h would define symbols that are not reserved.
*/
#ifndef __NORETURN
# ifdef __GNUC__
# define __NORETURN __attribute__((noreturn))
# else /*__GNUC__*/
# define __NORETURN
# endif /*__GNUC__*/
#endif /*__NORETURN*/

/**
* @brief Function to report a failed assertion - verbose variant
*
* @warning This function is internal and should not be used by downstream code.
*
* @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_panic_verbose(const char *file, unsigned line);

/**
* @brief Concise version of reporting a blown assertion
*
* @warning This function is internal and should not be used by downstream code.
*
* This is an alternative to @ref _assert_panic_verbose that doesn't require
* the caller to spent memory in `.rodata` for a file name and a line number.
*/
__NORETURN void _assert_panic_concise(void);

#ifdef NDEBUG
# define assert(ignore) ((void)0)
# define assert_unreachable() UNREACHABLE()
#else
# if DEBUG_ASSERT_VERBOSE

Check failure on line 173 in core/lib/include/assert.h

View workflow job for this annotation

GitHub Actions / static-tests

preprocessing issue while doing constant expression evaluation: syntax error: input=' '
# define _assert_panic(file, line) _assert_panic_verbose(file, line)
# else
# define _assert_panic(file, line) _assert_panic_concise()

Check failure on line 176 in core/lib/include/assert.h

View workflow job for this annotation

GitHub Actions / static-tests

Member _assert_panic(file, line) (macro definition) of file assert.h is not documented.
# endif
# if COMPILING_RIOT_PKG_CODE
# define assert(cond) \
(_likely(cond) ? (void)0 : _assert_panic(__FILE__, __LINE__))
# else
# define assert(cond) \
do { \
if (__builtin_constant_p(cond)) { \
if (!(cond)) { \
extern void __assertion_is_known_to_fail_at_compile_time(void); \
__assertion_is_known_to_fail_at_compile_time(); \
} \
} \
else { \
if (!(_likely(cond))) { \
_assert_panic(__FILE__, __LINE__); \
} \
} \
} \
while (0)
# endif
# define assert_unreachable() \
do { \
_assert_panic(__FILE__, __LINE__); \
} while (0)
#endif

#if !defined __cplusplus
#if __STDC_VERSION__ >= 201112L
# if __STDC_VERSION__ >= 201112L
/**
* @brief c11 static_assert() macro
*/
#define static_assert(...) _Static_assert(__VA_ARGS__)
#else
# 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
# define static_assert(cond, ...) \
{ enum { static_assert_failed_on_div_by_0 = 1 / (!!(cond)) }; }
# endif
#endif

#ifdef __cplusplus
Expand Down
2 changes: 1 addition & 1 deletion cpu/atmega_common/periph/rtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ static inline uint8_t _rtt_div(uint16_t freq)
case 256: return 0x5;
case 128: return 0x6;
case 32: return 0x7;
default: assert(0);
default: assert_unreachable();
return 0;
}
}
Expand Down
6 changes: 3 additions & 3 deletions cpu/cc2538/radio/cc2538_rf_radio_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
RFCORE_XREG_CSPY = cc2538_min_be; /* Holds MinBE */

assert(cc2538_csma_ca_retries >= 0);
RFCORE_XREG_CSPZ = cc2538_csma_ca_retries + 1; /* Holds CSMA-CA attempts (retries + 1) */

Check warning on line 157 in cpu/cc2538/radio/cc2538_rf_radio_ops.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters

RFCORE_XREG_CSPCTRL &= ~CC2538_CSP_MCU_CTRL_MASK;

Expand Down Expand Up @@ -287,7 +287,7 @@
/* The upper layer shouldn't call this function if the RX_DONE event was
* not triggered */
if (!(RFCORE_XREG_RXFIFOCNT > 0)) {
assert(false);
assert_unreachable();
}

pkt_len = rfcore_read_byte() - IEEE802154_FCS_LEN;
Expand Down Expand Up @@ -391,7 +391,7 @@

if ((flags_f0 & SFD)) {
handled_f0 |= SFD;
switch(cc2538_state) {

Check warning on line 394 in cpu/cc2538/radio/cc2538_rf_radio_ops.c

View workflow job for this annotation

GitHub Actions / static-tests

keyword 'switch' not followed by a single space
case CC2538_STATE_READY:
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_RX_START);
break;
Expand All @@ -406,7 +406,7 @@
default:
/* This should never happen */
DEBUG("ERROR: cc2538_state: %i\n", cc2538_state);
assert(false);
assert_unreachable();
}
}

Expand Down Expand Up @@ -464,7 +464,7 @@
default:
/* This should never happen */
DEBUG("ERROR: cc2538_state: %i\n", cc2538_state);
assert(false);
assert_unreachable();
break;
}
}
Expand All @@ -485,7 +485,7 @@
const network_uint16_t *short_addr = value;
const eui64_t *ext_addr = value;
const uint16_t *pan_id = value;
switch(cmd) {

Check warning on line 488 in cpu/cc2538/radio/cc2538_rf_radio_ops.c

View workflow job for this annotation

GitHub Actions / static-tests

keyword 'switch' not followed by a single space
case IEEE802154_AF_SHORT_ADDR:
RFCORE_FFSM_SHORT_ADDR0 = short_addr->u8[1];
RFCORE_FFSM_SHORT_ADDR1 = short_addr->u8[0];
Expand All @@ -511,10 +511,10 @@
return 0;
}

static int _config_src_addr_match(ieee802154_dev_t *dev, ieee802154_src_match_t cmd, const void *value)

Check warning on line 514 in cpu/cc2538/radio/cc2538_rf_radio_ops.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
{
(void) dev;
switch(cmd) {

Check warning on line 517 in cpu/cc2538/radio/cc2538_rf_radio_ops.c

View workflow job for this annotation

GitHub Actions / static-tests

keyword 'switch' not followed by a single space
case IEEE802154_SRC_MATCH_EN:
RFCORE_XREG_FRMCTRL1 &= ~CC2538_FRMCTRL1_PENDING_OR_MASK;
if (*((const bool*) value) == true) {
Expand Down
10 changes: 5 additions & 5 deletions cpu/esp32/esp-ble-nimble/esp_ble_nimble.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static int _esp_hci_h4_frame_cb(uint8_t pkt_type, void *data)
rc = ble_transport_to_hs_evt(data);
break;
default:
assert(0);
assert_unreachable();
break;
}

Expand All @@ -202,24 +202,24 @@ void esp_ble_nimble_init(void)
LOG_TAG_ERROR(LOG_TAG,
"Bluetooth controller release classic bt memory failed: %s",
esp_err_to_name(ret));
assert(0);
assert_unreachable();
}
*/

/* init and enable the Bluetooth LE controller */
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
LOG_TAG_ERROR(LOG_TAG, "Bluetooth controller initialize failed: %d", ret);
assert(0);
assert_unreachable();
}

if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) {
LOG_TAG_ERROR(LOG_TAG, "Bluetooth controller enable failed: %d", ret);
assert(0);
assert_unreachable();
}

/* register callbacks from Bluetooth LE controller */
if ((ret = esp_vhci_host_register_callback(&vhci_host_cb)) != ESP_OK) {
assert(0);
assert_unreachable();
}

/* init HCI H4 processing */
Expand Down
2 changes: 1 addition & 1 deletion cpu/esp32/periph/can.c
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ static void _esp_can_power_up(can_t *dev)
* pending interrupts cleared */

if (!twai_hal_init(&hw)) {
assert(false);
assert_unreachable();
}

/* set bittiming from parameters as given in device data */
Expand Down
4 changes: 2 additions & 2 deletions cpu/esp32/periph/i2c_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ void i2c_init(i2c_t dev)
i2c_config[dev].scl, i2c_config[dev].sda,
gpio_get_pin_usage_str(i2c_config[dev].scl),
gpio_get_pin_usage_str(i2c_config[dev].sda));
assert(0);
assert_unreachable();
}

_i2c_bus[dev].cmd = 0;
Expand Down Expand Up @@ -169,7 +169,7 @@ void i2c_init(i2c_t dev)
break;
default:
LOG_TAG_ERROR("i2c", "Invalid speed value in %s\n", __func__);
assert(0);
assert_unreachable();
}

_i2c_bus[dev].clk_freq = cfg.master.clk_speed;
Expand Down
4 changes: 2 additions & 2 deletions cpu/esp32/periph/sdmmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,11 @@ static void _init(sdmmc_dev_t *sdmmc_dev)

if ((res = sdmmc_host_init())) {
LOG_ERROR("[sdmmc] Could not initialize SDMMC host controller\n");
assert(false);
assert_unreachable();
}
if ((res = sdmmc_host_init_slot(dev->config->slot, &slot_config))) {
LOG_ERROR("[sdmmc] Could not initialize SDMMC slot\n");
assert(false);
assert_unreachable();
}

if (gpio_is_valid(conf->cd)) {
Expand Down
4 changes: 2 additions & 2 deletions cpu/esp32/periph/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@
LOG_TAG_ERROR("spi",
"SPI_DEV(%d) CS signal could not be initialized\n",
bus);
assert(0);
assert_unreachable();
}

/* lock the bus */
Expand All @@ -286,7 +286,7 @@
/*
* set SPI mode
* see ESP32 Technical Reference, Section 7.4.1, Table 27
* https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf

Check warning on line 289 in cpu/esp32/periph/spi.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
*/

/* hardware CS not used (TODO) */
Expand All @@ -302,7 +302,7 @@
/*
* set SPI clock
* see ESP32 Technical Reference, Section 7.8 SPI_CLOCK_REG
* https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf

Check warning on line 305 in cpu/esp32/periph/spi.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
*/

/* check whether timing has to be recalculated (time consuming) */
Expand All @@ -314,7 +314,7 @@
LOG_TAG_ERROR("spi", "APB clock rate (%"PRIu32" Hz) has to be at "
"least 5 times SPI clock rate (%d Hz)\n",
apb_clk, clk);
assert(false);
assert_unreachable();
}

/* duty cycle is measured in is 1/256th, 50% = 128 */
Expand Down
2 changes: 1 addition & 1 deletion cpu/esp8266/periph/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@
LOG_TAG_ERROR("spi",
"SPI_DEV(%d) CS signal could not be initialized\n",
bus);
assert(0);
assert_unreachable();
}

/* lock the bus */
Expand All @@ -259,7 +259,7 @@

/* set SPI clock
* see ESP8266 Technical Reference Appendix 2 - SPI registers
* https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf

Check warning on line 262 in cpu/esp8266/periph/spi.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
*/

uint32_t spi_clkdiv_pre; /* 13 bit */
Expand Down
16 changes: 8 additions & 8 deletions cpu/esp8266/vendor/esp-idf/esp8266/source/startup.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,26 +60,26 @@ static void user_init_entry(void *param)
#endif

if (nvs_flash_init() != 0) {
assert(0);
assert_unreachable();
}
if (wifi_nvs_init() != 0) {
assert(0);
assert_unreachable();
}
if (esp_rtc_init() != 0) {
assert(0);
assert_unreachable();
}
if (mac_init() != 0) {
assert(0);
assert_unreachable();
}
if (base_gpio_init() != 0) {
assert(0);
assert_unreachable();
};

esp_phy_load_cal_and_init(0);

#ifdef MODULE_ESP_WIFI_ANY
if (wifi_timer_init() != 0) {
assert(0);
assert_unreachable();
}
#endif

Expand All @@ -95,7 +95,7 @@ static void user_init_entry(void *param)

#ifdef CONFIG_ENABLE_PTHREAD
if (esp_pthread_init() != 0) {
assert(0);
assert_unreachable();
}
#endif

Expand Down Expand Up @@ -163,7 +163,7 @@ void call_user_start(size_t start_addr)
wifi_os_init();

if (wifi_task_create(user_init_entry, "uiT", CONFIG_MAIN_TASK_STACK_SIZE, NULL, wifi_task_get_max_priority()) == NULL) {
assert(0);
assert_unreachable();
}

wifi_os_start();
Expand Down
Loading
Loading