Skip to content

Commit cd00aae

Browse files
committed
[GR-18163] Fix StringIO#initialize and preserve initial string's encoding
PullRequest: truffleruby/4306
2 parents b0b947e + 1b6c7a5 commit cd00aae

File tree

3 files changed

+34
-11
lines changed

3 files changed

+34
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Compatibility:
3434
* Fix `RangeError` message to match CRuby for `Integer#chr` called with invalid codepoint argument (#2795, @andrykonchin).
3535
* Joni has been updated from 2.1.44 to 2.2.1 (@andrykonchin).
3636
* Fix `Hash#to_h` called with a block and pass key and value to the block as separate arguments (#3607, @andrykonchin).
37+
* Fix `StringIO#initialize` and preserve initial string's encoding when mode is `w` so the initial string is truncated (#3599, @andrykonchin).
3738

3839
Performance:
3940

lib/truffle/stringio.rb

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@ def initialize(string = nil, mode = nil, **options)
166166
mode_from_string(string.frozen? ? 'r' : 'r+')
167167
end
168168

169+
if @writable && @__data__.string.frozen?
170+
raise Errno::EACCES, 'Permission denied'
171+
end
172+
173+
if @truncate
174+
@__data__.string.replace(''.force_encoding(@__data__.string.encoding))
175+
end
176+
169177
self
170178
end
171179

@@ -672,43 +680,37 @@ def yaml_initialize(type, val)
672680
end
673681

674682
private def mode_from_string(mode)
675-
@append = truncate = false
683+
@append = @truncate = false
676684

677685
if mode[0] == ?r
678686
@readable = true
679687
@writable = mode[-1] == ?+ ? true : false
680688
end
681689

682690
if mode[0] == ?w
683-
@writable = truncate = true
691+
@writable = @truncate = true
684692
@readable = mode[-1] == ?+ ? true : false
685693
end
686694

687695
if mode[0] == ?a
688696
@append = @writable = true
689697
@readable = mode[-1] == ?+ ? true : false
690698
end
691-
692-
d = @__data__ # no sync, only called from initialize
693-
raise Errno::EACCES, 'Permission denied' if @writable && d.string.frozen?
694-
d.string.replace('') if truncate
695699
end
696700

697701
private def mode_from_integer(mode)
698-
@readable = @writable = @append = false
699-
d = @__data__ # no sync, only called from initialize
702+
@readable = @writable = @append = @truncate = false
700703

701704
if mode == 0 or mode & IO::RDWR != 0
702705
@readable = true
703706
end
704707

705708
if mode & (IO::WRONLY | IO::RDWR) != 0
706-
raise Errno::EACCES, 'Permission denied' if d.string.frozen?
707709
@writable = true
708710
end
709711

710712
@append = true if (mode & IO::APPEND) != 0
711-
d.string.replace('') if (mode & IO::TRUNC) != 0
713+
@truncate = true if (mode & IO::TRUNC) != 0
712714
end
713715

714716
private def getline(arg_error, sep, limit, chomp = false)

spec/ruby/library/stringio/initialize_spec.rb

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,26 @@
130130
-> { @io.send(:initialize, str, "w") }.should raise_error(Errno::EACCES)
131131
-> { @io.send(:initialize, str, "a") }.should raise_error(Errno::EACCES)
132132
end
133+
134+
it "truncates all the content if passed w mode" do
135+
io = StringIO.allocate
136+
source = +"example".encode(Encoding::ISO_8859_1);
137+
138+
io.send(:initialize, source, "w")
139+
140+
io.string.should.empty?
141+
io.string.encoding.should == Encoding::ISO_8859_1
142+
end
143+
144+
it "truncates all the content if passed IO::TRUNC mode" do
145+
io = StringIO.allocate
146+
source = +"example".encode(Encoding::ISO_8859_1);
147+
148+
io.send(:initialize, source, IO::TRUNC)
149+
150+
io.string.should.empty?
151+
io.string.encoding.should == Encoding::ISO_8859_1
152+
end
133153
end
134154

135155
describe "StringIO#initialize when passed [Object]" do
@@ -172,7 +192,7 @@
172192
# NOTE: Synchronise with core/io/new_spec.rb (core/io/shared/new.rb)
173193
describe "StringIO#initialize when passed keyword arguments" do
174194
it "sets the mode based on the passed :mode option" do
175-
io = StringIO.new("example", "r")
195+
io = StringIO.new("example", mode: "r")
176196
io.closed_read?.should be_false
177197
io.closed_write?.should be_true
178198
end

0 commit comments

Comments
 (0)