Skip to content

feat: S12.07 PosixMessageQueueBuffer error path completeness#443

Merged
DavidCozens merged 11 commits into
mainfrom
fix/s12-07-pmqb-error-paths
May 25, 2026
Merged

feat: S12.07 PosixMessageQueueBuffer error path completeness#443
DavidCozens merged 11 commits into
mainfrom
fix/s12-07-pmqb-error-paths

Conversation

@DavidCozens

@DavidCozens DavidCozens commented May 25, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #118.

  • Slice 0 — MqFake. PMQB was the only Platform/Posix/ adapter unit-testing against real Linux POSIX message queues. New Tests/Support/MqFake.{h,c} mirrors SocketFake's shape — in-memory queue registry plus one-shot failure-injection knobs (MqFake_FailNextOpen/Send/Receive(errno)). Existing 18 PMQB tests migrated; 14 self-tests pin the fake's contracts.
  • Slices 1–4 — Honest error reporting. Three new error codes follow the S12.11 Resolver/Datagram pattern: MQ_OPEN_FAILED (Create releases the slot and returns NullBuffer fallback), SEND_FAILED (Write's mq_send check; EAGAIN/EMSGSIZE both surface), RECEIVE_FAILED (mq_receive non-EAGAIN failure; empty-queue EAGAIN stays silent — part of the polling happy path).
  • Slices 5–6 — Crash-safety. Read guards NULL bytesRead* (segfault → defensive false return). Test pins for use-after-Destroy (NullBuffer vtable patch) and Destroy(NULL) (UNKNOWN_DESTROY warning fallthrough).
  • Slice 7 — Cleanup. IGNORE_TEST(SolidSyslogPosixMessageQueueBuffer, HappyPathOnly) deleted — every referent now pinned or explicitly out of scope.

PMQB error surface now matches the bar S12.11 set for Resolver/Datagram. Real mq_* continues to exercise PMQB end-to-end at the BDD layer.

Test plan

  • All CI checks green
  • Coverage report holds at ≥90% (PMQB surface area grew with new branches)
  • tunable-override-debug preset exercises the new CreateOnMqOpenFailureReleasesSlot test at pool size 2 (slot release observable across multiple slots, not just slot 0)
  • Spot-check the new error messages render sensibly via an integrator's error handler

Follow-up — not in this PR

  • SolidSyslogPassthroughBuffer has an analogous IGNORE_TEST placeholder (Tests/SolidSyslogPassthroughBufferTest.cpp:102) with a much smaller surface (no syscalls). The real residue is _Create(NULL sender). Worth a separate < ½-day story under E12.
  • CHECK_ERROR_MESSAGE_WAS(severity, source, code) macro extraction — five tests now share the same four-line ErrorHandlerFake assertion shape. Refactor when the next slice adds a sixth.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Enhanced error detection and reporting for POSIX message queue operations with specific error codes for initialization, send, and receive failures
    • Improved initialization validation to ensure queue creation succeeds before proceeding
    • Better error diagnostics to aid troubleshooting of message queue issues
  • Tests

    • Added comprehensive test coverage for message queue buffer operations and failure scenarios

Review Change Stack

PMQB was the only Platform/Posix adapter unit-testing against real
Linux POSIX message queues — violated the "fake the platform API
for adapter unit tests" convention (S08.05 FatFsFake precedent;
existing SocketFake/WinsockFake/OpenSslFake siblings).

Add Tests/Support/MqFake.{h,c} exporting mq_open / mq_send /
mq_receive / mq_close / mq_unlink with an in-memory queue registry
and one-shot failure-injection knobs mirroring SocketFake.

Migrate the 18 existing PMQB tests to call MqFake_Reset() in
setup(). Behaviour-preserving — no new error codes yet. Add
MqFakeTest.cpp self-tests pinning the fake's contracts.

Foundation for S12.07 error-path slices. Real mq_* continues to
exercise PMQB end-to-end at the BDD layer.
PMQB Create previously stored the mq_open result without checking
it. On failure (e.g. invalid maxMessages, kernel rlimit), Create
returned a broken handle whose subsequent mq_send / mq_receive
silently failed with EBADF, and the acquired pool slot leaked.

Thread the mq_open result back from Initialise. On failure, Create
releases the slot (so the pool stays accurate for the next caller)
and returns the shared SolidSyslogNullBuffer fallback, emitting the
new POSIXMESSAGEQUEUEBUFFER_ERROR_MQ_OPEN_FAILED error.

Two tests pin the behaviour: error emission and slot release.

Slice 1 of #118.
PMQB Write previously discarded the mq_send return value, so any
failure (queue full, oversized message, EBADF on a broken handle)
was silent — the record was dropped with no visibility to the
caller's error handler.

Check the mq_send result and emit
POSIXMESSAGEQUEUEBUFFER_ERROR_SEND_FAILED on failure. Write's
contract stays fire-and-forget (the record is still dropped on the
floor); honesty surfaces via the error handler rather than a return
code, matching StreamSender.

Test pins the EAGAIN (queue full) path. EMSGSIZE (oversized) goes
through the same uniform check and lands in slice 3 as a regression
guard.

Slice 2 of #118.
Regression guard. The production check in PosixMessageQueueBuffer_Write
is errno-agnostic — `if (mq_send(...) != 0)` catches EAGAIN, EMSGSIZE,
EBADF, etc. uniformly — so this test passes without a production
change. A future contributor who adds errno-specific handling has to
deliberately drop one of these cases.

Slice 3 of #118.
PMQB Read previously folded every mq_receive failure into a silent
`return false`. EAGAIN (empty queue) is part of the polling happy
path and rightly stays silent, but other errnos (EMSGSIZE on a
short caller buffer, EBADF on a broken handle, EINTR, etc.) deserve
to surface to the error handler.

Classify the mq_receive errno: EAGAIN stays silent; any other
failure emits the new POSIXMESSAGEQUEUEBUFFER_ERROR_RECEIVE_FAILED.
Read's return contract is unchanged — still false on any failure.

Two tests: EMSGSIZE-via-MqFake pins the new error emit; empty-queue
poll pins that EAGAIN stays silent (regression guard).

Slice 4 of #118.
PosixMessageQueueBuffer_Read previously dereferenced bytesRead
unconditionally (`*bytesRead = ...`), so passing NULL would segfault.
Early-return false if bytesRead is NULL.

No new error code — this is invalid caller usage, not a runtime
failure. The Read contract still says "false on failure, bytesRead
holds the count on success".

Slice 5 of #118.
Both behaviours are already safe by construction:

- After Destroy, the abstract-base vtable is overwritten with the
  shared SolidSyslogNullBuffer's, so stale-handle Write/Read is a
  no-op rather than a NULL-fn-pointer crash. Mirrors the equivalent
  PassthroughBuffer test.
- Destroy(NULL) routes via IndexFromHandle → POOL_SIZE → IndexIsValid
  false → UNKNOWN_DESTROY warning. The existing
  DestroyOfUnknownHandleReportsWarning test exercises a stack-allocated
  stranger; the new test pins literal NULL specifically.

Both pass first time — regression guards for an integrator who
strays into either case.

Slice 6 of #118.
Every test case enumerated in the PMQB IGNORE_TEST block is now
either pinned by a real test (slices 1–6) or explicitly out of
scope (NULL-buffer dispatcher guards belong to SolidSyslog_Log,
not PMQB; the blocking-mode pointer at "S4.5 or later" was stale
and deserves its own story if still wanted).

Also re-flow a Messages.c line that clang-format coalesced onto a
single line after RECEIVE_FAILED landed in slice 4.

Slice 7 of #118 — closes the story.
End-of-story IWYU sweep caught a transitive include — MqFakeTest
references ssize_t (return type of mq_receive) but only got it
through <mqueue.h>'s implementation. Add the direct include.

Slice 7 follow-up of #118.
@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@DavidCozens, we couldn't start this review because you've used your available PR reviews for now.

Your plan includes 1 review of capacity. Refill in 30 minutes and 32 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dfffcfc0-5316-47e2-9dfb-76a1eb4e3457

📥 Commits

Reviewing files that changed from the base of the PR and between e4fa4be and e8110ce.

📒 Files selected for processing (4)
  • Platform/Posix/Source/SolidSyslogPosixMessageQueueBuffer.c
  • Tests/MqFakeTest.cpp
  • Tests/Support/MqFake.c
  • misra_suppressions.txt
📝 Walkthrough

Walkthrough

This PR implements comprehensive error handling for POSIX message queue buffers by adding three new error codes, changing Initialise to return bool for failure detection, enhancing Read/Write error reporting, and introducing MqFake—a complete test double for POSIX queue functions—then migrating all existing tests to use the fake backend.

Changes

POSIX Message Queue Buffer Error Handling

Layer / File(s) Summary
Error codes and string mappings
Platform/Posix/Interface/SolidSyslogPosixMessageQueueBufferErrors.h, Platform/Posix/Source/SolidSyslogPosixMessageQueueBufferMessages.c
Three new enum values (POSIXMESSAGEQUEUEBUFFER_ERROR_MQ_OPEN_FAILED, SEND_FAILED, RECEIVE_FAILED) and matching human-readable strings enable error-path identification.
Core buffer function changes
Platform/Posix/Source/SolidSyslogPosixMessageQueueBuffer.c, Platform/Posix/Source/SolidSyslogPosixMessageQueueBufferPrivate.h
PosixMessageQueueBuffer_Initialise returns bool to signal mq_open success/failure. Enhanced Read handles null bytesRead and reports non-EAGAIN errors via SolidSyslog_Error. Enhanced Write reports mq_send failures instead of silently dropping them.
Pool slot release on init failure
Platform/Posix/Source/SolidSyslogPosixMessageQueueBufferStatic.c
SolidSyslogPosixMessageQueueBuffer_Create branches on Initialise result: releases pool slot and logs MQ_OPEN_FAILED on failure, only assigns handle on success.
MqFake test double implementation
Tests/Support/MqFake.c
In-memory fake implementing mq_open, mq_close, mq_unlink, mq_send, mq_receive with fixed queue registry, message ring buffers, one-shot failure injection, and call tracking for deterministic error testing.
MqFake public API header
Tests/Support/MqFake.h
Declares reset, failure-injection toggles, and accessor functions to inspect call counts and last-observed arguments across all queue operations.
MqFake test suite validation
Tests/MqFakeTest.cpp
CppUTest tests verify fake behavior: queue creation with distinct handles, message send/receive through ring buffer, empty-queue EAGAIN, failure injection, and queue isolation.
PMQB adapter tests migrated to MqFake
Tests/SolidSyslogPosixMessageQueueBufferTest.cpp
Migrate existing tests off real kernel queues onto MqFake. Add new tests for mq_send/mq_receive error reporting, regression tests for empty-queue silence and null-pointer guards, and pool-level tests for mq_open failure detection and slot-leak prevention.
Build configuration updates
Tests/CMakeLists.txt, Tests/Support/CMakeLists.txt
Include MqFakeTest.cpp in test sources and MqFake.c in the PosixFakes test support library on POSIX platforms.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • DavidCozens/solid-syslog#407: Pool allocator migration for message queue buffer; this PR builds on that foundation to add proper pool-slot cleanup on mq_open failure.
  • DavidCozens/solid-syslog#319: Introduces the library-wide SolidSyslog_Error handler API that this PR depends on to report adapter-level failures.
  • DavidCozens/solid-syslog#396: Introduces SolidSyslogPoolAllocator_FreeIfInUse helper that this PR uses to clean up failed pool allocations.

Poem

🐰 Queues once silent now sing their woes,
With MqFake faking what Linux knows.
No more kernel code in unit tests—
Error paths caught before the sun sets.
Pool slots released, no leaks in sight,
One bouncy PR makes PMQB right! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: S12.07 PosixMessageQueueBuffer error path completeness' directly aligns with the main change: adding comprehensive error handling to the POSIX message queue buffer, following the conventional commits format.
Description check ✅ Passed The PR description covers Purpose (issue #118), Change Description (7 slices with implementation details), Test Evidence (comprehensive test plan), and Areas Affected (PMQB module). All required template sections are addressed.
Linked Issues check ✅ Passed The PR meets all coding requirements from issue #118: adds MqFake test infrastructure, implements three error codes (MQ_OPEN_FAILED, SEND_FAILED, RECEIVE_FAILED), guards NULL bytesRead, and pins crash-safety paths. Issue #39 (CMake platform detection) is unrelated to this PR's scope.
Out of Scope Changes check ✅ Passed All changes are scoped to issue #118: MqFake infrastructure, error handling in PMQB, test coverage expansion, and CMakeLists updates for test support. No out-of-scope modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/s12-07-pmqb-error-paths

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1324 passed, 🙈 1 skipped)
   🚦   build-freertos-host-tdd: 100% successful (✔️ 1552 passed, 🙈 1 skipped)
   🚦   build-linux-clang: 100% successful (✔️ 1276 passed, 🙈 1 skipped)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1276 passed, 🙈 1 skipped)
   🚦   integration-linux-openssl: 100% successful (✔️ 9 passed)
   🚦   integration-linux-mbedtls: 100% successful (✔️ 7 passed)
   🚦   integration-windows-openssl: 100% successful (✔️ 9 passed)
   🚦   bdd-linux-syslog-ng: 94% successful (✔️ 46 passed, 🙈 3 skipped)
   🚦   bdd-windows-otel: 90% successful (✔️ 44 passed, 🙈 5 skipped)
   🚦   bdd-freertos-qemu: 86% successful (✔️ 42 passed, 🙈 7 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 1137 passed, 🙈 1 skipped)
   🚦   build-linux-tunable-override: 100% successful (✔️ 1276 passed, 🙈 1 skipped)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: 1 warning (low: 1)


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
Tests/Support/MqFake.c (1)

226-253: ⚡ Quick win

Reorder helpers to match this repo’s C file top-down rule.

MqFake_AllocateQueue / MqFake_QueueFromMqd are helper functions but are defined before their first caller and without top-of-file forward declarations. Move helpers beneath first caller and keep forward declarations at file top.

As per coding guidelines: “Within source files, order functions top-down… Helper functions must be forward-declared at file top and defined immediately beneath their first caller for top-down reading”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Support/MqFake.c` around lines 226 - 253, Move the helper function
definitions MqFake_AllocateQueue and MqFake_QueueFromMqd so they appear
immediately beneath their first caller (not before it), and add forward
declarations for both at the top of the C file; specifically, add prototypes for
MqFake_AllocateQueue(void) and MqFake_QueueFromMqd(mqd_t) near the other
top-of-file declarations, then cut the two full definitions and paste them right
after the first function that calls them so the file follows the repo’s top-down
ordering rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Tests/Support/MqFake.c`:
- Around line 357-364: mq_send in MqFake currently uses the global
MQFAKE_MAX_MESSAGES_PER_QUEUE and silently truncates oversize messages; change
it to enforce each queue's configured limits: in mq_send use queue->maxMessages
to detect a full queue and set errno = EAGAIN and return -1, and before copying
check if msgLen > queue->maxMessageSize and if so set errno = EMSGSIZE and
return -1 (do not truncate); adjust the copy logic (storeLen) to be used only
after msgLen validated against queue->maxMessageSize.

---

Nitpick comments:
In `@Tests/Support/MqFake.c`:
- Around line 226-253: Move the helper function definitions MqFake_AllocateQueue
and MqFake_QueueFromMqd so they appear immediately beneath their first caller
(not before it), and add forward declarations for both at the top of the C file;
specifically, add prototypes for MqFake_AllocateQueue(void) and
MqFake_QueueFromMqd(mqd_t) near the other top-of-file declarations, then cut the
two full definitions and paste them right after the first function that calls
them so the file follows the repo’s top-down ordering rule.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ecb745e1-ae94-4c42-9c93-a91ab2b454a7

📥 Commits

Reviewing files that changed from the base of the PR and between 358bd22 and e4fa4be.

📒 Files selected for processing (11)
  • Platform/Posix/Interface/SolidSyslogPosixMessageQueueBufferErrors.h
  • Platform/Posix/Source/SolidSyslogPosixMessageQueueBuffer.c
  • Platform/Posix/Source/SolidSyslogPosixMessageQueueBufferMessages.c
  • Platform/Posix/Source/SolidSyslogPosixMessageQueueBufferPrivate.h
  • Platform/Posix/Source/SolidSyslogPosixMessageQueueBufferStatic.c
  • Tests/CMakeLists.txt
  • Tests/MqFakeTest.cpp
  • Tests/SolidSyslogPosixMessageQueueBufferTest.cpp
  • Tests/Support/CMakeLists.txt
  • Tests/Support/MqFake.c
  • Tests/Support/MqFake.h

Comment thread Tests/Support/MqFake.c Outdated
CI's analyze-cppcheck job runs a second MISRA-addon invocation that
exits non-zero on unsuppressed violations; my local sweep only
covered the plain cppcheck invocation. Four violations slipped
through:

1. PMQB.c errno test after mq_receive triggered Rule 22.10 — the
   predicate's value could conceivably depend on errno being set by
   something other than the immediately preceding library call.
   Captured errno into a local right after mq_receive, matching the
   project's existing pattern in PosixTcpStream.c:190 and
   PosixDatagram.c:101. No suppression needed.

2-4. Three pre-existing line-pinned suppressions
   (misra-c2012-11.3 PMQB.c, 5.7 PMQB.c, 5.7 PMQBPrivate.h) shifted
   line numbers because slices 1-5 added includes and grew the
   functions. Updated the pinned line numbers in
   misra_suppressions.txt — no new suppressions added.

Local cppcheck-misra now exits 0 across all 147 production files.
CodeRabbit caught that MqFake's mq_send ignored the per-queue
attributes captured at mq_open:

- Queue-full path used the fake-wide MQFAKE_MAX_MESSAGES_PER_QUEUE
  (8) instead of queue->maxMessages, so a queue opened with
  maxMessages=2 would accept 8 sends before EAGAIN — diverging from
  the real kernel.
- Oversized messages were silently truncated via storeLen clamping
  rather than failing with -1/EMSGSIZE per POSIX.

Both gaps would mask real-kernel behaviour from tests that
exercise natural overflow rather than MqFake_FailNext* injection.
Per the "fakes must model the API faithfully" principle from
feedback_fake_platform_apis (the precedent that drove introducing
MqFake in S12.07 slice 0), fix while the fake is fresh.

Enforcement order matches POSIX (mq_send specification):
  1. EBADF — bad descriptor
  2. EMSGSIZE — msgLen > mq_attr.mq_msgsize
  3. EAGAIN — queue at mq_attr.mq_maxmsg

Storage cap MQFAKE_MAX_MESSAGES_PER_QUEUE bumped 8 → 16 so it
remains >= any maxMessages value tests pass (PMQB tests use 10).
Two new MqFakeTest cases pin the natural-overflow and
natural-oversize paths.

Addresses CodeRabbit comment on PR #443.
@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1326 passed, 🙈 1 skipped)
   🚦   build-freertos-host-tdd: 100% successful (✔️ 1554 passed, 🙈 1 skipped)
   🚦   build-linux-clang: 100% successful (✔️ 1278 passed, 🙈 1 skipped)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1278 passed, 🙈 1 skipped)
   🚦   integration-linux-openssl: 100% successful (✔️ 9 passed)
   🚦   integration-linux-mbedtls: 100% successful (✔️ 7 passed)
   🚦   integration-windows-openssl: 100% successful (✔️ 9 passed)
   🚦   bdd-linux-syslog-ng: 94% successful (✔️ 46 passed, 🙈 3 skipped)
   🚦   bdd-windows-otel: 90% successful (✔️ 44 passed, 🙈 5 skipped)
   🚦   bdd-freertos-qemu: 86% successful (✔️ 42 passed, 🙈 7 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 1137 passed, 🙈 1 skipped)
   🚦   build-linux-tunable-override: 100% successful (✔️ 1278 passed, 🙈 1 skipped)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: 1 warning (low: 1)


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

@DavidCozens DavidCozens merged commit a0edced into main May 25, 2026
21 checks passed
@DavidCozens DavidCozens deleted the fix/s12-07-pmqb-error-paths branch May 25, 2026 08:14
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.

S12.07: PosixMessageQueueBuffer error handling

1 participant