diff options
author | NARUSE, Yui <naruse@airemix.jp> | 2023-03-08 14:46:30 +0900 |
---|---|---|
committer | NARUSE, Yui <naruse@airemix.jp> | 2023-03-08 14:46:30 +0900 |
commit | 4e4a4e42b284d9309a7e51c97058093539e7a843 (patch) | |
tree | ce2710dc195ee49e8f41de8b2b68af9b4ca50b23 | |
parent | 59eb18037ff92839be48fb6c46ff0acc179b4f4c (diff) | |
download | ruby-4e4a4e42b284d9309a7e51c97058093539e7a843.tar.gz |
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.c | 20 | ||||
-rw-r--r-- | spec/ruby/core/marshal/shared/load.rb | 11 | ||||
-rw-r--r-- | version.h | 2 |
3 files changed, 30 insertions, 3 deletions
@@ -1803,6 +1803,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) { @@ -1826,7 +1840,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); @@ -2019,7 +2032,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 98fae44296..479c7477ec 100644 --- a/spec/ruby/core/marshal/shared/load.rb +++ b/spec/ruby/core/marshal/shared/load.rb @@ -720,6 +720,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 @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 1 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 37 +#define RUBY_PATCHLEVEL 38 #include "ruby/version.h" #include "ruby/internal/abi.h" |