From d0ed935d5bf8c3fce9800742a36e44fb7f63dda4 Mon Sep 17 00:00:00 2001 From: Jeremy Evans 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@mouraf.org (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] --- lib/drb/drb.rb | 84 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/drb/drb.rb b/lib/drb/drb.rb index caffd5df25..8c2ef63963 100644 --- a/lib/drb/drb.rb +++ b/lib/drb/drb.rb @@ -377,7 +377,12 @@ module DRb # 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 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 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 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 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 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 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 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 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 -- cgit v1.2.3