StringIO is not thread-safe (throws a Java exception) #4417

Closed
glebm opened this Issue Dec 30, 2016 · 1 comment

Projects

None yet

2 participants

@glebm
glebm commented Dec 30, 2016 edited

Environment

$ jruby -v
jruby 9.1.6.0 (2.3.1) 2016-11-09 0150a76 Java HotSpot(TM) 64-Bit Server VM 25.45-b02 on 1.8.0_45-b14 +jit [darwin-x86_64]
$ uname -a
Darwin Macintosh.local 16.3.0 Darwin Kernel Version 16.3.0: Thu Nov 17 20:23:58 PST 2016; root:xnu-3789.31.2~1/RELEASE_X86_64 x86_64

Expected Behavior

Given this test.rb file:

a = StringIO.new
100.times.map do
  Thread.start do
    # 'hello' seems to work but not *%w(hello)
    100.times { a.puts *%w(hello) }
  end
end.each(&:join)

Its execution should succeed:

$ jruby test.rb

Actual Behavior

Exception in thread "Ruby-0-Thread-100: test.rb:1" Exception in thread "Ruby-0-Thread-99: test.rb:1" java.lang.ArrayIndexOutOfBoundsException
	at java.lang.System.arraycopy(Native Method)
	at org.jruby.util.ByteList.grow(ByteList.java:1102)
	at org.jruby.util.ByteList.length(ByteList.java:584)
	at org.jruby.RubyString.resize(RubyString.java:995)
	at org.jruby.ext.stringio.StringIO.strioExtend(StringIO.java:701)
	at org.jruby.ext.stringio.StringIO.write(StringIO.java:1024)
	at org.jruby.ext.stringio.StringIO$INVOKER$i$1$0$write.call(StringIO$INVOKER$i$1$0$write.gen)
	at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:161)
	at org.jruby.RubyIO.write(RubyIO.java:2567)
	at org.jruby.ext.stringio.StringIO$GenericWritable.puts(StringIO.java:1213)
	at org.jruby.ext.stringio.StringIO$GenericWritable$INVOKER$s$0$0$puts.call(StringIO$GenericWritable$INVOKER$s$0$0$puts.gen)
	at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:67)
	at test.invokeOther1:puts(test.rb:4)
	at test.RUBY$block$\=test\,rb$2(test.rb:4)
	at org.jruby.runtime.CompiledIRBlockBody.yieldDirect(CompiledIRBlockBody.java:156)
	at org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:76)
	at org.jruby.runtime.Block.yieldSpecific(Block.java:136)
	at org.jruby.RubyFixnum.times(RubyFixnum.java:299)
	at org.jruby.RubyFixnum$INVOKER$i$0$0$times.call(RubyFixnum$INVOKER$i$0$0$times.gen)
	at org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:139)
	at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:145)
	at test.invokeOther4:times(test.rb:4)
	at test.RUBY$block$\=test\,rb$1(test.rb:4)
	at org.jruby.runtime.CompiledIRBlockBody.callDirect(CompiledIRBlockBody.java:145)
	at org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:67)
	at org.jruby.runtime.Block.call(Block.java:126)
	at org.jruby.RubyProc.call(RubyProc.java:324)
	at org.jruby.RubyProc.call(RubyProc.java:249)
	at org.jruby.internal.runtime.RubyRunnable.run(RubyRunnable.java:104)
	at java.lang.Thread.run(Thread.java:745)
@glebm glebm changed the title from StringIO is not thread-safe! to StringIO is not thread-safe Dec 30, 2016
@glebm glebm added a commit to glebm/i18n-tasks that referenced this issue Dec 30, 2016
@glebm glebm Explain on why the mutex is needed in logging.rb 823dd30
@glebm glebm changed the title from StringIO is not thread-safe to StringIO is not thread-safe (raises an exception) Dec 30, 2016
@headius
Member
headius commented Jan 4, 2017

I can play devil's advocate and ask "should it be threadsafe?" However, IO is thread-safe, and StringIO is intended to mimic it, so I agree we should deal with this.

FWIW, I don't believe MRI's StringIO is really safe, but it probably won't fail as severely as this.

@headius headius added this to the JRuby 9.1.7.0 milestone Jan 4, 2017
@headius headius closed this in #4421 Jan 4, 2017
@kares kares changed the title from StringIO is not thread-safe (raises an exception) to StringIO is not thread-safe (throws a Java exception) Jan 9, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment