mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Make Digest() thread-safe.
* ext/digest/lib/digest.rb (Digest()): This function should now be thread-safe. If you have a problem with regard to on-demand loading under a multi-threaded environment, preload "digest/*" modules on boot or use this method instead of directly referencing Digest::*. [Bug #9494] cf. https://github.com/aws/aws-sdk-ruby/issues/525 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48213 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
2172b44898
commit
c02fa39463
5 changed files with 106 additions and 3 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
Fri Oct 31 22:19:30 2014 Akinori MUSHA <knu@iDaemons.org>
|
||||||
|
|
||||||
|
* ext/digest/lib/digest.rb (Digest()): This function should now be
|
||||||
|
thread-safe. If you have a problem with regard to on-demand
|
||||||
|
loading under a multi-threaded environment, preload "digest/*"
|
||||||
|
modules on boot or use this method instead of directly
|
||||||
|
referencing Digest::*. [Bug #9494]
|
||||||
|
cf. https://github.com/aws/aws-sdk-ruby/issues/525
|
||||||
|
|
||||||
Fri Oct 31 21:33:17 2014 Akinori MUSHA <knu@iDaemons.org>
|
Fri Oct 31 21:33:17 2014 Akinori MUSHA <knu@iDaemons.org>
|
||||||
|
|
||||||
* test/digest/test_digest.rb: Drop #!. This no longer runs
|
* test/digest/test_digest.rb: Drop #!. This no longer runs
|
||||||
|
|
5
NEWS
5
NEWS
|
@ -128,6 +128,11 @@ with all sufficient information, see the ChangeLog file.
|
||||||
=== Stdlib updates (outstanding ones only)
|
=== Stdlib updates (outstanding ones only)
|
||||||
|
|
||||||
* Digest
|
* Digest
|
||||||
|
|
||||||
|
* Digest() should now be thread-safe. If you have a problem with
|
||||||
|
regard to on-demand loading under a multi-threaded environment,
|
||||||
|
preload "digest/*" modules on boot or use this method instead of
|
||||||
|
directly referencing Digest::*.
|
||||||
* Digest::HMAC has been removed just as previously noticed.
|
* Digest::HMAC has been removed just as previously noticed.
|
||||||
|
|
||||||
* Etc
|
* Etc
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
require 'digest.so'
|
require 'digest.so'
|
||||||
|
|
||||||
module Digest
|
module Digest
|
||||||
|
# A mutex for Digest().
|
||||||
|
REQUIRE_MUTEX = Mutex.new
|
||||||
|
|
||||||
def self.const_missing(name) # :nodoc:
|
def self.const_missing(name) # :nodoc:
|
||||||
case name
|
case name
|
||||||
when :SHA256, :SHA384, :SHA512
|
when :SHA256, :SHA384, :SHA512
|
||||||
|
@ -76,15 +79,30 @@ end
|
||||||
# call-seq:
|
# call-seq:
|
||||||
# Digest(name) -> digest_subclass
|
# Digest(name) -> digest_subclass
|
||||||
#
|
#
|
||||||
# Returns a Digest subclass by +name+.
|
# Returns a Digest subclass by +name+ in a thread-safe manner even
|
||||||
|
# when on-demand loading is involved.
|
||||||
#
|
#
|
||||||
# require 'digest'
|
# require 'digest'
|
||||||
#
|
#
|
||||||
# Digest("MD5")
|
# Digest("MD5")
|
||||||
# # => Digest::MD5
|
# # => Digest::MD5
|
||||||
#
|
#
|
||||||
# Digest("Foo")
|
# Digest(:SHA256)
|
||||||
|
# # => Digest::SHA256
|
||||||
|
#
|
||||||
|
# Digest(:Foo)
|
||||||
# # => LoadError: library not found for class Digest::Foo -- digest/foo
|
# # => LoadError: library not found for class Digest::Foo -- digest/foo
|
||||||
def Digest(name)
|
def Digest(name)
|
||||||
Digest.const_get(name)
|
const = name.to_sym
|
||||||
|
Digest::REQUIRE_MUTEX.synchronize {
|
||||||
|
# Ignore autoload's because it is void when we have #const_missing
|
||||||
|
Digest.const_missing(const)
|
||||||
|
}
|
||||||
|
rescue LoadError
|
||||||
|
# Constants do not necessarily rely on digest/*.
|
||||||
|
if Digest.const_defined?(const)
|
||||||
|
Digest.const_get(const)
|
||||||
|
else
|
||||||
|
raise
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
10
test/digest/digest/foo.rb
Normal file
10
test/digest/digest/foo.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module Digest
|
||||||
|
Foo = nil
|
||||||
|
|
||||||
|
sleep 0.2
|
||||||
|
|
||||||
|
remove_const(:Foo)
|
||||||
|
|
||||||
|
class Foo < Class
|
||||||
|
end
|
||||||
|
end
|
|
@ -208,4 +208,65 @@ module TestDigest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class TestDigestParen < Test::Unit::TestCase
|
||||||
|
def test_sha2
|
||||||
|
assert_separately(%w[-rdigest], <<-'end;')
|
||||||
|
assert_nothing_raised {
|
||||||
|
Digest(:SHA256).new
|
||||||
|
Digest(:SHA384).new
|
||||||
|
Digest(:SHA512).new
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_no_lib
|
||||||
|
assert_separately(%w[-rdigest], <<-'end;')
|
||||||
|
class Digest::Nolib < Digest::Class
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_nothing_raised {
|
||||||
|
Digest(:Nolib).new
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_no_lib_no_def
|
||||||
|
assert_separately(%w[-rdigest], <<-'end;')
|
||||||
|
assert_raise(LoadError) {
|
||||||
|
Digest(:Nodef).new
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_race
|
||||||
|
assert_separately(['-rdigest', "-I#{File.dirname(__FILE__)}"], <<-'end;')
|
||||||
|
assert_nothing_raised {
|
||||||
|
t = Thread.start {
|
||||||
|
sleep 0.1
|
||||||
|
Digest(:Foo).new
|
||||||
|
}
|
||||||
|
Digest(:Foo).new
|
||||||
|
t.join
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_race_mixed
|
||||||
|
assert_separately(['-rdigest', "-I#{File.dirname(__FILE__)}"], <<-'end;')
|
||||||
|
assert_nothing_raised {
|
||||||
|
t = Thread.start {
|
||||||
|
sleep 0.1
|
||||||
|
Digest::Foo.new
|
||||||
|
}
|
||||||
|
Digest(:Foo).new
|
||||||
|
begin
|
||||||
|
t.join
|
||||||
|
rescue NoMethodError, NameError
|
||||||
|
# NoMethodError is highly likely; NameError is listed just in case
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue