src/logging.c:write_logs() takes len_to_end from the read index as it stood
before the prefix, then subtracts LINEBUF_OFFSET from it. That is the distance
to the end of the ring only while the prefix itself does not wrap. When a record
begins at exactly TPX_LOGBUF_SIZE - LINEBUF_OFFSET, the prefix occupies the
last four bytes and the body starts at 0, so len_to_end comes out 0 rather
than the whole ring, ntowrite is MIN(0, linelen) and the write() loop
never runs. r_idx is then sitting on the body's first byte, the terminator
check fails, and the Log ring corrupt: line does not end where its length says
path resynchronizes read_idx onto write_idx, so the line and everything
queued behind it are discarded.
Reproduced with a copy of write_logs_returns_a_message_whose_header_wrapped
set to read_idx = write_idx = TPX_LOGBUF_SIZE - 4; it fails with that error
line in place of the message.
Before #61's fix the same input took the non-wrapping branch instead, leaving
r_idx at TPX_LOGBUF_SIZE and reading log_buf[65535], one past the array,
which sits in shared_t's tail padding and reads as '\0', so the line was
dropped silently. The out-of-bounds read is gone with that fix; the drop is not.
It needs a line to begin at one exact offset, so it is rare: for lines averaging
L bytes it is roughly one lap of the ring in L, which is an estimate from the
geometry rather than a measurement. It affects Debug and Release alike, and both
writes here are of the master's own making, so no worker input is needed to
reach it.
src/logging.c:write_logs()takeslen_to_endfrom the read index as it stoodbefore the prefix, then subtracts
LINEBUF_OFFSETfrom it. That is the distanceto the end of the ring only while the prefix itself does not wrap. When a record
begins at exactly
TPX_LOGBUF_SIZE - LINEBUF_OFFSET, the prefix occupies thelast four bytes and the body starts at 0, so
len_to_endcomes out 0 ratherthan the whole ring,
ntowriteisMIN(0, linelen)and thewrite()loopnever runs.
r_idxis then sitting on the body's first byte, the terminatorcheck fails, and the
Log ring corrupt: line does not end where its length sayspath resynchronizes
read_idxontowrite_idx, so the line and everythingqueued behind it are discarded.
Reproduced with a copy of
write_logs_returns_a_message_whose_header_wrappedset to
read_idx = write_idx = TPX_LOGBUF_SIZE - 4; it fails with that errorline in place of the message.
Before #61's fix the same input took the non-wrapping branch instead, leaving
r_idxatTPX_LOGBUF_SIZEand readinglog_buf[65535], one past the array,which sits in
shared_t's tail padding and reads as'\0', so the line wasdropped silently. The out-of-bounds read is gone with that fix; the drop is not.
It needs a line to begin at one exact offset, so it is rare: for lines averaging
L bytes it is roughly one lap of the ring in L, which is an estimate from the
geometry rather than a measurement. It affects Debug and Release alike, and both
writes here are of the master's own making, so no worker input is needed to
reach it.