[前][次][番号順一覧][スレッド一覧]

ruby-changes:60586

From: usa <ko1@a...>
Date: Tue, 31 Mar 2020 06:22:07 +0900 (JST)
Subject: [ruby-changes:60586] ec3e09c1eb (ruby_2_5): merge revision(s) c9423b016cfeab852bc5a829e55e0a11f80b3ab7,0b1e26398e018116180bf41cb63887f77d5d1b82,78ee2c245331e353e218b8fac9ca722a2bcd8fea: [Backport #15968]

https://git.ruby-lang.org/ruby.git/commit/?id=ec3e09c1eb

From ec3e09c1eb4e8bef71a15213be777ead424aa9d7 Mon Sep 17 00:00:00 2001
From: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Mon, 30 Mar 2020 21:21:53 +0000
Subject: merge revision(s)
 c9423b016cfeab852bc5a829e55e0a11f80b3ab7,0b1e26398e018116180bf41cb63887f77d5d1b82,78ee2c245331e353e218b8fac9ca722a2bcd8fea:
 [Backport #15968]

	marshal.c: check instance variable count

	* marshal.c (w_obj_each): ensure that no instance variable was
	  added while dumping other instance variables.  [Bug #15968]

	Hoisted out w_ivar_each


	marshal.c: check instance variable count

	* marshal.c (w_ivar_each): ensure that no instance variable was
	  removed while dumping other instance variables.  [Bug #15968]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_5@67861 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

diff --git a/marshal.c b/marshal.c
index 1593ca2..d89ccf5 100644
--- a/marshal.c
+++ b/marshal.c
@@ -553,14 +553,25 @@ w_uclass(VALUE obj, VALUE super, struct dump_arg *arg) https://github.com/ruby/ruby/blob/trunk/marshal.c#L553
 
 #define to_be_skipped_id(id) (id == rb_id_encoding() || id == rb_intern("E") || !rb_id2str(id))
 
+struct w_ivar_arg {
+    struct dump_call_arg *dump;
+    st_data_t num_ivar;
+};
+
 static int
 w_obj_each(st_data_t key, st_data_t val, st_data_t a)
 {
     ID id = (ID)key;
     VALUE value = (VALUE)val;
-    struct dump_call_arg *arg = (struct dump_call_arg *)a;
+    struct w_ivar_arg *ivarg = (struct w_ivar_arg *)a;
+    struct dump_call_arg *arg = ivarg->dump;
 
     if (to_be_skipped_id(id)) return ST_CONTINUE;
+    if (!ivarg->num_ivar) {
+        rb_raise(rb_eRuntimeError, "instance variable added to %"PRIsVALUE" instance",
+                 CLASS_OF(arg->obj));
+    }
+    --ivarg->num_ivar;
     w_symbol(ID2SYM(id), arg->arg);
     w_object(value, arg->arg, arg->limit);
     return ST_CONTINUE;
@@ -641,12 +652,20 @@ has_ivars(VALUE obj, VALUE encname, VALUE *ivobj) https://github.com/ruby/ruby/blob/trunk/marshal.c#L652
 }
 
 static void
+w_ivar_each(VALUE obj, st_index_t num, struct dump_call_arg *arg)
+{
+    struct w_ivar_arg ivarg = {arg, num};
+    if (!num) return;
+    rb_ivar_foreach(obj, w_obj_each, (st_data_t)&ivarg);
+}
+
+static void
 w_ivar(st_index_t num, VALUE ivobj, VALUE encname, struct dump_call_arg *arg)
 {
     w_long(num, arg->arg);
     w_encoding(encname, arg);
     if (ivobj != Qundef) {
-	rb_ivar_foreach(ivobj, w_obj_each, (st_data_t)arg);
+        w_ivar_each(ivobj, num, arg);
     }
 }
 
@@ -657,9 +676,7 @@ w_objivar(VALUE obj, struct dump_call_arg *arg) https://github.com/ruby/ruby/blob/trunk/marshal.c#L676
 
     rb_ivar_foreach(obj, obj_count_ivars, (st_data_t)&num);
     w_long(num, arg->arg);
-    if (num != 0) {
-        rb_ivar_foreach(obj, w_obj_each, (st_data_t)arg);
-    }
+    w_ivar_each(obj, num, arg);
 }
 
 static void
@@ -678,6 +695,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) https://github.com/ruby/ruby/blob/trunk/marshal.c#L695
     if (limit > 0) limit--;
     c_arg.limit = limit;
     c_arg.arg = arg;
+    c_arg.obj = obj;
 
     if (st_lookup(arg->data, obj, &num)) {
 	w_byte(TYPE_LINK, arg);
diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb
index e269428..0565a1c 100644
--- a/test/ruby/test_marshal.rb
+++ b/test/ruby/test_marshal.rb
@@ -779,4 +779,36 @@ class TestMarshal < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_marshal.rb#L779
     obj = Bug14314.new(foo: 42)
     assert_equal obj, Marshal.load(Marshal.dump(obj))
   end
+
+  class Bug15968
+    attr_accessor :bar, :baz
+
+    def initialize
+      self.bar = Bar.new(self)
+    end
+
+    class Bar
+      attr_accessor :foo
+
+      def initialize(foo)
+        self.foo = foo
+      end
+
+      def marshal_dump
+        self.foo.baz = :problem
+        {foo: self.foo}
+      end
+
+      def marshal_load(data)
+        self.foo = data[:foo]
+      end
+    end
+  end
+
+  def test_marshal_dump_adding_instance_variable
+    obj = Bug15968.new
+    assert_raise_with_message(RuntimeError, /instance variable added/) do
+      Marshal.dump(obj)
+    end
+  end
 end
diff --git a/version.h b/version.h
index 5d42d30..162d8d1 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/version.h#L1
 #define RUBY_VERSION "2.5.8"
 #define RUBY_RELEASE_DATE "2020-03-31"
-#define RUBY_PATCHLEVEL 210
+#define RUBY_PATCHLEVEL 211
 
 #define RUBY_RELEASE_YEAR 2020
 #define RUBY_RELEASE_MONTH 3
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]