diff --git a/marshal.c b/marshal.c index af952048af..cdf25df5aa 100644 --- a/marshal.c +++ b/marshal.c @@ -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); @@ -2020,7 +2033,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 8fdfedd746..1df2e8d4f1 100644 --- a/spec/ruby/core/marshal/shared/load.rb +++ b/spec/ruby/core/marshal/shared/load.rb @@ -740,6 +740,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