diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | marshal.c | 11 | ||||
-rw-r--r-- | test/ruby/test_marshal.rb | 20 | ||||
-rw-r--r-- | variable.c | 38 |
4 files changed, 75 insertions, 1 deletions
@@ -1,3 +1,10 @@ +Sat Dec 5 15:35:05 2009 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * marshal.c (w_object): dump instance variables when using + marshal_dump. [ruby-core:24211] + + * variable.c (rb_ivar_count): added. + Sat Dec 5 13:19:29 2009 Nobuyoshi Nakada <nobu@ruby-lang.org> * configure.in: default ac_cv_prog_CC to CC. @@ -643,14 +643,23 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) if (rb_respond_to(obj, s_mdump)) { volatile VALUE v; + int hasiv2 = 0; st_add_direct(arg->data, obj, arg->data->num_entries); v = rb_funcall(obj, s_mdump, 0, 0); check_dump_arg(arg, s_mdump); + if (!hasiv && (hasiv2 = rb_ivar_count(obj) > 0)) { + w_byte(TYPE_IVAR, arg); + } w_class(TYPE_USRMARSHAL, obj, arg, FALSE); w_object(v, arg, limit); - if (hasiv) w_ivar(obj, 0, &c_arg); + if (hasiv) { + w_ivar(obj, ivtbl, &c_arg); + } + else if (hasiv2) { + w_objivar(obj, &c_arg); + } return; } if (rb_respond_to(obj, s_dump)) { diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb index 0b37b7ab17..71936ec147 100644 --- a/test/ruby/test_marshal.rb +++ b/test/ruby/test_marshal.rb @@ -310,4 +310,24 @@ class TestMarshal < Test::Unit::TestCase Marshal.dump(Object.new, w) assert_not_empty(w, bug2390) end + + class C5 + def marshal_dump + "foo" + end + def marshal_load(foo) + @foo = foo + end + def initialize(x) + @x = x + end + end + def test_marshal_dump + bug1744 = '[ruby-core:24211]' + c = C5.new("bar") + s = Marshal.dump(c) + d = Marshal.load(s) + assert_equal("foo", d.instance_variable_get(:@foo), bug1744) + assert_equal("bar", d.instance_variable_get(:@x), bug1744) + end end diff --git a/variable.c b/variable.c index ddeae93a1b..62256a049e 100644 --- a/variable.c +++ b/variable.c @@ -1197,6 +1197,44 @@ rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg) } } +st_index_t +rb_ivar_count(VALUE obj) +{ + st_table *tbl; + switch (TYPE(obj)) { + case T_OBJECT: + if ((tbl = ROBJECT_IV_INDEX_TBL(obj)) != 0) { + st_index_t i, num = tbl->num_entries, count = 0; + const VALUE *const ivptr = ROBJECT_IVPTR(obj); + for (i = count = 0; i < num; ++i) { + if (ivptr[i] != Qundef) { + count++; + } + } + return count; + } + break; + case T_CLASS: + case T_MODULE: + if ((tbl = RCLASS_IV_TBL(obj)) != 0) { + return tbl->num_entries; + } + break; + default: + if (!generic_iv_tbl) break; + if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) { + st_data_t data; + + if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data) && + (tbl = (st_table *)data) != 0) { + return tbl->num_entries; + } + } + break; + } + return 0; +} + static int ivar_i(ID key, VALUE val, VALUE ary) { |