aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
authorRafael França <rafaelmfranca@gmail.com>2017-05-11 17:45:03 -0700
committerGitHub <noreply@github.com>2017-05-11 17:45:03 -0700
commitf96c14096c0b5bbb5973b791b5a7bdb8f403217a (patch)
treed185603758b01770b7f31a36d0aef1897efdcdb6 /activesupport
parent4b969ea417f097d217ff1f662d2fe8c406d21b99 (diff)
parent4fc2ea11811c50fb1f7c5baba6d4c20532a5a00c (diff)
downloadrails-f96c14096c0b5bbb5973b791b5a7bdb8f403217a.tar.gz
rails-f96c14096c0b5bbb5973b791b5a7bdb8f403217a.tar.bz2
rails-f96c14096c0b5bbb5973b791b5a7bdb8f403217a.zip
Merge pull request #29034 from peterjm/handle_loops_in_exception_handling
Handle loops in the cause chain in Rescuable#rescue_with_handler
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/lib/active_support/rescuable.rb10
-rw-r--r--activesupport/test/rescuable_test.rb34
2 files changed, 41 insertions, 3 deletions
diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb
index ee6592fb5a..12ec8bf1b8 100644
--- a/activesupport/lib/active_support/rescuable.rb
+++ b/activesupport/lib/active_support/rescuable.rb
@@ -84,12 +84,18 @@ module ActiveSupport
# end
#
# Returns the exception if it was handled and +nil+ if it was not.
- def rescue_with_handler(exception, object: self)
+ def rescue_with_handler(exception, object: self, visited_exceptions: [])
+ visited_exceptions << exception
+
if handler = handler_for_rescue(exception, object: object)
handler.call exception
exception
elsif exception
- rescue_with_handler(exception.cause, object: object)
+ if visited_exceptions.include?(exception.cause)
+ nil
+ else
+ rescue_with_handler(exception.cause, object: object, visited_exceptions: visited_exceptions)
+ end
end
end
diff --git a/activesupport/test/rescuable_test.rb b/activesupport/test/rescuable_test.rb
index f7eb047d44..3bdd1651e7 100644
--- a/activesupport/test/rescuable_test.rb
+++ b/activesupport/test/rescuable_test.rb
@@ -43,7 +43,9 @@ class Stargate
def dispatch(method)
send(method)
rescue Exception => e
- rescue_with_handler(e)
+ unless rescue_with_handler(e)
+ @result = "unhandled"
+ end
end
def attack
@@ -58,6 +60,26 @@ class Stargate
raise MadRonon.new("dex")
end
+ def crash
+ raise "unhandled RuntimeError"
+ end
+
+ def looped_crash
+ ex1 = StandardError.new("error 1")
+ ex2 = StandardError.new("error 2")
+ begin
+ begin
+ raise ex1
+ rescue
+ # sets the cause on ex2 to be ex1
+ raise ex2
+ end
+ rescue
+ # sets the cause on ex1 to be ex2
+ raise ex1
+ end
+ end
+
def fall_back_to_cause
# This exception is the cause and has a handler.
ronanize
@@ -139,4 +161,14 @@ class RescuableTest < ActiveSupport::TestCase
@stargate.dispatch :fall_back_to_cause
assert_equal "dex", @stargate.result
end
+
+ def test_unhandled_exceptions
+ @stargate.dispatch(:crash)
+ assert_equal "unhandled", @stargate.result
+ end
+
+ def test_rescue_handles_loops_in_exception_cause_chain
+ @stargate.dispatch :looped_crash
+ assert_equal "unhandled", @stargate.result
+ end
end