[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Fix exit status of signal handlers in shell scripts
From: |
Dmitry V. Levin |
Subject: |
[PATCH] Fix exit status of signal handlers in shell scripts |
Date: |
Sat, 30 Jan 2010 22:12:01 +0300 |
Hi,
There is a comment about shell signal handlers in gnulib-tool saying that
"The value of $? is 128 + signal number and is set before the
trap-registered command is run". Unfortunately, this comment is wrong,
and it seems to be a widespread misunderstanding.
The GNU Autoconf manual says that "it is widely admitted that when
entering the trap `$?' should be set to the exit status of the last
command run before the trap."
In case of signal handler, the exit status of the last command run
before the trap might be 128 + signal number, this usually happens when
the last command before the trap was a process terminated by signal. In
other cases, the value of $? may be arbitrary. Sometimes it's quite
hard to guess this value due to race conditions. Here is an example of
such race condition where the value of $? takes one of 3 different
values: 0, 1 and 143:
$ for i in `seq 0 9`; do sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done' & pid=$! && sleep 0.01 && kill -TERM -$pid && wait $pid; done
[1] 5122
Terminated
[1]+ Exit 143 sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
[1] 5142
Terminated
[1]+ Exit 143 sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
[1] 5165
[1]+ Exit 1 sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
[1] 5201
[1]+ Done sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
[1] 5238
Terminated
[1]+ Exit 143 sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
[1] 5271
[1]+ Exit 1 sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
[1] 5306
Terminated
[1]+ Exit 143 sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
[1] 5341
Terminated
[1]+ Exit 143 sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
[1] 5376
[1]+ Done sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
[1] 5411
[1]+ Done sh -c 'trap "exit \$?" TERM; while /bin/true; do
/bin/false; done'
Proposed patch is attached. It doesn't fix multiple trap bugs in the
test suite, though:
$ grep -r '\<trap[[:space:]].*15' tests/
tests/uniwidth/test-uc_width2.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-vc-list-files-git.sh:trap '(exit $?); exit $?' 1 2 13 15
tests/test-yesno.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-vprintf-posix.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-fpending.sh:trap 'rm -fr $tmpfile' 1 2 3 15
tests/test-tsearch.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-xstrtoimax.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-perror.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-fprintf-posix.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-select-out.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-binary-io.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-vc-list-files-cvs.sh:trap '(exit $?); exit $?' 1 2 13 15
tests/test-xstrtol.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-dprintf-posix.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-xstrtoumax.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-printf-posix.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-atexit.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-select-in.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-xprintf-posix.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-closein.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-sigpipe.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-update-copyright.sh:trap 'rm -f $TMP_BASE*' 0 1 2 3 15
tests/test-lseek.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-vdprintf-posix.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-vfprintf-posix.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-c-stack2.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
tests/test-c-stack.sh:trap 'rm -fr $tmpfiles' 1 2 3 15
What's wrong with these "trap 'rm -fr $tmpfiles' 1 2 3 15" lines?
This signal handler does no process termination thus leaving things in
an inconsistent state. Proper fix would be to use functions from
tests/init.sh
--
ldv
gnulib-trap.patch
Description: Text document
pgppZ1b4QYOSr.pgp
Description: PGP signature