BUG/MEDIUM: channel: bi_putblk() must not wrap before the end of buffer
The errors reported by Igor Chan on the stats interface in chunked mode
were caused by data wrapping at the wrong place in the buffer. It could
be reliably reproduced by picking random buffer sizes until the issue
appeared (for a given conf, 5300 with 1024 maxrewrite was OK).
The issue is that the stats interface uses bi_putchk() to emit data,
which relies on bi_putblk(). This code checks the largest part that can
be emitted while preserving the rewrite reserve, but uses that result to
compute the wrapping offset, which is wrong. If some data remain present
in the buffer, the wrapping may be allowed and will happen before the
end of the buffer, leaving some old data in the buffer.
The reason it did not happen before keep-alive is simply that the buffer
was much less likely to contain older data. It also used to happen only
for certain configs after a certain amount of time because the size of
the counters used to inflate the output till the point wrapping started
to happen.
The fix is trivial, buffer_contig_space_with_res() simply needs to be
replaced by buffer_contig_space().
Note that peers were using the same function so it is possible that they
were affected as well.
This issue was introduced in 1.5-dev8. No backport to stable is needed.
diff --git a/src/channel.c b/src/channel.c
index 1250370..2f98396 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -174,7 +174,7 @@
return 0;
/* OK so the data fits in the buffer in one or two blocks */
- max = buffer_contig_space_with_res(chn->buf, chn->buf->size - max);
+ max = buffer_contig_space(chn->buf);
memcpy(bi_end(chn->buf), blk, MIN(len, max));
if (len > max)
memcpy(chn->buf->data, blk + max, len - max);