From 0316cf2e523d9f77e610477697d5a93842b4d4bd Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 8 Mar 2013 15:26:08 +0000 Subject: marshal.c: prepended objects * marshal.c (r_object0): load prepended objects. treat the class of extended object in the included modules as prepended singleton class. [ruby-core:53202] [Bug #8041] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@39642 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++++++ marshal.c | 46 ++++++++++++++++++++++++++++++++------------- test/ruby/marshaltestlib.rb | 10 ++++++++++ 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 59426a840a..005f543b9b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Sat Mar 9 00:25:57 2013 Nobuyoshi Nakada + + * marshal.c (r_object0): load prepended objects. treat the class of + extended object in the included modules as prepended singleton + class. [ruby-core:53202] [Bug #8041] + Fri Mar 8 19:44:00 2013 Akinori MUSHA * man/rake.1, man/ruby.1: Use the Pa macro to make URLs stand out. diff --git a/marshal.c b/marshal.c index 13f01c003c..7b45d1c835 100644 --- a/marshal.c +++ b/marshal.c @@ -1387,11 +1387,11 @@ path2class(VALUE path) return v; } +#define path2module(path) must_be_module(rb_path_to_class(path), path) + static VALUE -path2module(VALUE path) +must_be_module(VALUE v, VALUE path) { - VALUE v = rb_path_to_class(path); - if (!RB_TYPE_P(v, T_MODULE)) { rb_raise(rb_eArgError, "%"PRIsVALUE" does not refer to module", path); } @@ -1473,16 +1473,36 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) case TYPE_EXTENDED: { - VALUE m = path2module(r_unique(arg)); - - if (NIL_P(extmod)) extmod = rb_ary_tmp_new(0); - rb_ary_push(extmod, m); - - v = r_object0(arg, 0, extmod); - while (RARRAY_LEN(extmod) > 0) { - m = rb_ary_pop(extmod); - rb_extend_object(v, m); - } + VALUE path = r_unique(arg); + VALUE m = rb_path_to_class(path); + + if (RB_TYPE_P(m, T_CLASS)) { /* prepended */ + VALUE c; + + v = r_object0(arg, 0, Qnil); + c = CLASS_OF(v); + if (c != m || FL_TEST(c, FL_SINGLETON)) { + rb_raise(rb_eArgError, + "prepended class %"PRIsVALUE" differs from class %"PRIsVALUE, + path, rb_class_name(c)); + } + c = rb_singleton_class(v); + while (RARRAY_LEN(extmod) > 0) { + m = rb_ary_pop(extmod); + rb_prepend_module(c, m); + } + } + else { + must_be_module(m, path); + if (NIL_P(extmod)) extmod = rb_ary_tmp_new(0); + rb_ary_push(extmod, m); + + v = r_object0(arg, 0, extmod); + while (RARRAY_LEN(extmod) > 0) { + m = rb_ary_pop(extmod); + rb_extend_object(v, m); + } + } } break; diff --git a/test/ruby/marshaltestlib.rb b/test/ruby/marshaltestlib.rb index f14209fc19..45c94e0f15 100644 --- a/test/ruby/marshaltestlib.rb +++ b/test/ruby/marshaltestlib.rb @@ -75,6 +75,16 @@ module MarshalTestLib marshal_equal_with_ancestry(o1) end + def test_object_prepend + bug8041 = '[ruby-core:53202] [Bug #8041]' + + o1 = MyObject.new(42) + o1.singleton_class.class_eval {prepend Mod1} + assert_nothing_raised(ArgumentError, bug8041) { + marshal_equal_with_ancestry(o1, bug8041) + } + end + class MyArray < Array def initialize(v, *args) super(args) -- cgit v1.2.3