From 475c8701d74ebebefb2f53052cde1a5effb4cb81 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 4 Sep 2020 17:32:31 -0700 Subject: [PATCH] Make SecureRandom support Ractor SecureRandom lazily defines `get_random`. Accessing the mutex to define the `get_random` method is not supported inside a Ractor. This commit defines `gen_random` when `securerandom` is required and makes it suppore Ractor (as well as thread safe). Here is a test program: ```ruby require "securerandom" r = Ractor.new do loop do Ractor.yield SecureRandom.hex end end p r.take ``` Before this commit: ``` $ make runruby ./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems ./test.rb :38: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues. /Users/aaron/git/ruby/lib/securerandom.rb:94:in `gen_random': can not access instance variables of classes/modules from non-main Ractors (RuntimeError) :124:in `take': thrown by remote Ractor. (Ractor::RemoteError) from ./test.rb:9:in `
' /Users/aaron/git/ruby/lib/securerandom.rb:94:in `gen_random': can not access instance variables of classes/modules from non-main Ractors (RuntimeError) from /Users/aaron/git/ruby/lib/securerandom.rb:155:in `random_bytes' from /Users/aaron/git/ruby/lib/securerandom.rb:176:in `hex' from ./test.rb:5:in `block (2 levels) in
' from ./test.rb:4:in `loop' from ./test.rb:4:in `block in
' make: *** [runruby] Error ``` After this commit: ``` $ make runruby ./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems ./test.rb :38: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues. "3fc8885157e3911bab4b5d7619bb0308" ``` --- lib/securerandom.rb | 46 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/lib/securerandom.rb b/lib/securerandom.rb index 205cb70be5..241fde98ce 100644 --- a/lib/securerandom.rb +++ b/lib/securerandom.rb @@ -66,42 +66,11 @@ # module SecureRandom - @rng_chooser = Mutex.new # :nodoc: - class << self def bytes(n) return gen_random(n) end - def gen_random(n) - ret = Random.urandom(1) - if ret.nil? - begin - require 'openssl' - rescue NoMethodError - raise NotImplementedError, "No random device" - else - @rng_chooser.synchronize do - class << self - remove_method :gen_random - alias gen_random gen_random_openssl - public :gen_random - end - end - return gen_random(n) - end - else - @rng_chooser.synchronize do - class << self - remove_method :gen_random - alias gen_random gen_random_urandom - public :gen_random - end - end - return gen_random(n) - end - end - private def gen_random_openssl(n) @@ -129,6 +98,21 @@ module SecureRandom end ret end + + ret = Random.urandom(1) + if ret.nil? + begin + require 'openssl' + rescue NoMethodError + raise NotImplementedError, "No random device" + else + alias gen_random gen_random_openssl + end + else + alias gen_random gen_random_urandom + end + + public :gen_random end end