Skip to content

Commit b4fe248

Browse files
committed
[GR-18163] Fix IO#read_nonblock and preserve buffer's encoding
PullRequest: truffleruby/4234
2 parents 6ddaef5 + df33fc1 commit b4fe248

File tree

24 files changed

+166
-31
lines changed

24 files changed

+166
-31
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Bug fixes:
1010
* Fix `rb_global_variable()` for `Float` and bignum values during the `Init_` function (#3478, @eregon).
1111
* Fix `rb_gc_register_mark_object()` for `Float` and bignum values (#3502, @eregon, @andrykonchin).
1212
* Fix parsing literal floats when the locale does not use `.` for the decimal separator (e.g. `LANG=fr_FR.UTF-8`) (#3512, @eregon).
13+
* Fix `IO#{read_nonblock,readpartial,sysread}`, `BasicSocket#{recv,recv_nonblock}`, `{Socket,UDPSocket}#recvfrom_nonblock`, `UnixSocket#recvfrom` and preserve a provided buffer's encoding (#3506, @andrykonchyn).
1314

1415
Compatibility:
1516

lib/truffle/socket/basic_socket.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,11 @@ def send(message, flags, dest_sockaddr = nil)
163163
end
164164

165165
str = buf.read_string(n_bytes)
166-
buffer ? buffer.replace(str) : str
166+
if buffer
167+
buffer.replace str.force_encoding(buffer.encoding)
168+
else
169+
str
170+
end
167171
end
168172
end
169173

lib/truffle/socket/ip_socket.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ def peeraddr(reverse_lookup = nil)
6161
end
6262
end
6363

64-
message = buffer.replace(message) if buffer
64+
if buffer
65+
message = buffer.replace message.force_encoding(buffer.encoding)
66+
end
6567

6668
[message, [aname, addr.ip_port, hostname, addr.ip_address]]
6769
end

lib/truffle/socket/socket.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,9 @@ def recvfrom(bytes, flags = 0)
384384
if message == :wait_readable
385385
message
386386
else
387-
message = buffer.replace(message) if buffer
387+
if buffer
388+
message = buffer.replace message.force_encoding(buffer.encoding)
389+
end
388390
[message, addr]
389391
end
390392
end

lib/truffle/socket/unix_socket.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,18 @@ def initialize(path)
5858
Errno.handle('connect(2)') if status < 0
5959
end
6060

61-
def recvfrom(bytes_read, flags = 0)
61+
def recvfrom(bytes_read, flags = 0, buffer = nil)
6262
Truffle::Socket::Foreign.memory_pointer(bytes_read) do |buf|
6363
n_bytes = Truffle::Socket::Foreign.recvfrom(Primitive.io_fd(self), buf, bytes_read, flags, nil, nil)
6464
Errno.handle('recvfrom(2)') if n_bytes == -1
65-
return [buf.read_string(n_bytes), ['AF_UNIX', '']]
65+
66+
message = buf.read_string(n_bytes)
67+
68+
if buffer
69+
message = buffer.replace message.force_encoding(buffer.encoding)
70+
end
71+
72+
return [message, ['AF_UNIX', '']]
6673
end
6774
end
6875

lib/truffle/stringio.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ def read(length = nil, buffer = nil)
450450
pos = d.pos
451451
string = d.string
452452

453+
# intentionally don't preserve buffer's encoding
454+
# see https://bugs.ruby-lang.org/issues/20418
453455
if length
454456
length = Truffle::Type.coerce_to length, Integer, :to_int
455457
raise ArgumentError if length < 0

spec/ruby/core/io/pread_spec.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
it "accepts a length, an offset, and an output buffer" do
2424
buffer = +"foo"
25-
@file.pread(3, 4, buffer)
25+
@file.pread(3, 4, buffer).should.equal?(buffer)
2626
buffer.should == "567"
2727
end
2828

@@ -38,6 +38,13 @@
3838
buffer.should == "12345"
3939
end
4040

41+
it "preserves the encoding of the given buffer" do
42+
buffer = ''.encode(Encoding::ISO_8859_1)
43+
@file.pread(10, 0, buffer)
44+
45+
buffer.encoding.should == Encoding::ISO_8859_1
46+
end
47+
4148
it "does not advance the file pointer" do
4249
@file.pread(4, 0).should == "1234"
4350
@file.read.should == "1234567890"

spec/ruby/core/io/read_spec.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,21 @@
376376
buf.should == @contents[0..4]
377377
end
378378

379+
it "preserves the encoding of the given buffer" do
380+
buffer = ''.encode(Encoding::ISO_8859_1)
381+
@io.read(10, buffer)
382+
383+
buffer.encoding.should == Encoding::ISO_8859_1
384+
end
385+
386+
# https://bugs.ruby-lang.org/issues/20416
387+
it "does not preserve the encoding of the given buffer when max length is not provided" do
388+
buffer = ''.encode(Encoding::ISO_8859_1)
389+
@io.read(nil, buffer)
390+
391+
buffer.encoding.should_not == Encoding::ISO_8859_1
392+
end
393+
379394
it "returns the given buffer" do
380395
buf = +""
381396

spec/ruby/core/io/readpartial_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
buffer = +"existing content"
6363
@wr.write("hello world")
6464
@wr.close
65-
@rd.readpartial(11, buffer)
65+
@rd.readpartial(11, buffer).should.equal?(buffer)
6666
buffer.should == "hello world"
6767
end
6868

@@ -106,6 +106,7 @@
106106
@wr.write("abc")
107107
@wr.close
108108
@rd.readpartial(10, buffer)
109+
109110
buffer.encoding.should == Encoding::ISO_8859_1
110111
end
111112
end

spec/ruby/core/io/sysread_spec.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797

9898
it "discards the existing buffer content upon successful read" do
9999
buffer = +"existing content"
100-
@file.sysread(11, buffer)
100+
@file.sysread(11, buffer).should.equal?(buffer)
101101
buffer.should == "01234567890"
102102
end
103103

@@ -107,6 +107,13 @@
107107
-> { @file.sysread(1, buffer) }.should raise_error(EOFError)
108108
buffer.should be_empty
109109
end
110+
111+
it "preserves the encoding of the given buffer" do
112+
buffer = ''.encode(Encoding::ISO_8859_1)
113+
string = @file.sysread(10, buffer)
114+
115+
buffer.encoding.should == Encoding::ISO_8859_1
116+
end
110117
end
111118

112119
describe "IO#sysread" do

0 commit comments

Comments
 (0)