Skip to content

Process.detach raises ArrayIndexOutOfBoundsException if called from a thread that is not the main thread #9308

@dazuma

Description

@dazuma

Environment Information

$ jruby -v
jruby 10.0.4.0 (3.4.5) 2026-03-03 9af05b916f Java HotSpot(TM) 64-Bit Server VM 24.0.1+9-30 on 24.0.1+9-30 +indy +jit [arm64-darwin]
$ uname -a
Darwin meowputer-m3.local 25.3.0 Darwin Kernel Version 25.3.0: Wed Jan 28 20:47:03 PST 2026; root:xnu-12377.81.4~5/RELEASE_ARM64_T6031 arm64

Description

Process.detach raises ArrayIndexOutOfBoundsException if called from a thread that is not the main thread.

It works as expected if called from the main thread:

pid = Process.spawn("sleep 2")
puts "Spawned #{pid}"
proc_thread = Process.detach(pid)
puts "Final status #{proc_thread.join.value.inspect}"

Output:

Spawned 485
Final status #<Process::Status: pid 485 exit 0>

If I create a new thread and call Process.detach from that thread, it raises:

pid = Process.spawn("sleep 2")
puts "Spawned #{pid}"
my_thread = Thread.new do
  proc_thread = Process.detach(pid)
  puts "Final status #{proc_thread.join.value.inspect}"
end
my_thread.join

Output:

Spawned 780
warning: thread "Ruby-0-Thread-1: foo2.rb:3" terminated with exception (report_on_exception is true):java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 10
	at org.jruby.dist/org.jruby.runtime.ThreadContext.getCurrentFrame(ThreadContext.java:580)
	at org.jruby.dist/org.jruby.runtime.ThreadContext.currentBinding(ThreadContext.java:1262)
	at org.jruby.dist/org.jruby.runtime.CallBlock.newCallClosure(CallBlock.java:49)
	at org.jruby.dist/org.jruby.RubyProcess.detach(RubyProcess.java:1751)
	at org.jruby.dist/org.jruby.RubyProcess$INVOKER$s$1$0$detach.call(RubyProcess$INVOKER$s$1$0$detach.gen)
	at org.jruby.dist/org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:841)
	at org.jruby.dist/org.jruby.ir.targets.indy.InvokeSite.performIndirectCall(InvokeSite.java:885)
	at org.jruby.dist/org.jruby.ir.targets.indy.InvokeSite.invoke(InvokeSite.java:789)
	at foo2.️❤ {} \=\^main\_ #0(foo2.rb:4)
	at org.jruby.dist/org.jruby.runtime.CompiledIRBlockBody.callDirect(CompiledIRBlockBody.java:141)
	at org.jruby.dist/org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:66)
	at org.jruby.dist/org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:60)
	at org.jruby.dist/org.jruby.runtime.Block.call(Block.java:146)
	at org.jruby.dist/org.jruby.RubyProc.call(RubyProc.java:394)
	at org.jruby.dist/org.jruby.internal.runtime.RubyRunnable.run(RubyRunnable.java:122)
	at java.base/java.lang.Thread.run(Thread.java:1447)
Unhandled Java exception: java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 10
java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 10
      getCurrentFrame at org/jruby/runtime/ThreadContext.java:580
       currentBinding at org/jruby/runtime/ThreadContext.java:1262
       newCallClosure at org/jruby/runtime/CallBlock.java:49
               detach at org/jruby/RubyProcess.java:1751
                 call at org/jruby/RubyProcess$INVOKER$s$1$0$detach.gen:-1
                 call at org/jruby/internal/runtime/methods/JavaMethod.java:841
  performIndirectCall at org/jruby/ir/targets/indy/InvokeSite.java:885
               invoke at org/jruby/ir/targets/indy/InvokeSite.java:789
  ️❤ {} \=\^main\_ #0 at foo2.rb:4
           callDirect at org/jruby/runtime/CompiledIRBlockBody.java:141
                 call at org/jruby/runtime/IRBlockBody.java:66
                 call at org/jruby/runtime/IRBlockBody.java:60
                 call at org/jruby/runtime/Block.java:146
                 call at org/jruby/RubyProc.java:394
                  run at org/jruby/internal/runtime/RubyRunnable.java:122
                  run at java/lang/Thread.java:1447

It also fails if I spawn the process from the same separate thread, so it's not a matter of the detach needing to happen from the same thread as the spawn. The difference seems to be main thread vs any other thread.

my_thread = Thread.new do
  pid = Process.spawn("sleep 2")
  puts "Spawned #{pid}"
  proc_thread = Process.detach(pid)
  puts "Final status #{proc_thread.join.value.inspect}"
end
my_thread.join

Similar output:

Spawned 882
warning: thread "Ruby-0-Thread-1: foo3.rb:3" terminated with exception (report_on_exception is true):java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 10
	at org.jruby.dist/org.jruby.runtime.ThreadContext.getCurrentFrame(ThreadContext.java:580)
	at org.jruby.dist/org.jruby.runtime.ThreadContext.currentBinding(ThreadContext.java:1262)
	at org.jruby.dist/org.jruby.runtime.CallBlock.newCallClosure(CallBlock.java:49)
	at org.jruby.dist/org.jruby.RubyProcess.detach(RubyProcess.java:1751)
	at org.jruby.dist/org.jruby.RubyProcess$INVOKER$s$1$0$detach.call(RubyProcess$INVOKER$s$1$0$detach.gen)
	at org.jruby.dist/org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:841)
	at org.jruby.dist/org.jruby.ir.targets.indy.InvokeSite.performIndirectCall(InvokeSite.java:885)
	at org.jruby.dist/org.jruby.ir.targets.indy.InvokeSite.invoke(InvokeSite.java:789)
	at foo3.️❤ {} \=\^main\_ #0(foo3.rb:4)
	at org.jruby.dist/org.jruby.runtime.CompiledIRBlockBody.callDirect(CompiledIRBlockBody.java:141)
	at org.jruby.dist/org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:66)
	at org.jruby.dist/org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:60)
	at org.jruby.dist/org.jruby.runtime.Block.call(Block.java:146)
	at org.jruby.dist/org.jruby.RubyProc.call(RubyProc.java:394)
	at org.jruby.dist/org.jruby.internal.runtime.RubyRunnable.run(RubyRunnable.java:122)
	at java.base/java.lang.Thread.run(Thread.java:1447)
Unhandled Java exception: java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 10
java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 10
      getCurrentFrame at org/jruby/runtime/ThreadContext.java:580
       currentBinding at org/jruby/runtime/ThreadContext.java:1262
       newCallClosure at org/jruby/runtime/CallBlock.java:49
               detach at org/jruby/RubyProcess.java:1751
                 call at org/jruby/RubyProcess$INVOKER$s$1$0$detach.gen:-1
                 call at org/jruby/internal/runtime/methods/JavaMethod.java:841
  performIndirectCall at org/jruby/ir/targets/indy/InvokeSite.java:885
               invoke at org/jruby/ir/targets/indy/InvokeSite.java:789
  ️❤ {} \=\^main\_ #0 at foo3.rb:4
           callDirect at org/jruby/runtime/CompiledIRBlockBody.java:141
                 call at org/jruby/runtime/IRBlockBody.java:66
                 call at org/jruby/runtime/IRBlockBody.java:60
                 call at org/jruby/runtime/Block.java:146
                 call at org/jruby/RubyProc.java:394
                  run at org/jruby/internal/runtime/RubyRunnable.java:122
                  run at java/lang/Thread.java:1447

CRuby/MRI works correctly in all three cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions