Fixes #61 Object names are exposed as writable pointers throughout the kernel API, which rejects string literals in C++ and lets a caller modify a name an object still holds. Information services return those names through writable double pointers. Create services, control blocks, information services, the module manager and trace registration now preserve const qualification, behind TX_ENABLE_CONST_NAMES. The option defaults to off, so a build that says nothing gets exactly the types it got before. It is opt-in rather than opt-out because it changes the type of a public struct field: application code that copies a name into a writable CHAR * stops compiling, which is a reasonable thing to ask of a minor release and not of a patch one. Issue #780 tracks making it the default in 6.6. Two things the option reaches that its own call sites do not. TX_CHAR_TO_UCHAR_POINTER_CONVERT has exactly two users, both of them reading an object name in _tx_trace_object_register, and every form of that macro but the MISRA one casts the qualifier away without saying so; the conversion is now const in and const out, so nothing launders const to make the build pass. The FreeRTOS adapter holds the name pcTaskGetName retrieves in a TX_NAME_CONST pointer so that it tracks whichever declaration tx_thread_info_get has, and keeps its writable return type through an explicit MISRA C:2012 Rule 11.8 cast, because that signature is part of the FreeRTOS API. Default build: all seven host configurations and all five SMP configurations build with zero warnings and pass -- 113/113 on five host configurations, 100/100 on the two MISRA builds, 118/118 on SMP, 3/3 FreeRTOS. With TX_ENABLE_CONST_NAMES set, the host default and both MISRA configurations, the SMP trace configuration and the FreeRTOS adapter build with zero warnings and pass. Co-authored-by: Tilen Majerle <tilen@majerle.eu> Assisted-by: Codex (gpt-6-astra) <noreply@openai.com> Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
FreeRTOS compatibility layer regression tests
Regression tests for utility/rtos_compatibility_layers/FreeRTOS/tx_freertos.c,
built against the real ThreadX Linux port.
Running them
./scripts/build_freertos.sh
./scripts/test_freertos.sh
Or directly, which is the same thing:
test/freertos/cmake/run.sh build all
test/freertos/cmake/run.sh test all
CI runs both scripts through .github/workflows/regression_test.yml.
What they cover
Every function in the layer that creates an object takes one or two byte pool
allocations for its bookkeeping and then creates one or more ThreadX kernel
objects. When one of those kernel objects cannot be created, the function
returns NULL, or pdFAIL for xTaskCreate(), and the caller is left with no
handle and therefore no way to call the matching delete function. Anything the
layer fails to release on the way out is lost until the system restarts.
That makes these error paths invisible from the outside: a leaking version and a correct version return exactly the same thing to the caller. The suite therefore counts the ThreadX primitives the layer reaches for, and checks that each error path gives back precisely what it took.
| Test | Covers |
|---|---|
txfr_queue_create_test |
xQueueCreate, xQueueCreateStatic, vQueueDelete |
txfr_task_create_test |
xTaskCreate, xTaskCreateStatic |
txfr_sync_create_test |
semaphores, mutexes, event groups and timers |
How the fault injection works
A test asks the harness to fail a chosen kernel creation call, then reads back
how many allocations, releases, object creations and object deletions the layer
performed. The interception is done with the linker's --wrap option, so
tx_freertos.c is compiled exactly as it ships, with no test hooks in it.
Two things are worth knowing before adding tests:
tx_api.hmaps the public API onto the error checking entry points, so the symbols that exist at link time are the_txe_variants, and those are what the wrap list incmake/regression/CMakeLists.txtnames. A--wrapfor a name that does not resolve is silently ignored, so a typo there produces a test that quietly never injects anything.txfr_malloc()andtxfr_free()cannot be wrapped, because they are defined intx_freertos.cand called from within it, so the compiler resolves those calls internally. The byte pool counts stand in for them.
Because --wrap is a GNU ld and lld feature with no MSVC equivalent, this
suite is Linux only. The CMake configuration stops with a clear message rather
than failing later with confusing link errors.
Fixtures
fixtures/FreeRTOSConfig.h configures the layer for the tests. Two of its
settings are not arbitrary:
configASSERT()andTX_FREERTOS_ASSERT_FAIL()are empty, since the tests drive error paths deliberately and neither may halt the run.portDISABLE_INTERRUPTS()andportENABLE_INTERRUPTS()are defined up front.FreeRTOS.hpicks those by compiler rather than by target, so a GNU build otherwise resolves them to the bare metal__disable_interrupts()intrinsic, which does not exist when the layer is hosted on Linux.
fixtures/tx_user.h supplies TX_THREAD_USER_EXTENSION, which the layer
requires, as documented in the layer's own readme.md.
Why the build is 32 bit
The Linux port defines ULONG as unsigned int on x86_64, while the layer
passes pointers through ULONG arguments, such as the task argument and the
timer identifier. A 64 bit build truncates those pointers, which the compiler
reports as -Wpointer-to-int-cast and which crashes the timer callback
wrapper. The ThreadX and SMP suites build 32 bit for their own reasons; this
suite has to.