Parent epic: #254
Context
Surfaced during the S23.02 public-header documentation pass (#248, PR #604).
Writing down SolidSyslogBuffer_Read's return contract exposed a genuine API
design gap; per S23.02's "inconsistencies surfaced during this pass are raised
as separate issues rather than papered over with prose" acceptance criterion,
tracking it here rather than fixing it in the docs PR.
Source: CodeRabbit review comment
#604 (comment)
The gap
bool SolidSyslogBuffer_Read(struct SolidSyslogBuffer* base, void* data, size_t maxSize, size_t* bytesRead)
returns false / bytesRead == 0 for two distinct conditions:
- The buffer is genuinely empty — nothing to deliver.
- The record at the head is larger than
maxSize and cannot be copied out, so
it is left un-dequeued.
SolidSyslog_Service's drain loop reads false as "empty, stop". In case (2)
the oversized record sits at the head indefinitely: the loop stops early on
every pass, the record is never delivered, and no SolidSyslog_Error is emitted
— a silent stall with no diagnostic and no caller-visible recovery path.
In normal operation maxSize (the servicing scratch buffer) is sized to the
maximum record, so this is latent rather than routinely hit — but it is
reachable via misconfiguration (a servicing buffer smaller than a producer's
max record) and is invisible when it happens.
Options to weigh (design, not prescribed)
- Distinguish the two conditions via a tri-state result or an out-enum
(EMPTY / DELIVERED / OVERSIZED).
- Keep
false but emit SolidSyslog_Error(..., _BUFFER_...) on the oversized
case so the stall is at least observable.
- Drop-and-advance the oversized head record (with an error) so the drain loop
makes progress rather than wedging.
Done when
SolidSyslogBuffer_Read (and the SolidSyslogBuffer vtable contract) can no
longer silently wedge the drain loop on an oversized head record.
- The chosen behaviour is covered by a unit test for the oversized-head case
against the concrete buffers (Circular, PosixMessageQueue) as applicable.
- Contract doc-comments in
SolidSyslogBuffer.h / SolidSyslogBufferDefinition.h
updated to match the new behaviour.
Parent epic: #254
Context
Surfaced during the S23.02 public-header documentation pass (#248, PR #604).
Writing down
SolidSyslogBuffer_Read's return contract exposed a genuine APIdesign gap; per S23.02's "inconsistencies surfaced during this pass are raised
as separate issues rather than papered over with prose" acceptance criterion,
tracking it here rather than fixing it in the docs PR.
Source: CodeRabbit review comment
#604 (comment)
The gap
bool SolidSyslogBuffer_Read(struct SolidSyslogBuffer* base, void* data, size_t maxSize, size_t* bytesRead)returns
false/bytesRead == 0for two distinct conditions:maxSizeand cannot be copied out, soit is left un-dequeued.
SolidSyslog_Service's drain loop readsfalseas "empty, stop". In case (2)the oversized record sits at the head indefinitely: the loop stops early on
every pass, the record is never delivered, and no
SolidSyslog_Erroris emitted— a silent stall with no diagnostic and no caller-visible recovery path.
In normal operation
maxSize(the servicing scratch buffer) is sized to themaximum record, so this is latent rather than routinely hit — but it is
reachable via misconfiguration (a servicing buffer smaller than a producer's
max record) and is invisible when it happens.
Options to weigh (design, not prescribed)
(EMPTY / DELIVERED / OVERSIZED).
falsebut emitSolidSyslog_Error(..., _BUFFER_...)on the oversizedcase so the stall is at least observable.
makes progress rather than wedging.
Done when
SolidSyslogBuffer_Read(and theSolidSyslogBuffervtable contract) can nolonger silently wedge the drain loop on an oversized head record.
against the concrete buffers (Circular, PosixMessageQueue) as applicable.
SolidSyslogBuffer.h/SolidSyslogBufferDefinition.hupdated to match the new behaviour.