Fix fill_cbuf putting back more bytes than the current rbuf fill holds

The converter can still hold readagain bytes from an earlier rbuf fill,
so fill_cbuf must not put all of them back into the current rbuf. Clamp
the putback to the bytes taken from the current fill; the rest stay in
the converter and are re-read first on the next conversion.

Co-authored-by: Percze Dániel <162882837+Flashmyname@users.noreply.github.com>
Co-Authored-By: Claude Mythos 5.1 <noreply@anthropic.com>
This commit is contained in:
committed 2026-10-28 03:18:36 +09:00
1 parent 93c45a96b5
commit 95f21cd82c
2 files changed
+27
Notes: git 2026-10-27 18:19:16 +00:00

No files matched your search

+5
View File
@@ -3329,6 +3329,11 @@ fill_cbuf(rb_io_t *fptr, int ec_flags)
fptr->cbuf.len += (int)(dp - ds);
putbackable = rb_econv_putbackable(fptr->readconv);
/* The converter can hold readagain bytes it received in an earlier
* fill (a character split across reads). Only bytes still in rbuf
* can be put back there; the rest stay in the converter. */
if (putbackable > fptr->rbuf.off)
putbackable = fptr->rbuf.off;
if (putbackable) {
rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
fptr->rbuf.off -= putbackable;
+22
View File
@@ -2307,6 +2307,28 @@ EOT
}
end
def test_read_utf16le_invalid_surrogate_split_across_reads
# The converter may hold readagain bytes from the previous fill;
# fill_cbuf must not put those back into rbuf.
with_pipe("UTF-16LE:UTF-8") {|r, w|
w.write("\x00\xD8\x41".b)
t = Thread.new {
sleep 0.1
w.write("\x00\x42\x00\x0a\x00".b)
w.close
}
begin
e = assert_raise(Encoding::InvalidByteSequenceError) { r.gets }
assert_equal("\x00\xD8".b, e.error_bytes)
assert_equal("\x41\x00".b, e.readagain_bytes)
assert_equal("AB\n", r.gets)
assert_nil(r.gets)
ensure
t.join
end
}
end
def test_cbuf
with_tmpdir {
fn = "tst"