diff options
| author | U.Nakamura <usa@ruby-lang.org> | 2023-07-25 20:29:45 +0900 |
|---|---|---|
| committer | U.Nakamura <usa@ruby-lang.org> | 2023-07-25 20:29:45 +0900 |
| commit | 3799270ec27b1267cd9923dae00bcb3955f7e061 (patch) | |
| tree | a09f9c752513589363cf906e4c0dcddb461049d7 | |
| parent | e7c94d9d1d2bdbf396c489d1dc653c771f59bb92 (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 | 39 | ||||
| -rw-r--r-- | version.h | 2 |
2 files changed, 23 insertions, 18 deletions
diff --git a/io_buffer.c b/io_buffer.c index 5951f54fc4..4b806906f2 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -284,37 +284,40 @@ 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); - 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; + if (!(flags & RB_IO_BUFFER_READONLY)) + rb_str_modify(string); + io_buffer_initialize(data, RSTRING_PTR(string), RSTRING_LEN(string), flags, string); return instance; } struct io_buffer_for_yield_instance_arguments { - VALUE klass; - VALUE string; - VALUE instance; + VALUE klass; + VALUE string; + VALUE instance; + enum rb_io_buffer_flags flags; }; static VALUE 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); } @@ -348,7 +351,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) @@ -376,17 +380,18 @@ rb_io_buffer_type_for(VALUE klass, VALUE string) // If the string is frozen, both code paths are okay. // If the string is not frozen, if a block is not given, it must be frozen. if (rb_block_given_p()) { - struct io_buffer_for_yield_instance_arguments arguments = { - .klass = klass, - .string = string, - .instance = Qnil, - }; + struct io_buffer_for_yield_instance_arguments arguments = { + .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); } 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); + // 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, RB_IO_BUFFER_READONLY); } } @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 4 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 234 +#define RUBY_PATCHLEVEL 235 #define RUBY_RELEASE_YEAR 2023 #define RUBY_RELEASE_MONTH 7 |
