From cfaf287a2c818b5b358057b3554ae75a3f271e4c Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Sat, 7 Mar 2026 00:01:53 +0100 Subject: [PATCH 1/7] Fix: Give template iterator more unique name In cases where ARRAY_DELETE template is used inside another loop iterators may clash causing internal iterator being initialized by random value rather than intended initialization value. --- include/cmrx/algo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cmrx/algo.h b/include/cmrx/algo.h index 9eb85154..7cc24c36 100644 --- a/include/cmrx/algo.h +++ b/include/cmrx/algo.h @@ -95,9 +95,9 @@ * items rather than allocation size) */ #define ARRAY_DELETE(_ARRAY, _POS, _SIZE) \ - for (unsigned q = _POS + 1; q < _SIZE; ++q)\ + for (unsigned _q = _POS + 1; _q < _SIZE; ++_q)\ {\ - _ARRAY[q - 1] = _ARRAY[q];\ + _ARRAY[_q - 1] = _ARRAY[_q];\ }\ _SIZE--; From ca03b311d7b9e79228aab4ae7b2c80d76e224a0a Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Fri, 6 Mar 2026 20:43:58 +0100 Subject: [PATCH 2/7] Fix: Mute type errors by typecasting key --- include/cmrx/algo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cmrx/algo.h b/include/cmrx/algo.h index 7cc24c36..91bb093b 100644 --- a/include/cmrx/algo.h +++ b/include/cmrx/algo.h @@ -237,7 +237,7 @@ inline uint32_t os_hash_key(uint32_t key) const uint32_t mask = (_MAX) - 1;\ uint32_t pos = hash & mask;\ uint32_t stride = 1;\ - while (_HASHTABLE[pos]._KEY != _VALUE && _HASHTABLE[pos]._KEY != HASH_EMPTY) {\ + while (_HASHTABLE[pos]._KEY != _VALUE && _HASHTABLE[pos]._KEY != (typeof(_HASHTABLE[0]._KEY)) HASH_EMPTY) {\ pos = (pos + stride) & mask;\ stride++;\ }\ From ccc5b29a378ce5291103190f7d67c572ffe8a490 Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Sat, 7 Mar 2026 00:03:14 +0100 Subject: [PATCH 3/7] Improvement: Code after failed assert is unreachable Mark code after failed as unreachable. Improves reasoning of newer versions of clang-tidy which tends to complain about errors in code after assert. --- src/os/arch/arm/cmsis/arch/assert.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/os/arch/arm/cmsis/arch/assert.h b/src/os/arch/arm/cmsis/arch/assert.h index 08b38eb5..a6bb8599 100644 --- a/src/os/arch/arm/cmsis/arch/assert.h +++ b/src/os/arch/arm/cmsis/arch/assert.h @@ -5,6 +5,7 @@ if (!(cond)) \ {\ asm volatile("BKPT 0xFF\n\t");\ + __builtin_unreachable();\ } #else # define ASSERT(cond) From e4217b3ce39008cb958c269f809ad67f41d33813 Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Sat, 7 Mar 2026 01:11:12 +0100 Subject: [PATCH 4/7] Fix: Do not search for non-existent timer If there are no waiters for given notification then don't try to search timers. --- src/os/kernel/notify.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/os/kernel/notify.c b/src/os/kernel/notify.c index b20cf242..99fb6416 100644 --- a/src/os/kernel/notify.c +++ b/src/os/kernel/notify.c @@ -189,7 +189,10 @@ int os_notify_object(const void * object, Event_t event, uint32_t flags) txn_id = os_txn_start(); candidate_waiter = os_find_notified_thread_waiter(object); - candidate_timer = os_find_timer(os_notification_waiters[candidate_waiter], TIMER_TIMEOUT); + if (candidate_waiter < OS_THREADS) + { + candidate_timer = os_find_timer(os_notification_waiters[candidate_waiter], TIMER_TIMEOUT); + } } while (os_txn_commit(txn_id, TXN_READWRITE) != E_OK); if (candidate_waiter < OS_THREADS) From 536bfb34cfa387973b84a20380afee9c35a560c1 Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Sat, 7 Mar 2026 01:12:23 +0100 Subject: [PATCH 5/7] Fix: Do not examine timer if none was given If no existing timer entry was found while timer is configured then don't examine offset given. This was achieved by swapping operands inside if statement, so that if offset given is out of range it won't be used to access array content. --- src/os/kernel/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os/kernel/timer.c b/src/os/kernel/timer.c index f5ef3a4d..0aa3bb7e 100644 --- a/src/os/kernel/timer.c +++ b/src/os/kernel/timer.c @@ -118,7 +118,7 @@ static int do_set_timed_event(Txn_t txn, const unsigned slot, const unsigned int sleeper->interval = interval; sleeper->timer_type = type; - if (sleeper_queue[old_queue_offs].resume_time != next_resume || old_queue_offs == TIMER_INVALID_ID) + if (old_queue_offs == TIMER_INVALID_ID || sleeper_queue[old_queue_offs].resume_time != next_resume) { if (old_queue_offs != TIMER_INVALID_ID) { From f12b0e0d63ac6f5ec65d926cd6bc64298c95ef2e Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Sat, 7 Mar 2026 01:14:03 +0100 Subject: [PATCH 6/7] Cleanup: Mark unreachable path After kernel was shutdown, code flow doesn't continue here. Mutes some static analyzer errors. --- src/os/kernel/sched.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/os/kernel/sched.c b/src/os/kernel/sched.c index f6957a2f..0d86cac4 100644 --- a/src/os/kernel/sched.c +++ b/src/os/kernel/sched.c @@ -624,6 +624,8 @@ uint32_t os_shutdown(void) os_memory_protection_stop(); os_kernel_shutdown(); + + __builtin_unreachable(); } struct OS_thread_t * os_thread_get(Thread_t thread_id) From 8f06f3f14192d45fe9bf5ff5f5afde737db8bc57 Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Wed, 11 Mar 2026 13:40:52 +0100 Subject: [PATCH 7/7] Fix: Remove thread from waitlist on notification timeout If notification times out then remove the waiting thread from notification waitlist. --- src/os/kernel/notify.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/os/kernel/notify.c b/src/os/kernel/notify.c index b20cf242..1a1f8782 100644 --- a/src/os/kernel/notify.c +++ b/src/os/kernel/notify.c @@ -282,6 +282,17 @@ void cb_syscall_notify_object(const void * object, Thread_t thread, int sleeper, case EVT_TIMEOUT: os_set_syscall_return_value(thread, E_TIMEOUT); + for (unsigned q = 0; q < os_notification_waiters_size; ++q) + { + if (os_notification_waiters[q] == thread) + { + ARRAY_DELETE(os_notification_waiters, q, os_notification_waiters_size); + break; + } + } + notified_thread->wait_object = NULL; + notified_thread->wait_callback = NULL; + break; } }