GNU bug report logs - #70144
system* affects signal handlers

Previous Next

Package: guile;

Reported by: Christopher Baines <mail <at> cbaines.net>

Date: Tue, 2 Apr 2024 14:28:02 UTC

Severity: normal

To reply to this bug, email your comments to 70144 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-guile <at> gnu.org:
bug#70144; Package guile. (Tue, 02 Apr 2024 14:28:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Christopher Baines <mail <at> cbaines.net>:
New bug report received and forwarded. Copy sent to bug-guile <at> gnu.org. (Tue, 02 Apr 2024 14:28:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Christopher Baines <mail <at> cbaines.net>
To: bug-guile <at> gnu.org
Subject: system* affects signal handlers
Date: Tue, 02 Apr 2024 15:22:57 +0100
[Message part 1 (text/plain, inline)]
I've encountered a situation where signal handlers don't seem to
run. With the following program, sending it SIGINT won't trigger the
handler, however if you remove the system* call, then the handler will
run.

  (use-modules (ice-9 threads))

  (call-with-new-thread
   (lambda ()
     ;; Remove the following system* call to fix the handler
     (system* "echo" "foo")))

  (sigaction SIGINT
    (lambda (sig)
      (peek "SIGINT handler")
      (exit 1)))

  (for-each
   (lambda _
     (sleep 1))
   (iota 30))

  (display "normal exit\n")
[signature.asc (application/pgp-signature, inline)]

Information forwarded to bug-guile <at> gnu.org:
bug#70144; Package guile. (Wed, 03 Apr 2024 08:29:01 GMT) Full text and rfc822 format available.

Message #8 received at 70144 <at> debbugs.gnu.org (full text, mbox):

From: Mikael Djurfeldt <mikael <at> djurfeldt.com>
To: Christopher Baines <mail <at> cbaines.net>
Cc: Mikael Djurfeldt <mikael <at> djurfeldt.com>, 70144 <at> debbugs.gnu.org
Subject: Re: bug#70144: system* affects signal handlers
Date: Wed, 3 Apr 2024 10:28:09 +0200
[Message part 1 (text/plain, inline)]
system* temporarily re-binds signal handlers to prevent the child process
from killing the parent. Thus, it is not thread safe with regard to SIGINT
(or SIGQUIT if available). So, your code has a race condition with respect
to the signal handler. This common resource can, in principle, be handled
the usual way by, for example, utilizing a mutex:

(use-modules (ice-9 threads))

(define sigint-mutex (make-mutex))

(define thread
  (call-with-new-thread
   (lambda ()
     (with-mutex sigint-mutex
       (system* "echo" "foo")))))

(with-mutex sigint-mutex
  (sigaction SIGINT
    (lambda (sig)
      (peek "SIGINT handler")
      (exit 1)))

  (for-each
   (lambda _
     (sleep 1))
   (iota 30)))

(join-thread thread)

(display "normal exit\n")

But if this was real code, another way would be to make sure that the code
blocks are run in the order that you wish (which you did not want here
since your very purpose was to provoke the collision of resources).

I'm leaving this bug open. *Should* system* re-bind the signal handlers?
Should it really protect itself from the child? If so, we should probably
document this behaviour in the reference manual.

Best regards,
Mikael

On Tue, Apr 2, 2024 at 4:28 PM Christopher Baines <mail <at> cbaines.net> wrote:

> I've encountered a situation where signal handlers don't seem to
> run. With the following program, sending it SIGINT won't trigger the
> handler, however if you remove the system* call, then the handler will
> run.
>
>   (use-modules (ice-9 threads))
>
>   (call-with-new-thread
>    (lambda ()
>      ;; Remove the following system* call to fix the handler
>      (system* "echo" "foo")))
>
>   (sigaction SIGINT
>     (lambda (sig)
>       (peek "SIGINT handler")
>       (exit 1)))
>
>   (for-each
>    (lambda _
>      (sleep 1))
>    (iota 30))
>
>   (display "normal exit\n")
>
[Message part 2 (text/html, inline)]

Information forwarded to bug-guile <at> gnu.org:
bug#70144; Package guile. (Thu, 02 May 2024 14:19:02 GMT) Full text and rfc822 format available.

Message #11 received at 70144 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Mikael Djurfeldt <mikael <at> djurfeldt.com>
Cc: 70144 <at> debbugs.gnu.org, Josselin Poiret <dev <at> jpoiret.xyz>,
 Christopher Baines <mail <at> cbaines.net>
Subject: Re: bug#70144: system* affects signal handlers
Date: Thu, 02 May 2024 16:17:49 +0200
Hi,

Mikael Djurfeldt <mikael <at> djurfeldt.com> skribis:

> system* temporarily re-binds signal handlers to prevent the child process
> from killing the parent. Thus, it is not thread safe with regard to SIGINT
> (or SIGQUIT if available). So, your code has a race condition with respect
> to the signal handler. This common resource can, in principle, be handled
> the usual way by, for example, utilizing a mutex:

[...]

> I'm leaving this bug open. *Should* system* re-bind the signal handlers?
> Should it really protect itself from the child? If so, we should probably
> document this behaviour in the reference manual.

Unless I’m mistaken, we can remove the ‘scm_dynwind_sigaction’ calls
from ‘scm_system_star’: now that we use ‘posix_spawn’, this is all taken
care of.

This can be seen by running:

  strace -o /tmp/log.strace -f guile -c '(system* "/bin/sh" "-c" "echo foo $$")'

… which shows pre-fork signal blocking (this is
‘internal_signal_block_all’ in spawni.c in glibc) followed, in the child
(PID 28592 here), by a long series of ‘sigaction’ calls to reset
handlers to their default behavior:

--8<---------------cut here---------------start------------->8---
28586 rt_sigprocmask(SIG_BLOCK, ~[], [], 8) = 0
28586 clone3({flags=CLONE_VM|CLONE_VFORK, exit_signal=SIGCHLD, stack=0x7f73b39b2000, stack_size=0x9000}, 88 <unfinished ...>
28592 rt_sigprocmask(SIG_BLOCK, NULL, ~[KILL STOP], 8) = 0
28592 rt_sigaction(SIGHUP, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
28592 rt_sigaction(SIGHUP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f73b432d2a0}, NULL, 8) = 0
28592 rt_sigaction(SIGINT, NULL, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f73b432d2a0}, 8) = 0
28592 rt_sigaction(SIGQUIT, NULL, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f73b432d2a0}, 8) = 0
28592 rt_sigaction(SIGILL, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
28592 rt_sigaction(SIGILL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f73b432d2a0}, NULL, 8) = 0
28592 rt_sigaction(SIGTRAP, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
28592 rt_sigaction(SIGTRAP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f73b432d2a0}, NULL, 8) = 0
--8<---------------cut here---------------end--------------->8---

Josselin, can you confirm?

Thanks,
Ludo’.




This bug report was last modified 1 day ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.