From 608328979d1cc8934b7f810f85fb703ac22c8e1d Mon Sep 17 00:00:00 2001 From: Tenone Date: Wed, 21 Oct 2026 02:29:20 +0800 Subject: [PATCH] fix(zkernel): make runtime assertions configurable Add CONFIG_ASSERT with a default of n. Disabled assertions do not evaluate their arguments. Include esp_rom_sys.h directly and suppress the unused timer result warning when assertions are disabled. Add regression tests, configuration documentation, and CI coverage for both settings. Fixes #33 --- .github/workflows/ci.yml | 4 ++ components/zkernel/Kconfig | 9 ++++ components/zkernel/README.md | 11 +++++ .../zkernel/include/boreas/zephyr/kernel.h | 1 + .../include/boreas/zephyr/sys/__assert.h | 13 ++++- components/zkernel/src/k_timer.c | 1 + test/main/CMakeLists.txt | 1 + test/main/test_assert.c | 49 +++++++++++++++++++ test/main/test_main.c | 2 + 9 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 test/main/test_assert.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a303a7d..d41b8d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,7 @@ jobs: fail-fast: false matrix: idf: ["v5.4", "v5.5"] + assertions: ["y", "n"] runs-on: ubuntu-latest container: image: espressif/idf:${{ matrix.idf }} @@ -38,6 +39,7 @@ jobs: run: | . /opt/esp/idf/export.sh cd test + echo "CONFIG_ASSERT=${{ matrix.assertions }}" >> sdkconfig.defaults idf.py --preview set-target linux idf.py build ./build/boreas_test.elf @@ -47,6 +49,7 @@ jobs: fail-fast: false matrix: idf: ["v5.4", "v5.5"] + assertions: ["y", "n"] runs-on: ubuntu-latest container: image: espressif/idf:${{ matrix.idf }} @@ -59,6 +62,7 @@ jobs: run: | . /opt/esp/idf/export.sh cd test + echo "CONFIG_ASSERT=${{ matrix.assertions }}" >> sdkconfig.defaults idf.py set-target esp32s3 idf.py build diff --git a/components/zkernel/Kconfig b/components/zkernel/Kconfig index ed1b15c..6922b5e 100644 --- a/components/zkernel/Kconfig +++ b/components/zkernel/Kconfig @@ -1,5 +1,14 @@ menu "Boreas Kernel (zkernel)" + config ASSERT + bool "Enable runtime assertions" + default n + help + Enable __ASSERT and __ASSERT_NO_MSG checks that log and abort + on failure. Disabled assertions do not evaluate their arguments; + do not put required side effects in assertion expressions. + Mirrors upstream Zephyr's CONFIG_ASSERT default. + config RING_BUFFER_LARGE bool "Use 32-bit ring buffer indices" default n diff --git a/components/zkernel/README.md b/components/zkernel/README.md index b99900d..a729afc 100644 --- a/components/zkernel/README.md +++ b/components/zkernel/README.md @@ -315,3 +315,14 @@ index 0 stays free for ESP-IDF internals. A compile-time `#error` backstops the requirement (Kconfig cannot set another component's int symbol automatically: `select` is bool-only and cross-component int defaults lose the parse-order race). + +### Runtime assertions + +`CONFIG_ASSERT` controls `__ASSERT` and `__ASSERT_NO_MSG`. +It defaults to `n`, matching Zephyr. + +Set `CONFIG_ASSERT=y` to enable checks that log and abort on failure. +When disabled, neither the condition nor the message is evaluated. +Required operations must therefore stay outside assertion expressions. + +`BUILD_ASSERT`, `K_ASSERT`, and `k_panic()` are unaffected. diff --git a/components/zkernel/include/boreas/zephyr/kernel.h b/components/zkernel/include/boreas/zephyr/kernel.h index 60b23a6..3df1a3b 100644 --- a/components/zkernel/include/boreas/zephyr/kernel.h +++ b/components/zkernel/include/boreas/zephyr/kernel.h @@ -24,6 +24,7 @@ #include "freertos/semphr.h" #include "freertos/task.h" +#include "esp_rom_sys.h" #include "esp_timer.h" #if CONFIG_IDF_TARGET_LINUX diff --git a/components/zkernel/include/boreas/zephyr/sys/__assert.h b/components/zkernel/include/boreas/zephyr/sys/__assert.h index bade260..f9a0dbc 100644 --- a/components/zkernel/include/boreas/zephyr/sys/__assert.h +++ b/components/zkernel/include/boreas/zephyr/sys/__assert.h @@ -5,8 +5,8 @@ * Zephyr-compatible runtime assertions (upstream * spellings). * - * Divergence: upstream compiles these out unless CONFIG_ASSERT=y - * (default n); Boreas keeps them always on -- they log and abort. + * Enabled by CONFIG_ASSERT (default n), matching upstream Zephyr. + * Disabled assertions do not evaluate the condition or message. * NOT safe from IRAM ISR context (ESP_LOGE + abort are flash-resident). * Use k_panic() (sys/util.h) for unrecoverable errors in ISR/IRAM * context. @@ -14,7 +14,10 @@ #pragma once +#include "sdkconfig.h" + #ifndef __ASSERT +#if defined(CONFIG_ASSERT) && CONFIG_ASSERT #include /* abort() */ #include "esp_log.h" @@ -25,6 +28,12 @@ abort(); \ } \ } while (0) +#else + +#define __ASSERT(cond, msg) \ + do { \ + } while (0) +#endif #endif /* Assertion with no message (upstream spelling). */ diff --git a/components/zkernel/src/k_timer.c b/components/zkernel/src/k_timer.c index 1f858d8..aa4f98a 100644 --- a/components/zkernel/src/k_timer.c +++ b/components/zkernel/src/k_timer.c @@ -74,6 +74,7 @@ void k_timer_init(struct k_timer *timer, k_timer_expiry_t expiry_fn, k_timer_sto }; esp_err_t err = esp_timer_create(&args, &timer->handle); __ASSERT(err == ESP_OK, "k_timer_init: esp_timer_create failed"); + (void)err; } void k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period) diff --git a/test/main/CMakeLists.txt b/test/main/CMakeLists.txt index b04800e..816f9ec 100644 --- a/test/main/CMakeLists.txt +++ b/test/main/CMakeLists.txt @@ -1,4 +1,5 @@ set(test_srcs + "test_assert.c" "test_main.c" "test_timeout.c" "test_slist.c" diff --git a/test/main/test_assert.c b/test/main/test_assert.c new file mode 100644 index 0000000..3a303c3 --- /dev/null +++ b/test/main/test_assert.c @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2026 Intercreate + */ + +#include "unity.h" +#include "zephyr/sys/__assert.h" + +static void test_assert_disabled_arguments(void) +{ +#if !defined(CONFIG_ASSERT) || !CONFIG_ASSERT + int condition_calls = 0; + int message_calls = 0; + + __ASSERT(++condition_calls, (++message_calls, "disabled assertion")); + __ASSERT_NO_MSG(++condition_calls); + + TEST_ASSERT_EQUAL_INT(0, condition_calls); + TEST_ASSERT_EQUAL_INT(0, message_calls); + + /* A false condition must not terminate the program when disabled. */ + __ASSERT(0, "must not abort"); + __ASSERT_NO_MSG(0); +#else + TEST_IGNORE_MESSAGE("Requires CONFIG_ASSERT=n"); +#endif +} + +static void test_assert_enabled_arguments(void) +{ +#if defined(CONFIG_ASSERT) && CONFIG_ASSERT + int condition_calls = 0; + int message_calls = 0; + + __ASSERT(++condition_calls, (++message_calls, "unused message")); + __ASSERT_NO_MSG(++condition_calls); + + TEST_ASSERT_EQUAL_INT(2, condition_calls); + TEST_ASSERT_EQUAL_INT(0, message_calls); +#else + TEST_IGNORE_MESSAGE("Requires CONFIG_ASSERT=y"); +#endif +} + +void test_assert_group(void) +{ + RUN_TEST(test_assert_disabled_arguments); + RUN_TEST(test_assert_enabled_arguments); +} diff --git a/test/main/test_main.c b/test/main/test_main.c index ab5e7ab..8d1689a 100644 --- a/test/main/test_main.c +++ b/test/main/test_main.c @@ -10,6 +10,7 @@ #include "unity.h" /* Test group declarations -- always available */ +void test_assert_group(void); void test_timeout_group(void); void test_slist_group(void); void test_dlist_group(void); @@ -49,6 +50,7 @@ void app_main(void) UNITY_BEGIN(); /* Layer 0: Foundation */ + test_assert_group(); test_timeout_group(); test_slist_group(); test_dlist_group();