Fix the debugger log stream going out of step after 1024 messages

DebuggerLogListener keeps a ring of the last BUFFER_SIZE messages. read_ and
count_ count messages ever read/written, while messages_ is indexed modulo
BUFFER_SIZE - but the non-overflow path used read_ directly as the index. Once
a session had logged BUFFER_SIZE messages that index was past the end of the
array, so the first copy loop (bounded by BUFFER_SIZE) ran zero times and the
second one handed back messages_[0..readCount-1] instead: real log messages,
just the wrong ones, and every later poll stayed the same distance out of step.

It looks like the tail of the log going missing rather than being wrong, which
is a bad way to find out. A log-only breakpoint in a hot loop reaches 1024
messages in seconds, and then "the last thing logged before the breakpoint hit"
- exactly what such a breakpoint is for - names an event thousands of messages
old. Confirmed against a case with an independently known answer: a log-only
breakpoint recording a register in a loop that runs ~20k times now ends with
the value that register actually held at the final hit, where before it ended
several hundred iterations short of it.

The overflow path was already correct - it starts from nextMessage_, which is
an index - so only the one line changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5 committed 2026-09-07 18:42:39 -06:00
1 parent 9799085c3a
commit 4e24c195ac
1 file changed
+9 -1
+9 -1
View File
@@ -52,7 +52,15 @@ public:
splitPoint = nextMessage_;
readCount = Count();
} else {
splitPoint = read_;
// read_ counts messages ever read, so it has to be wrapped to index the ring - the
// overflow branch above starts from nextMessage_, which already is an index. Without
// the modulo this went wrong the moment a session logged BUFFER_SIZE messages: with
// splitPoint >= BUFFER_SIZE the first copy loop below is empty, so the second one
// handed back messages_[0..readCount-1] - the oldest entries in the buffer, not the
// new ones - and every later poll stayed that far out of step. High-volume sources
// (a log-only breakpoint in a hot loop) hit it within seconds, and the result looked
// like the tail of the log going missing rather than being wrong.
splitPoint = read_ % BUFFER_SIZE;
readCount = count_ - read_;
}