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

ruby-changes:58236

From: Jeremy <ko1@a...>
Date: Mon, 14 Oct 2019 14:20:50 +0900 (JST)
Subject: [ruby-changes:58236] d0ed935d5b (master): Fix some DRb issues (#2552)

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

From d0ed935d5bf8c3fce9800742a36e44fb7f63dda4 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Sun, 13 Oct 2019 22:20:32 -0700
Subject: Fix some DRb issues (#2552)

* Handle BasicObject in drb

Also fix a bug in rescue clause of any_to_s because sprintf
does not handle the %l modifier.

Fixes [Bug #7833]

* Do not send a reply to the client if there is a connection error

This allows for normal TCP shutdown (fin-ack-fin-ack instead of
fin-ack-push-rst).

Patch from pierre@m... (Pierre-Alexandre Meyer).

Fixes [Bug #2339]

* Detect fork and do not reuse forked connections in drb

This associates each DRbConn with a pid, and if the pid changes,
it closes any DRbConns in the pool with a pid that no longer
matches.  This fixes DRb servers from sending messages intended
for one client to another client after forking.

Fixes [Bug #2718]
Fixes [Bug #14471]

diff --git a/lib/drb/drb.rb b/lib/drb/drb.rb
index caffd5d..8c2ef63 100644
--- a/lib/drb/drb.rb
+++ b/lib/drb/drb.rb
@@ -377,7 +377,12 @@ module DRb https://github.com/ruby/ruby/blob/trunk/lib/drb/drb.rb#L377
     # This implementation returns the object's __id__ in the local
     # object space.
     def to_id(obj)
-      obj.nil? ? nil : obj.__id__
+      case obj
+      when Object
+        obj.nil? ? nil : obj.__id__
+      when BasicObject
+        obj.__id__
+      end
     end
   end
 
@@ -560,7 +565,14 @@ module DRb https://github.com/ruby/ruby/blob/trunk/lib/drb/drb.rb#L565
     end
 
     def dump(obj, error=false)  # :nodoc:
-      obj = make_proxy(obj, error) if obj.kind_of? DRbUndumped
+      case obj
+      when DRbUndumped
+        obj = make_proxy(obj, error)
+      when Object
+        # nothing
+      else
+        obj = make_proxy(obj, error)
+      end
       begin
         str = Marshal::dump(obj)
       rescue
@@ -1092,7 +1104,14 @@ module DRb https://github.com/ruby/ruby/blob/trunk/lib/drb/drb.rb#L1104
     def initialize(obj, uri=nil)
       @uri = nil
       @ref = nil
-      if obj.nil?
+      case obj
+      when Object
+        is_nil = obj.nil?
+      when BasicObject
+        is_nil = false
+      end
+
+      if is_nil
         return if uri.nil?
         @uri, option = DRbProtocol.uri_option(uri, DRb.config)
         @ref = DRbURIOption.new(option) unless option.nil?
@@ -1209,15 +1228,20 @@ module DRb https://github.com/ruby/ruby/blob/trunk/lib/drb/drb.rb#L1228
     def self.open(remote_uri)  # :nodoc:
       begin
         conn = nil
+        pid = $$
 
         @mutex.synchronize do
           #FIXME
           new_pool = []
           @pool.each do |c|
-            if conn.nil? and c.uri == remote_uri
-              conn = c if c.alive?
+            if c.pid == pid
+              if conn.nil? and c.uri == remote_uri
+                conn = c if c.alive?
+              else
+                new_pool.push c
+              end
             else
-              new_pool.push c
+              c.close
             end
           end
           @pool = new_pool
@@ -1243,9 +1267,11 @@ module DRb https://github.com/ruby/ruby/blob/trunk/lib/drb/drb.rb#L1267
 
     def initialize(remote_uri)  # :nodoc:
       @uri = remote_uri
+      @pid = $$
       @protocol = DRbProtocol.open(remote_uri, DRb.config)
     end
     attr_reader :uri  # :nodoc:
+    attr_reader :pid  # :nodoc:
 
     def send_message(ref, msg_id, arg, block)  # :nodoc:
       @protocol.send_request(ref, msg_id, arg, block)
@@ -1527,7 +1553,13 @@ module DRb https://github.com/ruby/ruby/blob/trunk/lib/drb/drb.rb#L1553
     def any_to_s(obj)
       obj.to_s + ":#{obj.class}"
     rescue
-      sprintf("#<%s:0x%lx>", obj.class, obj.__id__)
+      case obj
+      when Object
+        klass = obj.class
+      else
+        klass = Kernel.instance_method(:class).bind(obj).call
+      end
+      sprintf("#<%s:0x%dx>", klass, obj.__id__)
     end
 
     # Check that a method is callable via dRuby.
@@ -1543,14 +1575,27 @@ module DRb https://github.com/ruby/ruby/blob/trunk/lib/drb/drb.rb#L1575
       raise(ArgumentError, "#{any_to_s(msg_id)} is not a symbol") unless Symbol == msg_id.class
       raise(SecurityError, "insecure method `#{msg_id}'") if insecure_method?(msg_id)
 
-      if obj.private_methods.include?(msg_id)
-        desc = any_to_s(obj)
-        raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
-      elsif obj.protected_methods.include?(msg_id)
-        desc = any_to_s(obj)
-        raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
+      case obj
+      when Object
+        if obj.private_methods.include?(msg_id)
+          desc = any_to_s(obj)
+          raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
+        elsif obj.protected_methods.include?(msg_id)
+          desc = any_to_s(obj)
+          raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
+        else
+          true
+        end
       else
-        true
+        if Kernel.instance_method(:private_methods).bind(obj).call.include?(msg_id)
+          desc = any_to_s(obj)
+          raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
+        elsif Kernel.instance_method(:protected_methods).bind(obj).call.include?(msg_id)
+          desc = any_to_s(obj)
+          raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
+        else
+          true
+        end
       end
     end
     public :check_insecure_method
@@ -1596,8 +1641,11 @@ module DRb https://github.com/ruby/ruby/blob/trunk/lib/drb/drb.rb#L1641
           end
         end
         @succ = true
-        if @msg_id == :to_ary && @result.class == Array
-          @result = DRbArray.new(@result)
+        case @result
+        when Array
+          if @msg_id == :to_ary
+            @result = DRbArray.new(@result)
+          end
         end
         return @succ, @result
       rescue StandardError, ScriptError, Interrupt
@@ -1678,7 +1726,9 @@ module DRb https://github.com/ruby/ruby/blob/trunk/lib/drb/drb.rb#L1726
             invoke_method = InvokeMethod.new(self, client)
             succ, result = invoke_method.perform
             error_print(result) if !succ && verbose
-            client.send_reply(succ, result)
+            unless DRbConnError === result && result.message == 'connection closed'
+              client.send_reply(succ, result)
+            end
           rescue Exception => e
             error_print(e) if verbose
           ensure
diff --git a/test/drb/drbtest.rb b/test/drb/drbtest.rb
index 9ac3e08..6b8cd5d 100644
--- a/test/drb/drbtest.rb
+++ b/test/drb/drbtest.rb
@@ -158,6 +158,14 @@ module DRbCore https://github.com/ruby/ruby/blob/trunk/test/drb/drbtest.rb#L158
     end
   end
 
+  def test_02_basic_object
+    obj = @there.basic_object
+    assert_kind_of(DRb::DRbObject, obj)
+    assert_equal(1, obj.foo)
+    assert_raise(NoMethodError){obj.prot}
+    assert_raise(NoMethodError){obj.priv}
+  end
+
   def test_02_unknown
     obj = @there.unknown_class
     assert_kind_of(DRb::DRbUnknown, obj)
diff --git a/test/drb/ut_drb.rb b/test/drb/ut_drb.rb
index 6a94a0f..b1306d0 100644
--- a/test/drb/ut_drb.rb
+++ b/test/drb/ut_drb.rb
@@ -63,6 +63,15 @@ class DRbEx https://github.com/ruby/ruby/blob/trunk/test/drb/ut_drb.rb#L63
     FooBar.new
   end
 
+  class BO < ::BasicObject
+    def foo; 1 end
+    protected def prot; 2; end
+    private def priv; 3; end
+  end
+  def basic_object
+    BO.new
+  end
+
   def unknown_class
     Unknown2.new
   end
-- 
cgit v0.10.2


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

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