summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorU.Nakamura <usa@ruby-lang.org>2023-06-19 20:49:09 +0900
committerU.Nakamura <usa@ruby-lang.org>2023-06-19 20:49:09 +0900
commit6302bf2ebe8d4807ede5ac9b8602c92ed336e5bd (patch)
tree7b900ae09cf17e243231f490b7691fbf2030f78b
parent344249674f7a7835445a44695664897fa4b83f00 (diff)
merge revision(s) d2520b7b76759118071a16e6bca22726a5de9fb4: [Backport #19439]
Marshal.load: restore instance variables on Regexp [Bug #19439] The instance variables were restore on the Regexp source, not the regexp itself. Unfortunately we have a bit of a chicken and egg problem. The source holds the encoding, and the encoding need to be set on the source to be able to instantiate the Regexp. So the instance variables have to be read on the `source`. To correct this we transfert the instance variables after instantiating the Regexp. The only way to avoid this would be to read the instance variable twice and rewind. --- marshal.c | 20 ++++++++++++++++++-- spec/ruby/core/marshal/shared/load.rb | 11 +++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-)
-rw-r--r--marshal.c20
-rw-r--r--spec/ruby/core/marshal/shared/load.rb11
-rw-r--r--version.h2
3 files changed, 30 insertions, 3 deletions
diff --git a/marshal.c b/marshal.c
index c5327fca60..2018e30ea6 100644
--- a/marshal.c
+++ b/marshal.c
@@ -1729,6 +1729,20 @@ r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod)
return r_object_for(arg, partial, ivp, extmod, type);
}
+static int
+r_move_ivar(st_data_t k, st_data_t v, st_data_t d)
+{
+ ID key = (ID)k;
+ VALUE value = (VALUE)v;
+ VALUE dest = (VALUE)d;
+
+ if (rb_is_instance_id(key)) {
+ rb_ivar_set(dest, key, value);
+ return ST_DELETE;
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type)
{
@@ -1752,7 +1766,6 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
case TYPE_IVAR:
{
int ivar = TRUE;
-
v = r_object0(arg, true, &ivar, extmod);
if (ivar) r_ivar(v, NULL, arg);
v = r_leave(v, arg, partial);
@@ -1926,7 +1939,10 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
}
rb_str_set_len(str, dst - ptr);
}
- v = r_entry0(rb_reg_new_str(str, options), idx, arg);
+ VALUE regexp = rb_reg_new_str(str, options);
+ rb_ivar_foreach(str, r_move_ivar, regexp);
+
+ v = r_entry0(regexp, idx, arg);
v = r_leave(v, arg, partial);
}
break;
diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb
index b70bca55bf..3a1eb72676 100644
--- a/spec/ruby/core/marshal/shared/load.rb
+++ b/spec/ruby/core/marshal/shared/load.rb
@@ -803,6 +803,17 @@ describe :marshal_load, shared: true do
new_obj_metaclass_ancestors[@num_self_class, 3].should ==
[Meths, UserRegexp, Regexp]
end
+
+ ruby_bug "#19439", ""..."3.3" do
+ it "restore the regexp instance variables" do
+ obj = Regexp.new("hello")
+ obj.instance_variable_set(:@regexp_ivar, [42])
+
+ new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
+ new_obj.instance_variables.should == [:@regexp_ivar]
+ new_obj.instance_variable_get(:@regexp_ivar).should == [42]
+ end
+ end
end
describe "for a Float" do
diff --git a/version.h b/version.h
index eaa8fcab68..8d8f6003d9 100644
--- a/version.h
+++ b/version.h
@@ -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 224
+#define RUBY_PATCHLEVEL 225
#define RUBY_RELEASE_YEAR 2023
#define RUBY_RELEASE_MONTH 6