summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--ext/-test-/marshal/compat/extconf.rb1
-rw-r--r--ext/-test-/marshal/compat/usrcompat.c32
-rw-r--r--ext/-test-/marshal/usr/extconf.rb1
-rw-r--r--ext/-test-/marshal/usr/usrmarshal.c35
-rw-r--r--marshal.c41
-rw-r--r--test/-ext-/marshal/test_usrmarshal.rb34
7 files changed, 138 insertions, 11 deletions
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 <nobu@ruby-lang.org>
+
+ * marshal.c (r_object0): also load TYPE_USRMARSHAL, TYPE_DATA using
+ compatible loader.
+
Mon Jun 4 11:33:42 2012 NAKAMURA Usaku <usa@ruby-lang.org>
* 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 <ruby.h>
+
+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 <ruby.h>
+
+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;
}
@@ -1314,6 +1312,23 @@ obj_alloc_by_path(VALUE path, struct load_arg *arg)
}
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)
{
VALUE v = Qnil;
@@ -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