summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2019-11-12 01:30:42 +0900
committerYusuke Endoh <mame@ruby-lang.org>2019-11-12 01:47:18 +0900
commitc02de30efbca2a2d89cdf188a27991f7ae15b9da (patch)
tree66735080c3d7197339087a996867a2449b88322e
parentb72eda3c59cd0a15ed3536a3c0cd8aebd225f16b (diff)
tool/lib/leakchecker.rb: show the code location that allocated leaked fd
by using ObjectSpace.trace_object_allocations. `make test-all LEAK_CHECKER_TRACE_OBJECT_ALLOCATION=true` will print not only leaked fds but also where it was created.
-rw-r--r--tool/lib/leakchecker.rb5
-rw-r--r--tool/lib/minitest/unit.rb40
2 files changed, 29 insertions, 16 deletions
diff --git a/tool/lib/leakchecker.rb b/tool/lib/leakchecker.rb
index af9200bf77..26ece9340f 100644
--- a/tool/lib/leakchecker.rb
+++ b/tool/lib/leakchecker.rb
@@ -75,9 +75,13 @@ class LeakChecker
}
fd_leaked.each {|fd|
str = ''.dup
+ pos = nil
if h[fd]
str << ' :'
h[fd].map {|io, autoclose, inspect|
+ if ENV["LEAK_CHECKER_TRACE_OBJECT_ALLOCATION"]
+ pos = "#{ObjectSpace.allocation_sourcefile(io)}:#{ObjectSpace.allocation_sourceline(io)}"
+ end
s = ' ' + inspect
s << "(not-autoclose)" if !autoclose
s
@@ -86,6 +90,7 @@ class LeakChecker
}
end
puts "Leaked file descriptor: #{test_name}: #{fd}#{str}"
+ puts " The IO was created at #{pos}" if pos
}
#system("lsof -p #$$") if !fd_leaked.empty?
h.each {|fd, list|
diff --git a/tool/lib/minitest/unit.rb b/tool/lib/minitest/unit.rb
index 90d2da25f8..8ac0f146bd 100644
--- a/tool/lib/minitest/unit.rb
+++ b/tool/lib/minitest/unit.rb
@@ -941,28 +941,36 @@ module MiniTest
leakchecker = LeakChecker.new
- assertions = filtered_test_methods.map { |method|
- inst = suite.new method
- inst._assertions = 0
+ continuation = proc do
+ assertions = filtered_test_methods.map { |method|
+ inst = suite.new method
+ inst._assertions = 0
- print "#{suite}##{method} = " if @verbose
+ print "#{suite}##{method} = " if @verbose
- start_time = Time.now if @verbose
- result = inst.run self
+ start_time = Time.now if @verbose
+ result = inst.run self
- print "%.2f s = " % (Time.now - start_time) if @verbose
- print result
- puts if @verbose
- $stdout.flush
+ print "%.2f s = " % (Time.now - start_time) if @verbose
+ print result
+ puts if @verbose
+ $stdout.flush
- unless defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # compiler process is wrongly considered as leak
- leakchecker.check("#{inst.class}\##{inst.__name__}")
- end
+ unless defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # compiler process is wrongly considered as leak
+ leakchecker.check("#{inst.class}\##{inst.__name__}")
+ end
- inst._assertions
- }
+ inst._assertions
+ }
+ return assertions.size, assertions.inject(0) { |sum, n| sum + n }
+ end
- return assertions.size, assertions.inject(0) { |sum, n| sum + n }
+ if ENV["LEAK_CHECKER_TRACE_OBJECT_ALLOCATION"]
+ require "objspace"
+ ObjectSpace.trace_object_allocations(&continuation)
+ else
+ continuation.call
+ end
end
##