From d24fba6c4d35d983c66944c460a0b37d11d2fff7 Mon Sep 17 00:00:00 2001 From: Ryan Davis Date: Tue, 16 Aug 2022 22:10:57 -0800 Subject: [PATCH] - Fixed exception sanitization by removing TypeError restriction on rescue. Fixes #921 [git-p4: depot-paths = "//src/minitest/dev/": change = 13507] --- lib/minitest/test.rb | 4 +-- test/minitest/test_minitest_test.rb | 43 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/lib/minitest/test.rb b/lib/minitest/test.rb index f79de76..6510e09 100644 --- a/lib/minitest/test.rb +++ b/lib/minitest/test.rb @@ -204,7 +204,7 @@ module Minitest def sanitize_exception e # :nodoc: Marshal.dump e e # good: use as-is - rescue TypeError + rescue neuter_exception e end @@ -213,7 +213,7 @@ module Minitest msg = e.message.dup new_exception e.class, msg, bt # e.class can be a problem... - rescue TypeError + rescue msg.prepend "Neutered Exception #{e.class}: " new_exception RuntimeError, msg, bt, true # but if this raises, we die diff --git a/test/minitest/test_minitest_test.rb b/test/minitest/test_minitest_test.rb index 5ed96b5..beb24cb 100644 --- a/test/minitest/test_minitest_test.rb +++ b/test/minitest/test_minitest_test.rb @@ -942,6 +942,49 @@ class TestMinitestRunnable < Minitest::Test assert_equal @tc.failures, over_the_wire.failures assert_equal @tc.klass, over_the_wire.klass end + + def test_spec_marshal_with_exception__worse_error_typeerror + worse_error_klass = Class.new(StandardError) do + # problem #1: anonymous subclass can'tmarshal, fails sanitize_exception + def initialize(record = nil) + + super(record.first) + end + end + + klass = describe("whatever") { + it("raises with NoMethodError") { + # problem #2: instantiated with a NON-string argument + # + # problem #3: arg responds to #first, but it becomes message + # which gets passed back in via new_exception + # that passes a string to worse_error_klass#initialize + # which calls first on it, which raises NoMethodError + raise worse_error_klass.new(["boom"]) + } + } + + rm = klass.runnable_methods.first + + # Run the test + @tc = klass.new(rm).run + + assert_kind_of Minitest::Result, @tc + assert_instance_of Minitest::UnexpectedError, @tc.failure + + msg = @tc.failure.error.message.gsub(/0x[A-Fa-f0-9]+/, "0xXXX") + + assert_equal "Neutered Exception #: boom", msg + + # Pass it over the wire + over_the_wire = Marshal.load Marshal.dump @tc + + assert_equal @tc.time, over_the_wire.time + assert_equal @tc.name, over_the_wire.name + assert_equal @tc.assertions, over_the_wire.assertions + assert_equal @tc.failures, over_the_wire.failures + assert_equal @tc.klass, over_the_wire.klass + end end class TestMinitestTest < TestMinitestRunnable