From 81a0c608eb73f1a250ec9ec11107280b8d086ef8 Mon Sep 17 00:00:00 2001 From: nobu Date: Mon, 4 Jun 2012 02:40:30 +0000 Subject: [PATCH] compatible loader * marshal.c (r_object0): also load TYPE_USRMARSHAL, TYPE_DATA using compatible loader. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35898 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 ++++ ext/-test-/marshal/compat/extconf.rb | 1 + ext/-test-/marshal/compat/usrcompat.c | 32 +++++++++++++++++++++ ext/-test-/marshal/usr/extconf.rb | 1 + ext/-test-/marshal/usr/usrmarshal.c | 35 +++++++++++++++++++++++ marshal.c | 41 ++++++++++++++++++++------- test/-ext-/marshal/test_usrmarshal.rb | 34 ++++++++++++++++++++++ 7 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 ext/-test-/marshal/compat/extconf.rb create mode 100644 ext/-test-/marshal/compat/usrcompat.c create mode 100644 ext/-test-/marshal/usr/extconf.rb create mode 100644 ext/-test-/marshal/usr/usrmarshal.c create mode 100644 test/-ext-/marshal/test_usrmarshal.rb diff --git a/ChangeLog b/ChangeLog index 856d390c8b..cfdd9f643e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon Jun 4 11:40:28 2012 Nobuyoshi Nakada + + * marshal.c (r_object0): also load TYPE_USRMARSHAL, TYPE_DATA using + compatible loader. + Mon Jun 4 11:33:42 2012 NAKAMURA Usaku * process.c (rb_run_exec_options_err): restore save_env() call for diff --git a/ext/-test-/marshal/compat/extconf.rb b/ext/-test-/marshal/compat/extconf.rb new file mode 100644 index 0000000000..bb11ebfb8c --- /dev/null +++ b/ext/-test-/marshal/compat/extconf.rb @@ -0,0 +1 @@ +create_makefile("-test-/marshal/compat") diff --git a/ext/-test-/marshal/compat/usrcompat.c b/ext/-test-/marshal/compat/usrcompat.c new file mode 100644 index 0000000000..f812df5631 --- /dev/null +++ b/ext/-test-/marshal/compat/usrcompat.c @@ -0,0 +1,32 @@ +#include + +static VALUE +usr_dumper(VALUE self) +{ + return self; +} + +static VALUE +usr_loader(VALUE self, VALUE m) +{ + VALUE val = rb_ivar_get(m, rb_intern("@value")); + *(int *)DATA_PTR(self) = NUM2INT(val); + return self; +} + +static VALUE +compat_mload(VALUE self, VALUE data) +{ + rb_ivar_set(self, rb_intern("@value"), data); + return self; +} + +void +Init_compat(void) +{ + VALUE newclass = rb_path2class("Bug::Marshal::UsrMarshal"); + VALUE oldclass = rb_define_class_under(newclass, "compat", rb_cObject); + + rb_define_method(oldclass, "marshal_load", compat_mload, 1); + rb_marshal_define_compat(newclass, oldclass, usr_dumper, usr_loader); +} diff --git a/ext/-test-/marshal/usr/extconf.rb b/ext/-test-/marshal/usr/extconf.rb new file mode 100644 index 0000000000..c662b23dd5 --- /dev/null +++ b/ext/-test-/marshal/usr/extconf.rb @@ -0,0 +1 @@ +create_makefile("-test-/marshal/usr") diff --git a/ext/-test-/marshal/usr/usrmarshal.c b/ext/-test-/marshal/usr/usrmarshal.c new file mode 100644 index 0000000000..b30bd52c13 --- /dev/null +++ b/ext/-test-/marshal/usr/usrmarshal.c @@ -0,0 +1,35 @@ +#include + +static VALUE +usr_alloc(VALUE klass) +{ + int *p; + return Data_Make_Struct(klass, int, 0, RUBY_DEFAULT_FREE, p); +} + +static VALUE +usr_init(VALUE self, VALUE val) +{ + *(int *)DATA_PTR(self) = NUM2INT(val); + return self; +} + +static VALUE +usr_value(VALUE self) +{ + int val = *(int *)DATA_PTR(self); + return INT2NUM(val); +} + +void +Init_usr(void) +{ + VALUE mMarshal = rb_define_module_under(rb_define_module("Bug"), "Marshal"); + VALUE newclass = rb_define_class_under(mMarshal, "UsrMarshal", rb_cObject); + + rb_define_alloc_func(newclass, usr_alloc); + rb_define_method(newclass, "initialize", usr_init, 1); + rb_define_method(newclass, "value", usr_value, 0); + rb_define_method(newclass, "marshal_load", usr_init, 1); + rb_define_method(newclass, "marshal_dump", usr_value, 0); +} diff --git a/marshal.c b/marshal.c index c4ee0671ca..c88814eaf4 100644 --- a/marshal.c +++ b/marshal.c @@ -1293,19 +1293,17 @@ path2module(VALUE path) } static VALUE -obj_alloc_by_path(VALUE path, struct load_arg *arg) +obj_alloc_by_klass(VALUE klass, struct load_arg *arg, VALUE *oldclass) { - VALUE klass; st_data_t data; rb_alloc_func_t allocator; - klass = path2class(path); - allocator = rb_get_alloc_func(klass); if (st_lookup(compat_allocator_tbl, (st_data_t)allocator, &data)) { marshal_compat_t *compat = (marshal_compat_t*)data; VALUE real_obj = rb_obj_alloc(klass); VALUE obj = rb_obj_alloc(compat->oldclass); + if (oldclass) *oldclass = compat->oldclass; st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj); return obj; } @@ -1313,6 +1311,23 @@ obj_alloc_by_path(VALUE path, struct load_arg *arg) return rb_obj_alloc(klass); } +static VALUE +obj_alloc_by_path(VALUE path, struct load_arg *arg) +{ + return obj_alloc_by_klass(path2class(path), arg, 0); +} + +static VALUE +append_extmod(VALUE obj, VALUE extmod) +{ + long i = RARRAY_LEN(extmod); + while (i > 0) { + VALUE m = RARRAY_PTR(extmod)[--i]; + rb_extend_object(obj, m); + } + return obj; +} + static VALUE r_object0(struct load_arg *arg, int *ivp, VALUE extmod) { @@ -1347,7 +1362,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) { VALUE m = path2module(r_unique(arg)); - if (NIL_P(extmod)) extmod = rb_ary_new2(0); + if (NIL_P(extmod)) extmod = rb_ary_tmp_new(0); rb_ary_push(extmod, m); v = r_object0(arg, 0, extmod); @@ -1607,14 +1622,13 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) case TYPE_USRMARSHAL: { VALUE klass = path2class(r_unique(arg)); + VALUE oldclass = 0; VALUE data; - v = rb_obj_alloc(klass); + v = obj_alloc_by_klass(klass, arg, &oldclass); if (!NIL_P(extmod)) { - while (RARRAY_LEN(extmod) > 0) { - VALUE m = rb_ary_pop(extmod); - rb_extend_object(v, m); - } + /* for the case marshal_load is overridden */ + append_extmod(v, extmod); } if (!rb_respond_to(v, s_mload)) { rb_raise(rb_eTypeError, "instance of %s needs to have method `marshal_load'", @@ -1625,6 +1639,10 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) rb_funcall(v, s_mload, 1, data); check_load_arg(arg, s_mload); v = r_leave(v, arg); + if (!NIL_P(extmod)) { + if (oldclass) append_extmod(v, extmod); + rb_ary_clear(extmod); + } } break; @@ -1644,8 +1662,9 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) case TYPE_DATA: { VALUE klass = path2class(r_unique(arg)); + VALUE oldclass = 0; - v = rb_obj_alloc(klass); + v = obj_alloc_by_klass(klass, arg, &oldclass); if (!RB_TYPE_P(v, T_DATA)) { rb_raise(rb_eArgError, "dump format error"); } diff --git a/test/-ext-/marshal/test_usrmarshal.rb b/test/-ext-/marshal/test_usrmarshal.rb new file mode 100644 index 0000000000..54adace7d6 --- /dev/null +++ b/test/-ext-/marshal/test_usrmarshal.rb @@ -0,0 +1,34 @@ +require 'test/unit' +require_relative '../../ruby/envutil' +require '-test-/marshal/usr' + +module Bug end + +module Bug::Marshal + class TestUsrMarshal < Test::Unit::TestCase + def old_dump + @old_dump ||= + begin + src = "module Bug; module Marshal; class UsrMarshal; def initialize(val) @value = val; end; end; ::Marshal.dump(UsrMarshal.new(42), STDOUT); end; end" + EnvUtil.invoke_ruby([], src, true)[0] + end + end + + def test_marshal + v = ::Marshal.load(::Marshal.dump(UsrMarshal.new(42))) + assert_instance_of(UsrMarshal, v) + assert_equal(42, v.value) + end + + def test_incompat + e = assert_raise(ArgumentError) {::Marshal.load(old_dump)} + assert_equal("dump format error", e.message) + end + + def test_compat + out, err = EnvUtil.invoke_ruby(["-r-test-/marshal/usr", "-r-test-/marshal/compat", "-e", "::Marshal.dump(::Marshal.load(STDIN), STDOUT)"], old_dump, true, true) + assert_equal(::Marshal.dump(UsrMarshal.new(42)), out) + assert_equal("", err) + end + end +end