summaryrefslogtreecommitdiff
path: root/marshal.c
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2021-10-09 15:05:24 +0900
committernagachika <nagachika@ruby-lang.org>2021-10-09 15:05:24 +0900
commitfe9d33beb78d5c7932a5c2ca3953045c0ae751d5 (patch)
tree3481e3a7b27b2cd5fdb1775ac3e9239c1cc8c32e /marshal.c
parentf192e01233ccd7966721a164e62a86707b4e6d9e (diff)
merge revision(s) 89242279e61b023a81c58065c62a82de8829d0b3,529fc204af84f825f98f83c34b004acbaa802615: [Backport #18141]
Marshal.load: do not call the proc until strings have their encoding Ref: https://bugs.ruby-lang.org/issues/18141 --- marshal.c | 7 +++- spec/ruby/core/marshal/shared/load.rb | 62 +++++++++++++++++++++++------------ test/ruby/test_marshal.rb | 17 ++++++++++ 3 files changed, 64 insertions(+), 22 deletions(-) marshal.c: don't call the proc with partially initialized objects. (#4866) For cyclic objects, it requires to keep a st_table of the partially initialized objects. --- marshal.c | 75 ++++++++++++++++++++--------------- spec/ruby/core/marshal/shared/load.rb | 75 ++++++++++++++++++++--------------- test/ruby/test_marshal.rb | 12 ++++++ 3 files changed, 97 insertions(+), 65 deletions(-)
Diffstat (limited to 'marshal.c')
-rw-r--r--marshal.c70
1 files changed, 42 insertions, 28 deletions
diff --git a/marshal.c b/marshal.c
index 5f0ac7e7bb..ed096f52fe 100644
--- a/marshal.c
+++ b/marshal.c
@@ -1137,6 +1137,7 @@ struct load_arg {
long offset;
st_table *symbols;
st_table *data;
+ st_table *partial_objects;
VALUE proc;
st_table *compat_tbl;
};
@@ -1163,6 +1164,7 @@ mark_load_arg(void *ptr)
return;
rb_mark_tbl(p->symbols);
rb_mark_tbl(p->data);
+ rb_mark_tbl(p->partial_objects);
rb_mark_hash(p->compat_tbl);
}
@@ -1516,6 +1518,7 @@ r_entry0(VALUE v, st_index_t num, struct load_arg *arg)
st_lookup(arg->compat_tbl, v, &real_obj);
}
st_insert(arg->data, num, real_obj);
+ st_insert(arg->partial_objects, (st_data_t)real_obj, Qtrue);
return v;
}
@@ -1546,10 +1549,15 @@ r_post_proc(VALUE v, struct load_arg *arg)
}
static VALUE
-r_leave(VALUE v, struct load_arg *arg)
+r_leave(VALUE v, struct load_arg *arg, bool partial)
{
v = r_fixup_compat(v, arg);
- v = r_post_proc(v, arg);
+ if (!partial) {
+ st_data_t data;
+ st_data_t key = (st_data_t)v;
+ st_delete(arg->partial_objects, &key, &data);
+ v = r_post_proc(v, arg);
+ }
return v;
}
@@ -1676,7 +1684,7 @@ append_extmod(VALUE obj, VALUE extmod)
} while (0)
static VALUE
-r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
+r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod)
{
VALUE v = Qnil;
int type = r_byte(arg);
@@ -1690,15 +1698,18 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
rb_raise(rb_eArgError, "dump format error (unlinked)");
}
v = (VALUE)link;
- v = r_post_proc(v, arg);
+ if (!st_lookup(arg->partial_objects, (st_data_t)v, &link)) {
+ v = r_post_proc(v, arg);
+ }
break;
case TYPE_IVAR:
{
int ivar = TRUE;
- v = r_object0(arg, &ivar, extmod);
+ v = r_object0(arg, true, &ivar, extmod);
if (ivar) r_ivar(v, NULL, arg);
+ v = r_leave(v, arg, partial);
}
break;
@@ -1711,7 +1722,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
if (RB_TYPE_P(m, T_CLASS)) { /* prepended */
VALUE c;
- v = r_object0(arg, 0, Qnil);
+ v = r_object0(arg, true, 0, Qnil);
c = CLASS_OF(v);
if (c != m || FL_TEST(c, FL_SINGLETON)) {
rb_raise(rb_eArgError,
@@ -1728,7 +1739,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
must_be_module(m, path);
rb_ary_push(extmod, m);
- v = r_object0(arg, 0, extmod);
+ v = r_object0(arg, true, 0, extmod);
while (RARRAY_LEN(extmod) > 0) {
m = rb_ary_pop(extmod);
rb_extend_object(v, m);
@@ -1744,7 +1755,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
if (FL_TEST(c, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "singleton can't be loaded");
}
- v = r_object0(arg, 0, extmod);
+ v = r_object0(arg, partial, 0, extmod);
if (rb_special_const_p(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS)) {
goto format_error;
}
@@ -1762,17 +1773,17 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
case TYPE_NIL:
v = Qnil;
- v = r_leave(v, arg);
+ v = r_leave(v, arg, false);
break;
case TYPE_TRUE:
v = Qtrue;
- v = r_leave(v, arg);
+ v = r_leave(v, arg, false);
break;
case TYPE_FALSE:
v = Qfalse;
- v = r_leave(v, arg);
+ v = r_leave(v, arg, false);
break;
case TYPE_FIXNUM:
@@ -1780,7 +1791,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
long i = r_long(arg);
v = LONG2FIX(i);
}
- v = r_leave(v, arg);
+ v = r_leave(v, arg, false);
break;
case TYPE_FLOAT:
@@ -1805,7 +1816,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
}
v = DBL2NUM(d);
v = r_entry(v, arg);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, false);
}
break;
@@ -1822,13 +1833,13 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
INTEGER_PACK_LITTLE_ENDIAN | (sign == '-' ? INTEGER_PACK_NEGATIVE : 0));
rb_str_resize(data, 0L);
v = r_entry(v, arg);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, false);
}
break;
case TYPE_STRING:
v = r_entry(r_string(arg), arg);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
break;
case TYPE_REGEXP:
@@ -1863,7 +1874,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
rb_str_set_len(str, dst - ptr);
}
v = r_entry0(rb_reg_new_str(str, options), idx, arg);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
}
break;
@@ -1878,7 +1889,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
rb_ary_push(v, r_object(arg));
arg->readable--;
}
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
arg->readable++;
}
break;
@@ -1901,7 +1912,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
if (type == TYPE_HASH_DEF) {
RHASH_SET_IFNONE(v, r_object(arg));
}
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
}
break;
@@ -1953,7 +1964,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
}
}
rb_struct_initialize(v, values);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
arg->readable += 2;
}
break;
@@ -1980,7 +1991,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
marshal_compat_t *compat = (marshal_compat_t*)d;
v = compat->loader(klass, v);
}
- v = r_post_proc(v, arg);
+ if (!partial) v = r_post_proc(v, arg);
}
break;
@@ -2022,7 +2033,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
}
v = r_entry0(v, idx, arg);
r_ivar(v, NULL, arg);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
}
break;
@@ -2043,9 +2054,9 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
"class %"PRIsVALUE" needs to have instance method `_load_data'",
name);
}
- r = r_object0(arg, 0, extmod);
+ r = r_object0(arg, partial, 0, extmod);
load_funcall(arg, v, s_load_data, 1, &r);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
}
break;
@@ -2056,7 +2067,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
v = rb_path_to_class(str);
prohibit_ivar("class/module", str);
v = r_entry(v, arg);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
}
break;
@@ -2067,7 +2078,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
v = path2class(str);
prohibit_ivar("class", str);
v = r_entry(v, arg);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
}
break;
@@ -2078,7 +2089,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
v = path2module(str);
prohibit_ivar("module", str);
v = r_entry(v, arg);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
}
break;
@@ -2091,7 +2102,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
v = r_symreal(arg, 0);
}
v = rb_str_intern(v);
- v = r_leave(v, arg);
+ v = r_leave(v, arg, partial);
break;
case TYPE_SYMLINK:
@@ -2113,7 +2124,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
static VALUE
r_object(struct load_arg *arg)
{
- return r_object0(arg, 0, Qnil);
+ return r_object0(arg, false, 0, Qnil);
}
static void
@@ -2131,6 +2142,8 @@ clear_load_arg(struct load_arg *arg)
arg->symbols = 0;
st_free_table(arg->data);
arg->data = 0;
+ st_free_table(arg->partial_objects);
+ arg->partial_objects = 0;
if (arg->compat_tbl) {
st_free_table(arg->compat_tbl);
arg->compat_tbl = 0;
@@ -2185,6 +2198,7 @@ rb_marshal_load_with_proc(VALUE port, VALUE proc)
arg->offset = 0;
arg->symbols = st_init_numtable();
arg->data = rb_init_identtable();
+ arg->partial_objects = rb_init_identtable();
arg->compat_tbl = 0;
arg->proc = 0;
arg->readable = 0;