Bug #18881
closedIO#read_nonblock raises IOError when called following buffered character IO
Description
The following example code works as expected on Linux but raises an IOError
on Windows:
r, w = IO.pipe
w.write("foobar")
c = r.getc
r.ungetc(c)
r.read_nonblock(3)
The error message is:
IOError: byte oriented read for character buffered IO
Updated by shyouhei (Shyouhei Urabe) almost 3 years ago
Not looking at the implementation but sounds like an issue of Linux side to me. The error message seems intentional.
Updated by nobu (Nobuyoshi Nakada) almost 3 years ago
- Status changed from Open to Rejected
It is an expected behavior.
On Windows, text/binary conversion is used by default, and ungetc
pushes back the character to the conversion buffer in that case.
The error message means this situation.
Updated by shyouhei (Shyouhei Urabe) almost 3 years ago
@nobu (Nobuyoshi Nakada) Yes but wouldn't it be nice if IO#read_nonblock also raises on Linux?
Updated by nobu (Nobuyoshi Nakada) almost 3 years ago
@shyouhei (Shyouhei Urabe) Even without any conversion?
This is an example on macOS.
$ ruby -v -e 'r, w = IO.pipe; r.set_encoding("utf-8", "iso-8859-15"); w.write("foobar"); c = r.getc; r.ungetc(c); r.read_nonblock(3)'
ruby 3.2.0dev (2022-06-28T06:49:05Z master 98bf8c83fa) [x86_64-darwin21]
<internal:io>:63:in `read_nonblock': byte oriented read for character buffered IO (IOError)
from -e:1:in `<main>'
Updated by shyouhei (Shyouhei Urabe) almost 3 years ago
nobu (Nobuyoshi Nakada) wrote in #note-4:
@shyouhei (Shyouhei Urabe) Even without any conversion?
Yes. "Byte oriented and character oriented IO operations cannot be mixed at all" sounds much simpler than the current (it sometimes raises and sometimes doesn't).
Updated by nobu (Nobuyoshi Nakada) almost 3 years ago
Do you mean that once character oriented methods are called, all byte oriented methods always fail?
(Possibly reset by seek
?)
Updated by shyouhei (Shyouhei Urabe) almost 3 years ago
Basically yes. Some edge cases can be considered though (e.g. IO#flush could also reset this, IO#pread could be special-case allowed (avoiding IO#seek is the reason for this method to exist), etc).
Updated by javanthropus (Jeremy Bopp) almost 3 years ago
There needs to be documentation to cover the corner cases no matter what. Wouldn't it be better to document the current behavior rather than add artificial limitations?
For what it's worth, I was able to reproduce the reported behavior on Linux with a minor modification to the example script:
r, w = IO.pipe
r.set_encoding('utf-8', universal_newline: true) # Set line ending handling like on Windows
w.write("foobar")
c = r.getc
r.ungetc(c)
r.read_nonblock(3)