Skip to content

fix: v0.4.0 — RELAY ecosystem audit fixes - #12

Merged
SoundMatt merged 2 commits into
mainfrom
fix/backlog-2026-07
Jul 27, 2026
Merged

fix: v0.4.0 — RELAY ecosystem audit fixes#12
SoundMatt merged 2 commits into
mainfrom
fix/backlog-2026-07

Conversation

@SoundMatt

Copy link
Copy Markdown
Owner

Summary

Fixes all 8 open issues filed by the RELAY ecosystem audit (2026-07-27).

Issues fixed

Spec-conformance:

Bug fixes:

  • [P1] Adapt() subscription thread captures raw this pointer; adapter destruction while the thread runs is a use-after-free #8Adapt()'s subscription thread captured the adapter's this by raw pointer and dereferenced it (++seq_) for the thread's lifetime; nothing joined the detached thread on adapter destruction, so dropping the adapter (while the bus stayed open) was a use-after-free on the next inbound frame. Fixed by moving the seq counter into a shared_ptr<atomic<uint64_t>> captured into the thread instead of this — the thread now never touches the adapter, and as a side effect this also brings seq-counter ownership in line with spec §10.5.2 point 7 (owned per-subscription, not shared across Adapt() calls).
  • [P1] Out-of-range LIN frame ID is signalled as ErrPayloadTooLarge instead of ErrInvalidFrame (spec section 5.3) #6 — Out-of-range LIN frame ID was signalled as ErrPayloadTooLarge instead of a structural-violation error, at 5 call sites (spec §5.3: "ErrInvalidFrame and ErrPayloadTooLarge are distinct ... ValidateFrame MUST NOT return ErrPayloadTooLarge"). Added lin::Errc::invalid_frame (a LIN-specific std::error_category, not mapped to any relay::Errc, matching the CAN ErrInvalidFrame pattern in spec §5.4) and applied it to virtual::Bus::do_publish()/send_header(), master::Node::set_schedule()/run(), and — found during the fix, same mis-mapping, not in the original issue evidence — slave::Node::set_response(). LinAdapter::send() (the relay::INode interface, constrained to the four documented relay sentinels per §10.1) now delegates to the existing from_message() instead of duplicating ID-parsing logic, but still approximates with ErrPayloadTooLarge as the issue itself notes is unavoidable there.

Docs

  • ROADMAP.md was rewritten to reflect what v0.1.0v0.3.0 actually shipped (it still described unshipped v0.2.0/v0.3.0 plans — "Enhanced Bus Features"/"Diagnostics" — for content that in reality shipped as the Full Safety & Cyber Pack and RELAY v1.11 conformance releases). Future unshipped plans renumbered to start at v0.5.0 so they don't collide with real tags again.
  • README.md architecture section and features list updated for the new mock module.

Issues closed as already-resolved

None — all 8 open issues were live gaps in the current code, verified against the actual current source before fixing.

Issues left open

None.

Test plan

  • cmake -B build -DCMAKE_BUILD_TYPE=Release -DRELAY_BUILD_CLI=ON -G Ninja && cmake --build build --parallel — clean build
  • ctest --test-dir build -j1 — 171/171 tests pass (added tests/test_mock.cpp, plus new cases in test_lin.cpp/test_cli.cpp for the sentinel and --format fixes)
  • Rebuilt with -Werror under -Wall -Wextra -Wpedantic -Wshadow ... (this repo's own flag set) — clean, no warnings
  • Manually exercised version/version --format text/version --format bogus/status/status --format text/capabilities/convert (invalid frame) against the built CLI binary to confirm exit codes and output match the fixes

Spec-conformance fixes:
- Add lin::Errc::invalid_frame error category, distinct from
  ErrPayloadTooLarge, for out-of-range LIN frame IDs per spec §5.3
  ("ErrInvalidFrame and ErrPayloadTooLarge are distinct ... ValidateFrame
  MUST NOT return ErrPayloadTooLarge"). Applied to virtual::Bus::do_publish()/
  send_header(), master::Node::set_schedule()/run(), and slave::Node::
  set_response() (same mis-mapping, found during the fix).
- convert now writes the correct "ErrInvalidFrame" sentinel name to stderr
  instead of the nonexistent "ErrInvalidInput" (spec §11.2).
- capabilities now reports an actual transport backend ("virtual") instead
  of the protocol name ("LIN") in the transports array (spec §12.2).
- version/capabilities/status "tool" field lowercased to "cpp-lin" to match
  the CLI-binary-name convention used by peers (go-can, cpp-rcp) (spec §13.2).
- version/status now support --format text|json, exiting 2 on an
  unrecognized format or any other unrecognized argument (spec §11.1).
- Add lin::mock (aliasing lin::virt::Bus), the RELAY spec §13.7.1 canonical
  "mock" module, plus "mock" in the capabilities features list.

Bug fixes:
- Fix a use-after-free: Adapt()'s subscription thread captured the adapter's
  `this` by raw pointer and dereferenced it via ++seq_ for the thread's
  lifetime, with nothing joining the (detached) thread on adapter
  destruction. The Seq counter is now owned by a shared_ptr captured into
  the thread, which also brings it in line with spec §10.5.2 point 7 (the
  Seq counter belongs to the subscription, not the adapter).
- version/capabilities/status self-reported version is now driven by
  PROJECT_VERSION via a generated header (cli/version.hpp.in) instead of a
  second hard-coded "0.1.0" literal that had drifted three releases behind
  the actual v0.3.0 tag.

Also fixes the same stale-0.1.0 pattern in .fusa.json and the two
`cpfusa init --project-version` invocations in ci.yml (--force would have
overwritten .fusa.json with 0.1.0 on every CI run), and brings ROADMAP.md
in line with what v0.1.0-v0.3.0 actually shipped (it still described
unshipped v0.2.0/v0.3.0 plans for content that shipped differently).

Closes #4
Closes #5
Closes #6
Closes #7
Closes #8
Closes #9
Closes #10
Closes #11

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
The MSVC/Windows CI leg failed: ctest discovers test names via one process
invocation and filters by name in another, and the "§" character in the new
mock-features TEST_CASE name round-tripped differently across that boundary
on the Windows runner's console codepage, so the filter matched zero tests
and ctest treated it as a failure. No other TEST_CASE name in this repo uses
non-ASCII characters; drop the "§" from this one to match.

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
@SoundMatt
SoundMatt merged commit bc61be7 into main Jul 27, 2026
15 checks passed
@SoundMatt
SoundMatt deleted the fix/backlog-2026-07 branch July 27, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant