mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 08:25:20 +08:00
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:
1 parent
93c45a96b5
commit
95f21cd82c
2 files changed
+27
Notes:
git
2026-10-27 18:19:16 +00:00
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in new issue
Block a user