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

ruby-changes:59253

From: nagachika <ko1@a...>
Date: Sun, 15 Dec 2019 16:15:02 +0900 (JST)
Subject: [ruby-changes:59253] ec2934d504 (ruby_2_6): merge revision(s) c9423b016cfeab852bc5a829e55e0a11f80b3ab7,0b1e26398e018116180bf41cb63887f77d5d1b82,78ee2c245331e353e218b8fac9ca722a2bcd8fea: [Backport #15968]

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

From ec2934d5048d8f3f0bff32eeddf9f244fa407397 Mon Sep 17 00:00:00 2001
From: nagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Sun, 15 Dec 2019 07:14:45 +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_6@67832 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

diff --git a/marshal.c b/marshal.c
index 73d36e2..bb5b1a9 100644
--- a/marshal.c
+++ b/marshal.c
@@ -257,7 +257,7 @@ class2path(VALUE klass) https://github.com/ruby/ruby/blob/trunk/marshal.c#L257
 }
 
 static void w_long(long, struct dump_arg*);
-static void w_encoding(VALUE encname, struct dump_call_arg *arg);
+static int w_encoding(VALUE encname, struct dump_call_arg *arg);
 static VALUE encoding_name(VALUE obj, struct dump_arg *arg);
 
 static void
@@ -550,14 +550,25 @@ w_uclass(VALUE obj, VALUE super, struct dump_arg *arg) https://github.com/ruby/ruby/blob/trunk/marshal.c#L550
 
 #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;
@@ -604,7 +615,7 @@ encoding_name(VALUE obj, struct dump_arg *arg) https://github.com/ruby/ruby/blob/trunk/marshal.c#L615
     }
 }
 
-static void
+static int
 w_encoding(VALUE encname, struct dump_call_arg *arg)
 {
     int limit = arg->limit;
@@ -614,11 +625,13 @@ w_encoding(VALUE encname, struct dump_call_arg *arg) https://github.com/ruby/ruby/blob/trunk/marshal.c#L625
       case Qtrue:
 	w_symbol(ID2SYM(rb_intern("E")), arg->arg);
 	w_object(encname, arg->arg, limit);
+        return 1;
       case Qnil:
-	return;
+	return 0;
     }
     w_symbol(ID2SYM(rb_id_encoding()), arg->arg);
     w_object(encname, arg->arg, limit);
+    return 1;
 }
 
 static st_index_t
@@ -643,12 +656,24 @@ has_ivars(VALUE obj, VALUE encname, VALUE *ivobj) https://github.com/ruby/ruby/blob/trunk/marshal.c#L656
 }
 
 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);
+    if (ivarg.num_ivar) {
+        rb_raise(rb_eRuntimeError, "instance variable removed from %"PRIsVALUE" instance",
+                 CLASS_OF(arg->obj));
+    }
+}
+
+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);
+    num -= w_encoding(encname, arg);
     if (ivobj != Qundef) {
-	rb_ivar_foreach(ivobj, w_obj_each, (st_data_t)arg);
+        w_ivar_each(ivobj, num, arg);
     }
 }
 
@@ -659,9 +684,7 @@ w_objivar(VALUE obj, struct dump_call_arg *arg) https://github.com/ruby/ruby/blob/trunk/marshal.c#L684
 
     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
@@ -680,6 +703,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) https://github.com/ruby/ruby/blob/trunk/marshal.c#L703
     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..f6d84d1 100644
--- a/test/ruby/test_marshal.rb
+++ b/test/ruby/test_marshal.rb
@@ -779,4 +779,48 @@ 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
+        if self.foo.baz
+          self.foo.remove_instance_variable(:@baz)
+        else
+          self.foo.baz = :problem
+        end
+        {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
+
+  def test_marshal_dump_removing_instance_variable
+    obj = Bug15968.new
+    obj.baz = :Bug15968
+    assert_raise_with_message(RuntimeError, /instance variable removed/) do
+      Marshal.dump(obj)
+    end
+  end
 end
diff --git a/version.h b/version.h
index d9885ec..0af5aba 100644
--- a/version.h
+++ b/version.h
@@ -1,10 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/version.h#L1
 #define RUBY_VERSION "2.6.6"
 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 119
+#define RUBY_PATCHLEVEL 120
 
 #define RUBY_RELEASE_YEAR 2019
 #define RUBY_RELEASE_MONTH 12
-#define RUBY_RELEASE_DAY 9
+#define RUBY_RELEASE_DAY 15
 
 #include "ruby/version.h"
 
-- 
cgit v0.10.2


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

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