Skip to content

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

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions