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
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@
- **`eos_queue_create`:** Size check now uses division so `item_size * capacity` cannot wrap `size_t` on 32-bit targets and overflow the 1024-byte queue store.
- **`eos_sem_create`:** Reject `initial > max` and `max` values that do not fit in `int32_t`, so the counting-semaphore invariant cannot be created already broken.
- **`eos_mutex_lock`:** Recursive lock returns `EOS_KERN_FULL` at `uint8_t` saturation instead of wrapping `rec_count` to 0 and leaving the mutex stuck.
- **`eos_mutex_lock`:** A waiter that times out no longer leaves the mutex owner permanently boosted. Owner priority is recomputed from remaining waiters (or restored to `original_prio`). A full waiter table now returns `EOS_KERN_NO_MEMORY` without applying a boost.
- **`eos_mutex_lock`:** A waiter that times out no longer leaves the mutex owner permanently boosted. The owner's effective priority is recomputed from its base priority and the remaining waiters, so the boost propagates transitively along the blocking chain and is withdrawn when a waiter leaves. A full waiter table returns `EOS_KERN_NO_MEMORY` without applying a boost.
- **`eos_dt_parse`:** Bounds-check the flattened device tree blob before dereferencing it. A malformed DTB could previously read outside the buffer four different ways: `off_struct` past the end of the blob (the `size - off_struct` bound wrapped), a node name with no terminator (unbounded `strlen`), a property name offset outside the strings block, and nesting deeper than the 32-entry node stack. All are now rejected.
- **`eos_dt_find_compatible`:** Search within `prop->len` instead of calling `strstr()` on a property value that is not guaranteed to be NUL-terminated.
- **`eos_dt_get_irq`:** Reject a negative index, and one large enough that `index * 4` overflows, before it is used as an offset.

### Added
- `tests/test_devicetree.c` — device tree parser suite: happy path, malformed-blob rejection, a sweep over every truncation of a valid blob, and a single-byte corruption sweep.
- `tests/fuzz/` is now wired into the build. The directory was never added by any `add_subdirectory`, so no fuzz target could be built. `fuzz_devicetree` is enabled and calls the real `eos_dt_parse()` API — it previously declared a non-existent `eos_dtb_parse()` and was commented out.

## [3.0.1] - 2026-05-16

Expand Down
2 changes: 1 addition & 1 deletion TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Status is one of: `todo`, `in-progress`, `blocked`, `review`, `done`.
| T-002 | Fail CI when no tests are found | backend | reviewer | Added `--no-tests=error`. Against the old broken config `ctest` now exits **8**; against the fixed config it exits **0**. Both verified. |
| T-003 | Make the test build link | architect | reviewer | 7 of 19 targets failed to link (`test_power`, `test_multicore`, `test_net`, `test_ota`, `test_sensor`, `test_filesystem`, `test_motor_ctrl`) — module sources are wrapped in `#if EOS_ENABLE_<MODULE>` and `eos_config.h` defaults each to 0, so with no product profile they compiled to empty translation units. A test `#define`-ing the flag only affects its own TU. Flags now set before the first `add_library()`. Result: build exit 0, **19/19 tests passed**. |
| T-004 | Replace unverifiable README claims | docs | reviewer | Static `Status-Production Ready`, `Build-Passing`, `Coverage-100%` badges replaced with real workflow badges. "100% test coverage" removed — there is no coverage instrumentation in `CMakeLists.txt`, so no figure can be produced. The Zephyr/FreeRTOS/Linux benchmark claim removed — no comparative benchmark exists in this tree. |
| T-009 | Zero-fill newly exposed RAM-filesystem ranges | backend | independent reviewer | Warning-clean focused build and direct filesystem run: **15/15 passed**; the same tests abort on the stale-byte assertion against the old implementation. Generic/RTOS C build passed and Python suites reported **10 passed**. Host CTest launch is unverified because the Windows cross-build emits extensionless PE test paths. The separate write-length overflow is already tracked by PR #95. |
| T-009 | Restore kernel build broken by commit `02c490a` (PR #55) | backend | — | `kernel/src/sync.c` referenced `m->original_prio` (field absent from `mtx_t`), `task_valid`, `g_blocked_on`, `pi_propagate` (all removed) — 9 compile errors; `kernel/src/task.c` had a duplicate `eos_task_set_current_internal` — 1 error. Restored the transitive priority-inheritance machinery from `9a61678`, removed the duplicate definition, re-registered the two kernel tests the commit dropped (`test_task_stats`, `test_tick_overflow`), and repaired the clobbered CHANGELOG. Verified with `zig cc`: `sync.c`/`task.c` compile clean under `-Wall -Wextra`; `test_priority_inherit` 6/6 and `test_kernel` 12/12 pass. |

---

Expand Down
6 changes: 2 additions & 4 deletions kernel/src/sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ int eos_mutex_lock(eos_mutex_handle_t h, uint32_t timeout_ms)
}

/* Refuse rather than block: a task that is not enqueued is never granted
* the mutex, so with EOS_WAIT_FOREVER it would sleep forever. Refusing
* also avoids boosting the owner on behalf of a caller that never waits. */
* the mutex, so with EOS_WAIT_FOREVER it would sleep forever. */
if (g_mtx[h].waiter_count >= MTX_MAX_WAITERS) {
eos_port_exit_critical(crit);
return EOS_KERN_NO_MEMORY;
Expand All @@ -198,8 +197,7 @@ int eos_mutex_lock(eos_mutex_handle_t h, uint32_t timeout_ms)
return EOS_KERN_OK;
}

/* Timeout — leave the queue and drop the boost we were causing, so a
* waiter that gave up no longer keeps the owner running elevated. */
/* Timeout — leave the queue and drop the boost we were causing. */
uint8_t owner = g_mtx[h].owner;
mtx_remove_waiter(&g_mtx[h], caller);
pi_propagate(owner);
Expand Down
Loading