Subject: bug#64666: Nested ‘scm_sigaction_for_thread’ calls lead to deadlock

From: Ludovic Courtès <[email-masked]>
Date: Sun, 16 Jul 2023 18:16:17 +0200

Hello,

It’s possible for ‘sigaction’ (aka. ‘scm_sigaction_for_thread’) to run
asyncs, which in turn call ‘scm_sigaction_for_thread’ for the very same
thread, leading to a deadlock:

--8<---------------cut here---------------start------------->8---
(gdb) bt
#0  0x00007f823bcdf32b in __lll_lock_wait ()
   from /gnu/store/gsjczqir1wbz8p770zndrpw4rnppmxi3-glibc-2.35/lib/libc.so.6
#1  0x00007f823bce5572 in pthread_mutex_lock@@GLIBC_2.2.5 ()
   from /gnu/store/gsjczqir1wbz8p770zndrpw4rnppmxi3-glibc-2.35/lib/libc.so.6
#2  0x00007f823c278e45 in scm_pthread_mutex_lock (mutex=<optimized out>)
    at /home/ludo/src/guile-3.0/libguile/threads.c:1616
#3  0x00007f823c27cc79 in scm_dynwind_pthread_mutex_lock (
    mutex=0x7f823c2fa240 <signal_handler_lock>)
    at /home/ludo/src/guile-3.0/libguile/threads.c:1629
#4  0x00007f823c25d254 in scm_sigaction_for_thread (signum=<optimized out>, 
    handler=0x7f8239940258, flags=0x904, thread=0x7f823ba38320)
    at /home/ludo/src/guile-3.0/libguile/scmsigs.c:339
#5  0x00007f823990f257 in ?? ()
#6  0x0000000001918f38 in ?? ()
#7  0x00007f8239910b50 in ?? ()
#8  0x00007f823ba1ad80 in ?? ()
#9  0x00007f823c22556c in scm_jit_enter_mcode (thread=0x7f823ba1ad80, 
    mcode=0x191f55c "\034\r\002") at /home/ludo/src/guile-3.0/libguile/jit.c:6061
#10 0x00007f823c2812c5 in vm_regular_engine (thread=0x7f823c330d68)
    at /home/ludo/src/guile-3.0/libguile/vm-engine.c:360
#11 0x00007f823c28af95 in scm_call_n (proc=<optimized out>, argv=<optimized out>, nargs=0)
    at /home/ludo/src/guile-3.0/libguile/vm.c:1616
#12 0x00007f823c1f25a0 in scm_async_tick () at /home/ludo/src/guile-3.0/libguile/async.c:154
#13 0x00007f823c1f8545 in scm_dynstack_unwind_frame (dynstack=0x7f823ba1af88)
    at /home/ludo/src/guile-3.0/libguile/dynstack.c:628
#14 scm_dynwind_end () at /home/ludo/src/guile-3.0/libguile/dynwind.c:71
#15 0x00007f823c25d478 in scm_sigaction_for_thread (signum=<optimized out>, 
    handler=0x7f8239940258, flags=<optimized out>, thread=0x7f823ba38320)
    at /home/ludo/src/guile-3.0/libguile/scmsigs.c:447
--8<---------------cut here---------------end--------------->8---

Notice the nested ‘scm_sigaction_for_thread’ call for 0x7f823ba38320.

This happens while letting the code below run for a minute or so:

--8<---------------cut here---------------start------------->8---
(use-modules (ice-9 match))

(setvbuf (current-output-port) 'line)

(match (primitive-fork)
  (0
   (format #t "child: ~a~%" (getpid))
   (letrec ((handler (lambda args
                       (pk 'SIGUSR1! args)
                       (sigaction SIGUSR1 handler))))
     (sigaction SIGUSR1 handler))
   (let loop ()
     (pk 'slept (sleep 100000))
     (loop)))
  (pid
   (sleep 1)
   (let loop ()
     (usleep 10000)
     (kill pid SIGUSR1)
     (loop))))
--8<---------------cut here---------------end--------------->8---

Ludo’.