Details
-
Type:
Bug
-
Status:
Resolved
-
Priority:
Minor
-
Resolution: Fixed
-
Affects Version/s: JRuby 1.7.0.pre1
-
Fix Version/s: JRuby 1.7.0.pre2
-
Component/s: Core Classes/Modules
-
Labels:None
-
Number of attachments :
Description
RubyRandom is not thread-safe and is throwing java.lang.ArrayIndexOutOfBoundsException exception under concurrent load.
To reproduce:
bin/jruby -e'Array.new(100).map {Thread.new{500000.times
{rand}}}.map(&:join)'
Exception in thread "RubyThread-52: -e:1" java.lang.ArrayIndexOutOfBoundsException: 624
at org.jruby.util.Random.genrandInt32(Random.java:145)
at org.jruby.util.Random.genrandReal(Random.java:158)
at org.jruby.RubyRandom$RandomType.genrandReal(RubyRandom.java:135)
at org.jruby.RubyRandom.randFloat(RubyRandom.java:348)
at org.jruby.RubyRandom.randCommon19(RubyRandom.java:269)
at org.jruby.RubyKernel.rand19(RubyKernel.java:1537)
at org.jruby.RubyKernel$INVOKER$s$0$1$rand19.call(RubyKernel$INVOKER$s$0$1$rand19.gen)
at org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:636)
at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:196)
at java.lang.invoke.MethodHandle.invokeExact(MethodHandle.java)
at java.lang.invoke.MethodHandle.invokeExact(MethodHandle.java)
at java.lang.invoke.MethodHandle.invokeExact(MethodHandle.java)
at ruby._dash_e.block_2$RUBY$file_(-e:1)
at ruby$_dash_e$block_2$RUBY$file.call(ruby$dash_e$block_2$RUBY$file_)
at org.jruby.runtime.CompiledBlock19.yield(CompiledBlock19.java:139)
at org.jruby.runtime.Block.yield(Block.java:130)
at org.jruby.RubyFixnum.times(RubyFixnum.java:265)
at java.lang.invoke.MethodHandleImpl$GuardWithCatch.invoke_L4(MethodHandleImpl.java:1146)
at java.lang.invoke.MethodHandleImpl$GuardWithCatch.invoke_L4(MethodHandleImpl.java:1146)
at ruby._dash_e.block_1$RUBY$file_(-e:1)
at ruby$_dash_e$block_1$RUBY$file.call(ruby$dash_e$block_1$RUBY$file_)
at org.jruby.runtime.CompiledBlock19.yield(CompiledBlock19.java:163)
at org.jruby.runtime.CompiledBlock19.call(CompiledBlock19.java:91)
at org.jruby.runtime.Block.call(Block.java:89)
at org.jruby.RubyProc.call(RubyProc.java:269)
at org.jruby.RubyProc.call(RubyProc.java:223)
at org.jruby.internal.runtime.RubyRunnable.run(RubyRunnable.java:101)
at java.lang.Thread.run(Thread.java:722)
I run into this by having Array#shuffle throwing concurrent modification errors, because it is catching ArrayIndexOutOfBoundsException thrown by the RubyRandom and re-throwing them as Array concurrency exceptions.
To reproduce:
bin/jruby -e'arr = Array.new(1000); Array.new(100).map {Thread.new{1000.times
}}.map(&:join)'
Don't know enough about rand, but maybe this can be fixed by wrapping org.jruby.util.Random.genrandInt32() with a try/catch block and simply retrying on ArrayIndexOutOfBoundsException exception (or is this risking internal rand generator corruption?).