Skip to content

Commit

Permalink
merge revision(s) bd786e7: [Backport #19084]
Browse files Browse the repository at this point in the history
	Fix mutation on shared strings. (#7837)

	---
	 io_buffer.c                 | 19 ++++++++++++-------
	 test/ruby/test_io_buffer.rb |  4 ----
	 2 files changed, 12 insertions(+), 11 deletions(-)
  • Loading branch information
unak committed Jul 25, 2023
1 parent e7c94d9 commit 3799270
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 18 deletions.
39 changes: 22 additions & 17 deletions io_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion version.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 3799270

Please sign in to comment.