Files
metasploit-gs/lib/metasploit/framework/spec/threads/logger.rb
T
Luke Imhoff 8416985c9d Give Threads UUIDs for spec run so caller can be correlated
Have 'metasploit/framework/spec/threads/suite/logger' generate a UUID
for each Thread.  This UUID is printed on the "BEGIN Thread.new caller"
line and is assigned as a thread-local variable,
'metasploit/framework/spec/threads/logger/uuid'.  In `after(:suite)`,
the log can be parsed to map the caller back to each UUID and then only
the UUID of the still existing threads is used to look up the caller and
print their stacktraces.  This means only leaked threads callers will be
printed.
2014-11-06 14:05:35 -06:00

41 lines
1.1 KiB
Ruby

#
# Standard Library
#
require 'securerandom'
#
# Project
#
require 'metasploit/framework/spec/threads/suite'
original_thread_new = Thread.method(:new)
# Patches `Thread.new` so that if logs `caller` so thread leaks can be traced
Thread.define_singleton_method(:new) { |*args, &block|
uuid = SecureRandom.uuid
# tag caller with uuid so that only leaked threads caller needs to be printed
lines = ["BEGIN Thread.new caller (#{uuid})"]
caller.each do |frame|
lines << " #{frame}"
end
lines << 'END Thread.new caller'
Metasploit::Framework::Spec::Threads::Suite::LOG_PATHNAME.parent.mkpath
Metasploit::Framework::Spec::Threads::Suite::LOG_PATHNAME.open('a') { |f|
# single puts so threads can't write in between each other.
f.puts lines.join("\n")
}
options = {original_args: args, uuid: uuid}
original_thread_new.call(options) {
# record uuid for thread-leak detection can used uuid to correlate log with this thread.
Thread.current[Metasploit::Framework::Spec::Threads::Suite::UUID_THREAD_LOCAL_VARIABLE] = options.fetch(:uuid)
block.call(*options.fetch(:original_args))
}
}