[ruby-core:126383] [Ruby Bug#18444] Trapped TSTP causes a locking deadlock in 3.0.3 onward
Issue #18444 has been updated by wanabe (_ wanabe). File 18444.log added This issue can also be reproduced on the master branch. Since it is not specific to TSTP, it can be reproduced with any signal. ``` $ ./miniruby -ve 'Signal.trap(:TERM) { print "2\r"; sleep 0.01; exit(0) }; spawn("sleep 0.1; kill -TERM #{$$}"); loop {print "1\r"}' ruby 4.1.0dev (2026-08-12T02:39:28Z origin/master c6e9858440) +PRISM [x86_64-linux] -e:1:in 'IO#write': deadlock; recursive locking (ThreadError) from -e:1:in 'Kernel#print' from -e:1:in 'block in <main>' from -e:1:in 'IO#write' from -e:1:in 'Kernel#print' from -e:1:in 'block in <main>' from -e:1:in 'Kernel#loop' from -e:1:in '<main>' ``` I attached the backtrace captured with GDB. Summary: ``` print "1\r" # print in loop{} -> #44 0x00005555557005d5 in io_binwrite (ptr=0x55555606e810 "1\r", len=2, fptr=0x555555f26c40, nosync=0) at ../../io.c:1939 #43 0x000055555589676c in rb_mutex_synchronize (self=140737345534480, func=0x555555700320 <io_binwrite_string>, arg=140737488338256) at ../../thread_sync.c:629 #42 0x00005555556b408c in rb_ec_ensure (ec_arg=0x555555ebff58, b_proc=0x555555700320 <io_binwrite_string>, data1=140737488338256, e_proc_arg=0x555555896318 <do_mutex_unlock_safe>, data2_arg=140737488338176) at ../../eval.c:1171 #40 0x000055555570030a in io_binwrite_string_internal (fptr=0x555555f26c40, ptr=0x55555606e810 "1\r", length=2) at ../../io.c:1817 #38 0x00005555556fdf28 in rb_io_blocking_region_wait (io=0x555555f26c40, function=0x5555556ff0db <internal_write_func>, argument=0x7fffffffbac0, events=RUBY_IO_WRITABLE) at ../../io.c:230 #35 0x000055555589d86e in rb_threadptr_execute_interrupts (th=0x555555ea0780 <_main_thread>, blocking_timing=1) at ../../thread.c:2820 Signal.trap(:TERM) -> #34 0x000055555584688a in rb_signal_exec (th=0x555555ea0780 <_main_thread>, sig=15) at ../../signal.c:1143 #33 0x00005555558466ef in signal_exec (cmd=140737345533960, sig=15) at ../../signal.c:1081 #32 0x00005555559106d9 in rb_eval_cmd_call_kw (cmd=140737345533960, argc=1, argv=0x7fffffffb778, kw_splat=0) at ../../vm_eval.c:2196 print "2\r" # print in trap{} -> #3 0x00005555557005d5 in io_binwrite (ptr=0x55555606e8c0 "2\r", len=2, fptr=0x555555f26c40, nosync=0) at ../../io.c:1939 #2 0x000055555589674a in rb_mutex_synchronize (self=140737345534480, func=0x555555700320 <io_binwrite_string>, arg=140737488328896) at ../../thread_sync.c:628 #1 0x0000555555895bf4 in do_mutex_lock (args=0x7fffffff9870, interruptible_p=1) at ../../thread_sync.c:296 #0 rb_raise (exc_class=93824993755556, fmt=0x7fffffff9710 "@\227\377\377\377\177") at ../../error.c:3930 ``` - Since `rb_signal_exec` is executed - while STDOUT is locked by the `print` statement in the main loop, - a problem occurs when attempting to use `print` within the `trap` block - because STDOUT is still locked. Ideally, this issue could be resolved by ensuring that `rb_signal_exec` is executed only after the lock is released by the first `print` statement in the main loop. But I am concerned that doing so might compromise compatibility. ---------------------------------------- Bug #18444: Trapped TSTP causes a locking deadlock in 3.0.3 onward https://bugs.ruby-lang.org/issues/18444#change-118519 * Author: why-el (Mohamed Wael Khobalatte) * Status: Open * ruby -v: 3.0.3 * Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- A curious case: `ruby -e 'Signal.trap("TSTP") { puts "Received a terminal stop signal, but i will sleep instead."; sleep 10 }; loop {puts 1}'` this fails with `deadlock; recursive locking (ThreadError)` when I send the SIGTSTP via my terminal. This is on Mac OS Monterey (M1). It only happens in 3.0.3 and onward (I tried 3.1.0-preview1 as well, fails there too), when I try 3.0.2, the signal is handled properly. ---Files-------------------------------- 18444.log (11.8 KB) -- https://bugs.ruby-lang.org/
participants (1)
-
wanabe (_ wanabe)