From: "YO4 (Yoshinao Muramatsu) via ruby-core" Date: 2025-11-16T14:52:44+00:00 Subject: [ruby-core:123814] [Ruby Bug#21634] Combining read(1) with eof? causes dropout of results unexpectedly on Windows. Issue #21634 has been updated by YO4 (Yoshinao Muramatsu). @nobu, I had not correctly understood the 'rt' case in #note-2. In the case where 'universal_newline: true' attribute, Ctrl-Z is not interpreted as an EOF, so I believe the behavior you pointed out is correct. ``` > ruby -ve "open('eof.txt', 'rt') { |f| p f.read }" ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x64-mingw-ucrt] "abcd\u001A\n" ``` Additionally, while investigating another case, I observed behavior related to #note-2. #21687#note-1 Therefore, the C runtime library's eof() appears unreliable. The current rb_io_eof code originates from #6271, but if io_unread has been improved, we may not need to use eof(). ```c if (rb_w32_fd_is_text(fptr->fd)) { return RBOOL(eof(fptr->fd)); } ``` If the above code is unnecessary, everytime we could rely on `RBOOL(io_fillbuf(fptr) < 0)`. However, as pointed out in #21687, the file position becomes incorrect after encountering an intermediate EOF, making subsequent operation results unreliable. That should be discussed in that issue. ---------------------------------------- Bug #21634: Combining read(1) with eof? causes dropout of results unexpectedly on Windows. https://bugs.ruby-lang.org/issues/21634#change-115215 * Author: YO4 (Yoshinao Muramatsu) * Status: Open * ruby -v: ruby 3.5.0dev (2025-10-03T08:59:54Z master 5b2ec0eb1b) +PRISM [x64-mingw-ucrt] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- On Windows, when reading a file containing EOF(\x1A), using read(1) with IO#eof? causes unexpected dropout of results. ```ruby irb(main):001> IO.binwrite("txt", "abcd\x1A") => 5 irb(main):002> open("txt", "r") { p _1.read(1) until _1.eof? }; # works fine "a" "b" "c" "d" "\x1A" irb(main):003> open("txt", "rt") { p _1.read(1) until _1.eof? }; # has failure "b" "d" irb(main):004> ``` The problem disappeared when I commented out one of the following lines (though this will break other things). * previous_mode = set_binary_mode_with_seek_cur(fptr); in io_read() * flush_before_seek(fptr, false); in set_binary_mode_with_seek_cur(() * io_unread(fptr, discard_rbuf); in flush_before_seek() Within io_unread(), rbuf.len should have changed as 5, 4, 3,... but instead changed as 4, 2,(end). Since inconsistencies already exist at this point, the problem appears to originate elsewhere. I found this in ruby master but the same issue was found at least in ruby-1.9.3-p551. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/