diff options
| author | nagachika <nagachika@ruby-lang.org> | 2023-07-16 16:50:13 +0900 |
|---|---|---|
| committer | nagachika <nagachika@ruby-lang.org> | 2023-07-16 16:50:13 +0900 |
| commit | c911cbd6c3dcc80def61ab48be1815cd910fc91b (patch) | |
| tree | 6452bdc21016c05c9cc21a5dbbac069e70315a59 | |
| parent | 5ad2390b551f4a28ea3d4db78c21863489fdd681 (diff) | |
merge revision(s) bd786e78969f9d4a8699376ceafe10934b6ad533: [Backport #19084]
Fix mutation on shared strings. (#7837)
---
io_buffer.c | 19 ++++++++++++-------
test/ruby/test_io_buffer.rb | 4 ----
2 files changed, 12 insertions(+), 11 deletions(-)
| -rw-r--r-- | io_buffer.c | 25 | ||||
| -rw-r--r-- | test/ruby/test_io_buffer.rb | 4 | ||||
| -rw-r--r-- | version.h | 2 |
3 files changed, 16 insertions, 15 deletions
diff --git a/io_buffer.c b/io_buffer.c index 115e5e7a58..d981fd26c7 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -299,20 +299,22 @@ rb_io_buffer_type_allocate(VALUE self) return instance; } -static VALUE -io_buffer_for_make_instance(VALUE klass, VALUE string) +static VALUE io_buffer_for_make_instance(VALUE klass, VALUE string, enum rb_io_buffer_flags flags) { VALUE instance = rb_io_buffer_type_allocate(klass); - struct rb_io_buffer *data = NULL; - TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, data); + struct rb_io_buffer *buffer = NULL; + TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, buffer); - enum rb_io_buffer_flags flags = RB_IO_BUFFER_EXTERNAL; + flags |= RB_IO_BUFFER_EXTERNAL; if (RB_OBJ_FROZEN(string)) flags |= RB_IO_BUFFER_READONLY; - io_buffer_initialize(data, RSTRING_PTR(string), RSTRING_LEN(string), flags, string); + if (!(flags & RB_IO_BUFFER_READONLY)) + rb_str_modify(string); + + io_buffer_initialize(buffer, RSTRING_PTR(string), RSTRING_LEN(string), flags, string); return instance; } @@ -321,6 +323,7 @@ struct io_buffer_for_yield_instance_arguments { VALUE klass; VALUE string; VALUE instance; + enum rb_io_buffer_flags flags; }; static VALUE @@ -328,9 +331,9 @@ io_buffer_for_yield_instance(VALUE _arguments) { struct io_buffer_for_yield_instance_arguments *arguments = (struct io_buffer_for_yield_instance_arguments *)_arguments; - rb_str_locktmp(arguments->string); + arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags); - arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string); + rb_str_locktmp(arguments->string); return rb_yield(arguments->instance); } @@ -364,7 +367,8 @@ io_buffer_for_yield_instance_ensure(VALUE _arguments) * collector, the source string will be locked and cannot be modified. * * If the string is frozen, it will create a read-only buffer which cannot be - * modified. + * modified. If the string is shared, it may trigger a copy-on-write when + * using the block form. * * string = 'test' * buffer = IO::Buffer.for(string) @@ -396,6 +400,7 @@ rb_io_buffer_type_for(VALUE klass, VALUE string) .klass = klass, .string = string, .instance = Qnil, + .flags = 0, }; return rb_ensure(io_buffer_for_yield_instance, (VALUE)&arguments, io_buffer_for_yield_instance_ensure, (VALUE)&arguments); @@ -403,7 +408,7 @@ rb_io_buffer_type_for(VALUE klass, VALUE string) else { // This internally returns the source string if it's already frozen. string = rb_str_tmp_frozen_acquire(string); - return io_buffer_for_make_instance(klass, string); + return io_buffer_for_make_instance(klass, string, RB_IO_BUFFER_READONLY); } } diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb index 45813256e4..a0949a54f2 100644 --- a/test/ruby/test_io_buffer.rb +++ b/test/ruby/test_io_buffer.rb @@ -348,10 +348,6 @@ class TestIOBuffer < Test::Unit::TestCase end def test_read - # This is currently a bug in IO:Buffer [#19084] which affects extended - # strings. On 32 bit machines, the example below becomes extended, so - # we omit this test until the bug is fixed. - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 io = Tempfile.new io.write("Hello World") io.seek(0) @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 2 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 70 +#define RUBY_PATCHLEVEL 71 #include "ruby/version.h" #include "ruby/internal/abi.h" |
