Skip to content
Merged
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
61 changes: 60 additions & 1 deletion .github/workflows/cpp-car.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,67 @@ jobs:
run: ./scripts/run_clang_tidy.sh
working-directory: car

ubsan:
needs: build-docker
permissions:
contents: read
actions: read

runs-on: ubuntu-latest

strategy:
matrix:
include:
- name: telemetry
path: car/components/telemetry/test_apps
pytest_pattern: pytest_telemetry_qemu.py
- name: web_server
path: car/components/web_server/test_apps
pytest_pattern: pytest_web_server_qemu.py

container:
image: ghcr.io/ltowarek/dust-mite-cpp-devcontainer
options: --user root
credentials:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

defaults:
run:
shell: bash

steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Cache ccache
uses: actions/cache@v5
with:
path: ${{ github.workspace }}/.ccache
key: ccache-${{ runner.os }}-idf-ubsan-${{ matrix.name }}-${{ github.run_id }}
restore-keys: |
ccache-${{ runner.os }}-idf-ubsan-${{ matrix.name }}-
ccache-${{ runner.os }}-idf-ubsan-

- name: Build
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
SDKCONFIG_DEFAULTS: sdkconfig.defaults;sdkconfig.defaults.qemu;sdkconfig.defaults.ubsan
run: |
source $IDF_PATH/export.sh
idf.py build
working-directory: ${{ matrix.path }}

- name: Run QEMU tests
run: |
source $IDF_PATH/export.sh
pytest ${{ matrix.pytest_pattern }} --embedded-services idf,qemu -v
working-directory: ${{ matrix.path }}

ci-status-cpp-car:
needs: [build-docker, build, clang-format, clang-tidy]
needs: [build-docker, build, clang-format, clang-tidy, ubsan]
if: always()
runs-on: ubuntu-latest
steps:
Expand Down
23 changes: 23 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,29 @@ tolerates that link failure and only requires `compile_commands.json` to be gene
`clang-tidy` CI job is blocking (part of `ci-status-cpp-car`); since `WarningsAsErrors` is
empty, it only fails on a genuine clang-tidy tool error, not on findings.

#### UndefinedBehaviorSanitizer (UBSan)

A QEMU test app can opt in to building its component under test with
[UndefinedBehaviorSanitizer](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/fatal-errors.html#undefined-behavior-sanitizer-ubsan-checks).
Enable it by adding a `CONFIG_<COMPONENT>_TEST_UBSAN` Kconfig boolean (default `n`) to the test
app's `main/Kconfig.projbuild`, a matching `sdkconfig.defaults.ubsan` overlay that sets it to
`y`, and guarding the sanitizer flags in the test app's `CMakeLists.txt`:

```cmake
if(CONFIG_<COMPONENT>_TEST_UBSAN)
idf_component_get_property(<component>_lib <component> COMPONENT_LIB)
target_compile_options(${<component>_lib} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")
endif()
```

Scoping the flags to just the component under test (rather than the whole app) follows ESP-IDF's
documented pattern — enabling UBSan project-wide grows code/data size too much to fit on-target,
which is also why it is never enabled for the production firmware build. A dedicated `ubsan` CI
job builds and runs each opted-in test app with `sdkconfig.defaults.ubsan` layered on top of
`sdkconfig.defaults.qemu`, using its own matrix (separate from the `build` job's matrix) so the
default test apps keep building without the sanitizer. The `ubsan` CI job is blocking (part of
`ci-status-cpp-car`).

### Car test types

Test scope and execution environment are independent choices. Scope determines what is under test; environment determines where it runs.
Expand Down
10 changes: 9 additions & 1 deletion car/components/telemetry/test_apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,12 @@ set(EXTRA_COMPONENT_DIRS "../.." "../../DFRobot_AXP313A/DFRobot_AXP313A/esp_idf"
set(COMPONENTS main)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(telemetry_test)
project(telemetry_test)

# Opt-in via CONFIG_TELEMETRY_TEST_UBSAN (see CONTRIBUTING.md); scoped to the
# component under test since enabling UBSan project-wide grows code/data size
# too much to fit on-target.
if(CONFIG_TELEMETRY_TEST_UBSAN)
idf_component_get_property(telemetry_lib telemetry COMPONENT_LIB)
target_compile_options(${telemetry_lib} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")
endif()
8 changes: 8 additions & 0 deletions car/components/telemetry/test_apps/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,12 @@ config TELEMETRY_TEST_QEMU_MODE
binary runs under QEMU. Hardware-dependent test cases report
TEST_IGNORE instead of crashing on missing peripherals.

config TELEMETRY_TEST_UBSAN
bool "Build telemetry with UndefinedBehaviorSanitizer"
default n
help
Compiles the telemetry component under test with -fsanitize=undefined.
Opt-in: not part of the default build, only enabled by the dedicated
UBSan CI job/sdkconfig overlay.

endmenu
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_TELEMETRY_TEST_UBSAN=y
8 changes: 8 additions & 0 deletions car/components/web_server/test_apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,11 @@ set(EXTRA_COMPONENT_DIRS "../.." "../../DFRobot_AXP313A/DFRobot_AXP313A/esp_idf"
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(web_server_test)

# Opt-in via CONFIG_WEB_SERVER_TEST_UBSAN (see CONTRIBUTING.md); scoped to the
# component under test since enabling UBSan project-wide grows code/data size
# too much to fit on-target.
if(CONFIG_WEB_SERVER_TEST_UBSAN)
idf_component_get_property(web_server_lib web_server COMPONENT_LIB)
target_compile_options(${web_server_lib} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")
endif()
8 changes: 8 additions & 0 deletions car/components/web_server/test_apps/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,12 @@ config WEB_SERVER_TEST_QEMU_MODE
test binary runs under QEMU. Hardware-dependent test cases report
TEST_IGNORE instead of blocking on missing peripherals.

config WEB_SERVER_TEST_UBSAN
bool "Build web_server with UndefinedBehaviorSanitizer"
default n
help
Compiles the web_server component under test with -fsanitize=undefined.
Opt-in: not part of the default build, only enabled by the dedicated
UBSan CI job/sdkconfig overlay.

endmenu
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_WEB_SERVER_TEST_UBSAN=y
Loading