summaryrefslogtreecommitdiff
path: root/marshal.c
diff options
context:
space:
mode:
authorJean Boussier <byroot@ruby-lang.org>2023-02-16 12:18:27 +0100
committerJean Boussier <jean.boussier@gmail.com>2023-02-21 13:57:04 +0100
commitd2520b7b76759118071a16e6bca22726a5de9fb4 (patch)
treecbd1eb444fe832a52f8133b0be3141440ce13a92 /marshal.c
parent61709227bbcdb354463861653057315ae977f1a3 (diff)
downloadruby-d2520b7b76759118071a16e6bca22726a5de9fb4.tar.gz
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.
Diffstat (limited to 'marshal.c')
-rw-r--r--marshal.c20
1 files changed, 18 insertions, 2 deletions
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;