Bug 18653 - spawn changes SIGPIPE SIG_DFL to SIG_IGN
Summary: spawn changes SIGPIPE SIG_DFL to SIG_IGN
Status: REOPENED
Alias: None
Product: gdb
Classification: Unclassified
Component: gdb (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 7.12
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-07-10 11:57 UTC by Jan Kratochvil
Modified: 2018-01-05 18:34 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Kratochvil 2015-07-10 11:57:24 UTC
That is a program run under GDB "run" behaves differently than standalone.

standalone:                 SIG_DFL
GDB linux-nat:        FAIL: SIG_IGN
GDB gdbserver legacy: PASS: SIG_DFL
GDB gdbserver multi:  FAIL: SIG_IGN

-----------------------------------------
#define _GNU_SOURCE
#include <stdio.h>
#include <signal.h>
int main(void) {
  sighandler_t s=signal(SIGPIPE,SIG_DFL);
  if (s==SIG_DFL) puts("SIG_DFL");
  if (s==SIG_IGN) puts("SIG_IGN");
  return 0;
}
Comment 1 Jan Kratochvil 2016-08-04 11:28:37 UTC
initsigs () at /usr/src/debug/Python-2.7.12/Python/pythonrun.c:1800 - PyOS_setsig(SIGPIPE, SIG_IGN);
initsigs () at /usr/src/debug/Python-3.5.1/Python/pylifecycle.c:1459 - PyOS_setsig(SIGPIPE, SIG_IGN);

gdb -ex 'b signal if $rdi==13' -ex 'b sigaction if $rdi==13' -ex r --args gdb -batch -ex r --args ./pipe
Comment 2 Pedro Alves 2016-08-04 17:39:59 UTC
Patch posted at:
  https://sourceware.org/ml/gdb-patches/2016-08/msg00082.html
Comment 3 cvs-commit@gcc.gnu.org 2016-08-09 19:21:22 UTC
The master branch has been updated by Pedro Alves <palves@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=f348d89aeccaf3eb613e2f31a823baa64300bf88

commit f348d89aeccaf3eb613e2f31a823baa64300bf88
Author: Pedro Alves <palves@redhat.com>
Date:   Tue Aug 9 20:16:20 2016 +0100

    Fix PR gdb/18653: gdb disturbs inferior's inherited signal dispositions
    
    gdb's (or gdbserver's) own signal handling should not interfere with
    the signal dispositions their spawned children inherit.  However, it
    currently does.  For example, some paths in gdb cause SIGPIPE to be
    set to SIG_IGN, and as consequence, the child starts with SIGPIPE to
    set to SIG_IGN too, even though gdb was started with SIGPIPE set to
    SIG_DFL.
    
    This is because the exec family of functions does not reset the signal
    disposition of signals that are set to SIG_IGN:
    
      http://pubs.opengroup.org/onlinepubs/7908799/xsh/execve.html
    
      Signals set to the default action (SIG_DFL) in the calling process
      image are set to the default action in the new process
      image. Signals set to be ignored (SIG_IGN) by the calling process
      image are set to be ignored by the new process image. Signals set to
      be caught by the calling process image are set to the default action
      in the new process image (see <signal.h>).
    
    And neither does it reset signal masks or flags.
    
    In order to be transparent, when spawning new child processes to debug
    (with "run", etc.), reset signal actions and mask back to what was
    originally inherited from gdb/gdbserver's parent, just before execing
    the target program to debug.
    
    gdb/ChangeLog:
    2016-08-09  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* Makefile.in (SFILES): Add
    	common/signals-state-save-restore.c.
    	(HFILES_NO_SRCDIR): Add common/signals-state-save-restore.h.
    	(COMMON_OBS): Add signals-state-save-restore.o.
    	(signals-state-save-restore.o): New rule.
    	* configure: Regenerate.
    	* fork-child.c: Include "signals-state-save-restore.h".
    	(fork_inferior): Call restore_original_signals_state.
    	* main.c: Include "signals-state-save-restore.h".
    	(captured_main): Call save_original_signals_state.
    	* common/common.m4: Add sigaction to AC_CHECK_FUNCS checks.
    	* common/signals-state-save-restore.c: New file.
    	* common/signals-state-save-restore.h: New file.
    
    gdb/gdbserver/ChangeLog:
    2016-08-09  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* Makefile.in (OBS): Add signals-state-save-restore.o.
    	(signals-state-save-restore.o): New rule.
    	* config.in: Regenerate.
    	* configure: Regenerate.
    	* linux-low.c: Include "signals-state-save-restore.h".
    	(linux_create_inferior): Call
    	restore_original_signals_state.
    	* server.c: Include "dispositions-save-restore.h".
    	(captured_main): Call save_original_signals_state.
    
    gdb/testsuite/ChangeLog:
    2016-08-09  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* gdb.base/signals-state-child.c: New file.
    	* gdb.base/signals-state-child.exp: New file.
    	* gdb.gdb/selftest.exp (do_steps_and_nexts): Add new pattern.
Comment 4 cvs-commit@gcc.gnu.org 2016-08-09 19:23:07 UTC
The gdb-7.12-branch branch has been updated by Pedro Alves <palves@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=35fcb4fc81e51295d14125785765e0ea3e132cd9

commit 35fcb4fc81e51295d14125785765e0ea3e132cd9
Author: Pedro Alves <palves@redhat.com>
Date:   Tue Aug 9 20:21:08 2016 +0100

    Fix PR gdb/18653: gdb disturbs inferior's inherited signal dispositions
    
    gdb's (or gdbserver's) own signal handling should not interfere with
    the signal dispositions their spawned children inherit.  However, it
    currently does.  For example, some paths in gdb cause SIGPIPE to be
    set to SIG_IGN, and as consequence, the child starts with SIGPIPE to
    set to SIG_IGN too, even though gdb was started with SIGPIPE set to
    SIG_DFL.
    
    This is because the exec family of functions does not reset the signal
    disposition of signals that are set to SIG_IGN:
    
      http://pubs.opengroup.org/onlinepubs/7908799/xsh/execve.html
    
      Signals set to the default action (SIG_DFL) in the calling process
      image are set to the default action in the new process
      image. Signals set to be ignored (SIG_IGN) by the calling process
      image are set to be ignored by the new process image. Signals set to
      be caught by the calling process image are set to the default action
      in the new process image (see <signal.h>).
    
    And neither does it reset signal masks or flags.
    
    In order to be transparent, when spawning new child processes to debug
    (with "run", etc.), reset signal actions and mask back to what was
    originally inherited from gdb/gdbserver's parent, just before execing
    the target program to debug.
    
    gdb/ChangeLog:
    2016-08-09  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* Makefile.in (SFILES): Add
    	common/signals-state-save-restore.c.
    	(HFILES_NO_SRCDIR): Add common/signals-state-save-restore.h.
    	(COMMON_OBS): Add signals-state-save-restore.o.
    	(signals-state-save-restore.o): New rule.
    	* configure: Regenerate.
    	* fork-child.c: Include "signals-state-save-restore.h".
    	(fork_inferior): Call restore_original_signals_state.
    	* main.c: Include "signals-state-save-restore.h".
    	(captured_main): Call save_original_signals_state.
    	* common/common.m4: Add sigaction to AC_CHECK_FUNCS checks.
    	* common/signals-state-save-restore.c: New file.
    	* common/signals-state-save-restore.h: New file.
    
    gdb/gdbserver/ChangeLog:
    2016-08-09  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* Makefile.in (OBS): Add signals-state-save-restore.o.
    	(signals-state-save-restore.o): New rule.
    	* config.in: Regenerate.
    	* configure: Regenerate.
    	* linux-low.c: Include "signals-state-save-restore.h".
    	(linux_create_inferior): Call
    	restore_original_signals_state.
    	* server.c: Include "dispositions-save-restore.h".
    	(captured_main): Call save_original_signals_state.
    
    gdb/testsuite/ChangeLog:
    2016-08-09  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* gdb.base/signals-state-child.c: New file.
    	* gdb.base/signals-state-child.exp: New file.
    	* gdb.gdb/selftest.exp (do_steps_and_nexts): Add new pattern.
Comment 5 Pedro Alves 2016-08-09 19:23:38 UTC
Fixed.
Comment 6 Jan Kratochvil 2017-11-03 18:32:24 UTC
I think the fix is incomplete:
 - it does fix spawned inferiors
 - it does not fix "shell" commands:
grep SigIgn /proc/self/status;./gdb -data-directory data-directory/ -batch -ex '! grep SigIgn /proc/self/status' -ex start -ex 'call (int)system("grep SigIgn /proc/self/status")' --args echo
SigIgn:	0000000000000000
SigIgn:	0000000001001000
Temporary breakpoint 1 at 0x1420: file ../src/echo.c, line 109.
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffd768) at ../src/echo.c:109
109	{
SigIgn:	0000000000000000
$1 = 0


A second issue:
https://bugzilla.redhat.com/show_bug.cgi?id=1473411#c2

The all-zeros SigIgn is a bit weak. You really want to make sure that if gdb starts with something ignored, then the child process ALSO gets started with that same signal ignored.  With working gdb, here's a slightly stronger test:

$ ( trap - BUS; sleep 30& grep SigIgn /proc/$!/status )
SigIgn:	0000000000000006
$ ( trap '' BUS; sleep 30& grep SigIgn /proc/$!/status )
SigIgn:	0000000000000046

Proof that we can control whether 0x40 is ignored during sleep using just the shell (the shell also ignores SIGINT and SIGQUIT during background tasks; that's life, hence why I used SIGBUS to show what I'm actually toggling)

$ ( trap '' BUS; gdb --args sleep 30 )
GNU gdb (GDB) Fedora 8.0-13.fc26
...
(gdb) ! grep SigIgn /proc/self/status
SigIgn:	0000000001001040

# So gdb started with SIGBUS ignored, and additionally ignores SIGPIPE itself...

(gdb) b main
Breakpoint 1 at 0x1590
(gdb) r
Starting program: /usr/bin/sleep 30

Breakpoint 1, 0x0000555555555590 in main ()
(gdb) info thread
  Id   Target Id         Frame 
* 1    process 27153 "sleep" 0x0000555555555590 in main ()
(gdb) ! grep SigIgn /proc/27153/status
SigIgn:	0000000000000040

# ...but the child process sees JUST SIGBUS ignored (ie. the exact environment that we started gdb with, prior to gdb fudging things around)
Comment 7 Andrew Pinski 2017-12-14 20:00:38 UTC
Also this causes gdb to be useless if you LD_PRELOAD of libSegFault.so.  You get an internal error right at the beginning of running gdb.  Is this by design and maybe the internal error should be changed to be sorry if the address of the function is not located in gdb itself or rather in a shared library.
Comment 8 Pedro Alves 2017-12-14 23:56:25 UTC
Indeed, we get:

(top-gdb) bt
#0  0x000000000056b001 in internal_error(char const*, int, char const*, ...) (file=0xaf5f38 "src/gdb/common/signals-state-save-restore.c", line=64, fmt=0xaf5f18 "unexpected signal handler") at src/gdb/common/errors.c:54
#1  0x00000000005752c9 in save_original_signals_state() () at src/gdb/common/signals-state-save-restore.c:64
#2  0x00000000007425de in captured_main_1(captured_main_args*) (context=0x7fffffffd860)
    at src/gdb/main.c:509
#3  0x0000000000743622 in captured_main(void*) (data=0x7fffffffd860) at src/gdb/main.c:1145
During symbol reading, cannot get low and high bounds for subprogram DIE at 24065.
#4  0x00000000007436f9 in gdb_main(captured_main_args*) (args=0x7fffffffd860) at src/gdb/main.c:1171
#5  0x0000000000413acd in main(int, char**) (argc=1, argv=0x7fffffffd968) at src/gdb/gdb.c:32

How about this?  Too noisy?

~~~~~~~~~~~~~~~~~~~~~
$ LD_PRELOAD=/usr/lib64/libSegFault.so  ./gdb ~/gdb/tests/threads
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 8.0.50.20171213-git
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /home/pedro/gdb/tests/threads...done.
(gdb)
~~~~~~~~~~~~~~~~~~~~~
Comment 9 Andrew Pinski 2017-12-14 23:58:32 UTC
(In reply to Pedro Alves from comment #8)
> How about this?  Too noisy?

As long as -q disables the message this is ok to me.
Comment 10 cvs-commit@gcc.gnu.org 2018-01-05 18:31:08 UTC
The master branch has been updated by Pedro Alves <palves@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e379cee61f3890e535e995828e8846b020ef2a32

commit e379cee61f3890e535e995828e8846b020ef2a32
Author: Pedro Alves <palves@redhat.com>
Date:   Fri Jan 5 18:26:18 2018 +0000

    Fix regression: cannot start with LD_PRELOAD=libSegFault.so (PR gdb/18653#c7)
    
    At https://sourceware.org/bugzilla/show_bug.cgi?id=18653#c7, Andrew
    reports that the fix for PR gdb/18653 made GDB useless if you preload
    libSegFault.so, because GDB internal-errors on startup:
    
     $ LD_PRELOAD=libSegFault.so gdb
     src/gdb/common/signals-state-save-restore.c:64: internal-error: unexpected signal handler
     A problem internal to GDB has been detected,
     further debugging may prove unreliable.
     Aborted (core dumped)
     $
    
    The internal error comes from the code saving the signal dispositions
    inherited from gdb's parent:
    
     (top-gdb) bt
     #0  0x000000000056b001 in internal_error(char const*, int, char const*, ...) (file=0xaf5f38 "src/gdb/common/signals-state-save-restore.c", line=64, fmt=0xaf5f18 "unexpected signal handler") at src/gdb/common/errors.c:54
     #1  0x00000000005752c9 in save_original_signals_state() () at src/gdb/common/signals-state-save-restore.c:64
     #2  0x00000000007425de in captured_main_1(captured_main_args*) (context=0x7fffffffd860)
         at src/gdb/main.c:509
     #3  0x0000000000743622 in captured_main(void*) (data=0x7fffffffd860) at src/gdb/main.c:1145
     During symbol reading, cannot get low and high bounds for subprogram DIE at 24065.
     #4  0x00000000007436f9 in gdb_main(captured_main_args*) (args=0x7fffffffd860) at src/gdb/main.c:1171
     #5  0x0000000000413acd in main(int, char**) (argc=1, argv=0x7fffffffd968) at src/gdb/gdb.c:32
    
    This commit downgrades the internal error to a warning.  You'll get
    instead:
    
    ~~~
     $ LD_PRELOAD=libSegFault.so gdb
     warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
     Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
     won't be propagated to spawned programs.
     GNU gdb (GDB) 8.0.50.20171213-git
     Copyright (C) 2017 Free Software Foundation, Inc.
     License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
     This is free software: you are free to change and redistribute it.
     There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
     and "show warranty" for details.
     This GDB was configured as "x86_64-pc-linux-gnu".
     Type "show configuration" for configuration details.
     For bug reporting instructions, please see:
     <http://www.gnu.org/software/gdb/bugs/>.
     Find the GDB manual and other documentation resources online at:
     <http://www.gnu.org/software/gdb/documentation/>.
     For help, type "help".
     Type "apropos word" to search for commands related to "word"...
     (gdb)
    ~~~
    
    This also moves the location where save_original_signals_state is
    called a bit further below (to after option processing), so that "-q"
    disables the warning:
    
    ~~~
     $ LD_PRELOAD=libSegFault.so gdb -q
     (gdb)
    ~~~
    
    New testcase included.
    
    gdb/ChangeLog:
    2018-01-05  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* common/signals-state-save-restore.c
    	(save_original_signals_state): New parameter 'quiet'.  Warn if we
    	find a custom handler preinstalled, instead of internal erroring.
    	But only warn if !quiet.
    	* common/signals-state-save-restore.h
    	(save_original_signals_state): New parameter 'quiet'.
    	* main.c (captured_main_1): Move save_original_signals_state call
    	after option handling, and pass QUIET.
    
    gdb/gdbserver/ChangeLog:
    2018-01-05  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* server.c (captured_main): Pass quiet=false to
    	save_original_signals_state.
    
    gdb/testsuite/ChangeLog:
    2018-01-05  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* gdb.base/libsegfault.exp: New.
Comment 11 cvs-commit@gcc.gnu.org 2018-01-05 18:34:49 UTC
The gdb-8.1-branch branch has been updated by Pedro Alves <palves@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1ec6a1148ad3ca06f48be269e1b61cb9c61a0938

commit 1ec6a1148ad3ca06f48be269e1b61cb9c61a0938
Author: Pedro Alves <palves@redhat.com>
Date:   Fri Jan 5 18:30:49 2018 +0000

    Fix regression: cannot start with LD_PRELOAD=libSegFault.so (PR gdb/18653#c7)
    
    At https://sourceware.org/bugzilla/show_bug.cgi?id=18653#c7, Andrew
    reports that the fix for PR gdb/18653 made GDB useless if you preload
    libSegFault.so, because GDB internal-errors on startup:
    
     $ LD_PRELOAD=libSegFault.so gdb
     src/gdb/common/signals-state-save-restore.c:64: internal-error: unexpected signal handler
     A problem internal to GDB has been detected,
     further debugging may prove unreliable.
     Aborted (core dumped)
     $
    
    The internal error comes from the code saving the signal dispositions
    inherited from gdb's parent:
    
     (top-gdb) bt
     #0  0x000000000056b001 in internal_error(char const*, int, char const*, ...) (file=0xaf5f38 "src/gdb/common/signals-state-save-restore.c", line=64, fmt=0xaf5f18 "unexpected signal handler") at src/gdb/common/errors.c:54
     #1  0x00000000005752c9 in save_original_signals_state() () at src/gdb/common/signals-state-save-restore.c:64
     #2  0x00000000007425de in captured_main_1(captured_main_args*) (context=0x7fffffffd860)
         at src/gdb/main.c:509
     #3  0x0000000000743622 in captured_main(void*) (data=0x7fffffffd860) at src/gdb/main.c:1145
     During symbol reading, cannot get low and high bounds for subprogram DIE at 24065.
     #4  0x00000000007436f9 in gdb_main(captured_main_args*) (args=0x7fffffffd860) at src/gdb/main.c:1171
     #5  0x0000000000413acd in main(int, char**) (argc=1, argv=0x7fffffffd968) at src/gdb/gdb.c:32
    
    This commit downgrades the internal error to a warning.  You'll get
    instead:
    
    ~~~
     $ LD_PRELOAD=libSegFault.so gdb
     warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
     Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
     won't be propagated to spawned programs.
     GNU gdb (GDB) 8.0.50.20171213-git
     Copyright (C) 2017 Free Software Foundation, Inc.
     License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
     This is free software: you are free to change and redistribute it.
     There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
     and "show warranty" for details.
     This GDB was configured as "x86_64-pc-linux-gnu".
     Type "show configuration" for configuration details.
     For bug reporting instructions, please see:
     <http://www.gnu.org/software/gdb/bugs/>.
     Find the GDB manual and other documentation resources online at:
     <http://www.gnu.org/software/gdb/documentation/>.
     For help, type "help".
     Type "apropos word" to search for commands related to "word"...
     (gdb)
    ~~~
    
    This also moves the location where save_original_signals_state is
    called a bit further below (to after option processing), so that "-q"
    disables the warning:
    
    ~~~
     $ LD_PRELOAD=libSegFault.so gdb -q
     (gdb)
    ~~~
    
    New testcase included.
    
    gdb/ChangeLog:
    2018-01-05  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* common/signals-state-save-restore.c
    	(save_original_signals_state): New parameter 'quiet'.  Warn if we
    	find a custom handler preinstalled, instead of internal erroring.
    	But only warn if !quiet.
    	* common/signals-state-save-restore.h
    	(save_original_signals_state): New parameter 'quiet'.
    	* main.c (captured_main_1): Move save_original_signals_state call
    	after option handling, and pass QUIET.
    
    gdb/gdbserver/ChangeLog:
    2018-01-05  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* server.c (captured_main): Pass quiet=false to
    	save_original_signals_state.
    
    gdb/testsuite/ChangeLog:
    2018-01-05  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/18653
    	* gdb.base/libsegfault.exp: New.