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 /io_buffer.c | |
| 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(-)
Diffstat (limited to 'io_buffer.c')
| -rw-r--r-- | io_buffer.c | 25 |
1 files changed, 15 insertions, 10 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); } } |
