diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c index 5c45e30950..33630463b2 100644 --- a/ext/stringio/stringio.c +++ b/ext/stringio/stringio.c @@ -180,6 +180,7 @@ check_modifiable(struct StringIO *ptr) else if (OBJ_FROZEN_RAW(ptr->string)) { rb_raise(rb_eIOError, "not modifiable string"); } + rb_str_modify(ptr->string); } static VALUE diff --git a/test/stringio/test_stringio.rb b/test/stringio/test_stringio.rb index 64bc5f67c3..8d236e5bba 100644 --- a/test/stringio/test_stringio.rb +++ b/test/stringio/test_stringio.rb @@ -14,6 +14,24 @@ class TestStringIO < Test::Unit::TestCase include TestEOF::Seek + def test_do_not_mutate_shared_buffers + # Ensure we have two strings that are not embedded but have the same shared + # string reference. + # + # In this case, we must use eval because we need two strings literals that + # are long enough they cannot be embedded, but also contain the same bytes. + + a = eval(("x" * 1024).dump) + b = eval(("x" * 1024).dump) + + s = StringIO.new(b) + s.getc + s.ungetc '#' + + # We mutated b, so a should not be mutated + assert_equal("x", a[0]) + end + def test_version assert_kind_of(String, StringIO::VERSION) end