How to restore ignored signals

233 views
Skip to first unread message

Manlio Perillo

unread,
May 21, 2021, 10:49:32 AM5/21/21
to golang-nuts
In a program I want to read a password from the terminal, using golang.org/x/term.
The problem is that there is a possibility that a signal is sent to the program, resulting in the terminal state not being restored:

In case of term.ReadPassword, on Linux I noted that ECHO is restored, but let's ignore it.

What I tried to do was to ttemporarily block the signals, using signal.Ignore and signal.Reset; the problem is that Reset doesn't reset ignored signals.

Looking at the runtime code, Go only use SIG_DFL in special cases.
Is there a reason why Reset don't reset ignore signals?  Portability?

Is there a simple, portable way, to do what I want?

Thanks
Manlio

Ian Lance Taylor

unread,
May 21, 2021, 4:22:08 PM5/21/21
to Manlio Perillo, golang-nuts
I thought that signal.Reset would reset a signal ignored by
signal.Ignore. What happens when you try it?

In any case I don't see why your program wants to ignore signals. It
seems better to catch the signal, restore the terminal, and exit.

Ian

Manlio Perillo

unread,
May 21, 2021, 4:36:44 PM5/21/21
to golang-nuts
On Friday, May 21, 2021 at 10:22:08 PM UTC+2 Ian Lance Taylor wrote:
On Fri, May 21, 2021 at 7:49 AM Manlio Perillo <manlio....@gmail.com> wrote:
>
> In a program I want to read a password from the terminal, using golang.org/x/term.
> The problem is that there is a possibility that a signal is sent to the program, resulting in the terminal state not being restored:
> https://play.golang.org/p/4IjLve9gDx0
>
> In case of term.ReadPassword, on Linux I noted that ECHO is restored, but let's ignore it.
>
> What I tried to do was to ttemporarily block the signals, using signal.Ignore and signal.Reset; the problem is that Reset doesn't reset ignored signals.
>
> Looking at the runtime code, Go only use SIG_DFL in special cases.
> Is there a reason why Reset don't reset ignore signals? Portability?
>
> Is there a simple, portable way, to do what I want?

I thought that signal.Reset would reset a signal ignored by
signal.Ignore. What happens when you try it?


In https://play.golang.org/p/c88iu09mOgO,  the SIGINT signal (via Ctrl-C) is ignored after the call to `signal.Ignore`.
However SIGINT is still ignored after the call to `signal.Reset`.
 
In any case I don't see why your program wants to ignore signals. It
seems better to catch the signal, restore the terminal, and exit.


In some C/C++ programs I have often see the use sigprocmask:

I think that it is more convenient to ignore all signals, since I don't need to specify each signal explicitly (requiring the use of build tags for portability).
However it is true that in this simple case (a command line program), the only signal to handle is SIGINT.

Thanks
Manlio 

Ian Lance Taylor

unread,
May 21, 2021, 4:44:01 PM5/21/21
to Manlio Perillo, golang-nuts
On Fri, May 21, 2021 at 1:37 PM Manlio Perillo <manlio....@gmail.com> wrote:
>
> On Friday, May 21, 2021 at 10:22:08 PM UTC+2 Ian Lance Taylor wrote:
>>
>> On Fri, May 21, 2021 at 7:49 AM Manlio Perillo <manlio....@gmail.com> wrote:
>> >
>> > In a program I want to read a password from the terminal, using golang.org/x/term.
>> > The problem is that there is a possibility that a signal is sent to the program, resulting in the terminal state not being restored:
>> > https://play.golang.org/p/4IjLve9gDx0
>> >
>> > In case of term.ReadPassword, on Linux I noted that ECHO is restored, but let's ignore it.
>> >
>> > What I tried to do was to ttemporarily block the signals, using signal.Ignore and signal.Reset; the problem is that Reset doesn't reset ignored signals.
>> >
>> > Looking at the runtime code, Go only use SIG_DFL in special cases.
>> > Is there a reason why Reset don't reset ignore signals? Portability?
>> >
>> > Is there a simple, portable way, to do what I want?
>>
>> I thought that signal.Reset would reset a signal ignored by
>> signal.Ignore. What happens when you try it?
>>
>
> In https://play.golang.org/p/c88iu09mOgO, the SIGINT signal (via Ctrl-C) is ignored after the call to `signal.Ignore`.
> However SIGINT is still ignored after the call to `signal.Reset`.

That is odd. Would you mind opening an issue with a test case? Thanks.


>> In any case I don't see why your program wants to ignore signals. It
>> seems better to catch the signal, restore the terminal, and exit.
>>
>
> In some C/C++ programs I have often see the use sigprocmask:
> https://www.gnu.org/software/libc/manual/html_node/Why-Block.html

Using sigprocmask is not the same as using signal.Ignore. sigprocmask
will temporarily block the signal until the old signal mask is
restored, at which point the signal will be delivered. signal.Ignore
will cause the signal to be ignored completely. That is,
signal.Ignore is like using sigaction to change the handler to
SIG_IGN. It is not like sigprocmask.

Ian

Brian Candler

unread,
May 21, 2021, 4:47:30 PM5/21/21
to golang-nuts
If I understand rightly, it boils down to this:
The documentation does say "Reset undoes the effect of any prior calls to Notify for the provided signals", without mentioning any effect on Ignore'd signals.

Ian Lance Taylor

unread,
May 21, 2021, 5:43:24 PM5/21/21
to Brian Candler, golang-nuts
On Fri, May 21, 2021 at 1:47 PM Brian Candler <b.ca...@pobox.com> wrote:
>
> If I understand rightly, it boils down to this:
> https://play.golang.org/p/vYlTzluIuBL

Thanks. That's clearly a bug. The sig.ignored mask is not being
updated when it should be.

> The documentation does say "Reset undoes the effect of any prior calls to Notify for the provided signals", without mentioning any effect on Ignore'd signals.

I think that is incomplete.

Ian
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/4033638c-347e-4c13-9a3f-bab3fbeb006an%40googlegroups.com.

Manlio Perillo

unread,
May 22, 2021, 8:48:51 AM5/22/21
to golang-nuts
On Friday, May 21, 2021 at 11:43:24 PM UTC+2 Ian Lance Taylor wrote:
On Fri, May 21, 2021 at 1:47 PM Brian Candler <b.ca...@pobox.com> wrote:
>
> If I understand rightly, it boils down to this:
> https://play.golang.org/p/vYlTzluIuBL

Thanks. That's clearly a bug. The sig.ignored mask is not being
updated when it should be.

> The documentation does say "Reset undoes the effect of any prior calls to Notify for the provided signals", without mentioning any effect on Ignore'd signals.

I think that is incomplete.

Ian

I checked with old versions (until go1.11) and the behavior is the same. 

I opened a new issue.

Manlio

Manlio Perillo

unread,
May 22, 2021, 8:53:36 AM5/22/21
to golang-nuts
On Friday, May 21, 2021 at 10:44:01 PM UTC+2 Ian Lance Taylor wrote:
On Fri, May 21, 2021 at 1:37 PM Manlio Perillo <manlio....@gmail.com> wrote:
>
> [...]

>
> In https://play.golang.org/p/c88iu09mOgO, the SIGINT signal (via Ctrl-C) is ignored after the call to `signal.Ignore`.
> However SIGINT is still ignored after the call to `signal.Reset`.

That is odd. Would you mind opening an issue with a test case? Thanks.


Done.  Thanks to Brian Candler for the example.
 

>> In any case I don't see why your program wants to ignore signals. It
>> seems better to catch the signal, restore the terminal, and exit.
>>
>
> In some C/C++ programs I have often see the use sigprocmask:
> https://www.gnu.org/software/libc/manual/html_node/Why-Block.html

Using sigprocmask is not the same as using signal.Ignore. sigprocmask
will temporarily block the signal until the old signal mask is
restored, at which point the signal will be delivered. signal.Ignore
will cause the signal to be ignored completely. That is,
signal.Ignore is like using sigaction to change the handler to
SIG_IGN. It is not like sigprocmask.


I'm curious to know if sigprocmask is safe/convenient to use in a Go program.

Thanks
Manlio

Ian Lance Taylor

unread,
May 22, 2021, 6:29:47 PM5/22/21
to Manlio Perillo, golang-nuts
On Sat, May 22, 2021 at 5:53 AM Manlio Perillo <manlio....@gmail.com> wrote:
>
> I'm curious to know if sigprocmask is safe/convenient to use in a Go program.

It's possible, of course, but it's not particularly convenient.
sigprocmask isn't a good fit for multi-threaded programs, and most Go
programs are multi-threaded. For cases where C programs use
sigprocmask Go programs normally use signal.Notify. signal.Notify
already lets the Go program handle the signal at a convenient time,
which is the main benefit of using sigprocmask in a single-threaded C
program.

Ian

Manlio Perillo

unread,
May 24, 2021, 9:05:36 AM5/24/21
to golang-nuts
There is a difference, however.
With signal.Notify, after receiving the signal you usually exit the program (probably calling atexit functions).
However this is not always safe.  As an example:

r := acquire(...)
atexit(r.release)

In a Go program it may be possible that the atexit function is not called before exit is called by Notify.

Thanks 
Reply all
Reply to author
Forward
0 new messages