458c1f218b
Upstream commit: Date: Sun, 22 Feb 2009 18:10:01 +0800 [JOBS] Fix dowait signal race This test program by Alexey Gladkov can cause dash to enter an infinite loop in waitcmd. #!/bin/dash trap "echo TRAP" USR1 stub() { echo ">>> STUB $1" >&2 sleep $1 echo "<<< STUB $1" >&2 kill -USR1 $$ } stub 3 & stub 2 & until { echo "###"; wait; } do echo "*** $?" done The problem is that if we get a signal after the wait3 system call has returned but before we get to INTON in dowait, then we can jump back up to the top and lose the exit status. So if we then wait for the job that has just exited, then it'll stay there forever. I made the original change that caused this bug to fix pretty much the same bug but in the opposite direction. That is, if we get a signal after we enter wait3 but before we hit the kernel then it too can cause the wait to go on forever (assuming the child doesn't exit). In fact this is pretty much exactly the scenario that you'll find in glibc's documentation on pause(). The solution is given there too, in the form of sigsuspend, which is the only way to do the check and wait atomically. So this patch fixes Alexey's race without reintroducing the old bug by converting the blocking wait3 to a sigsuspend. In order to do this we need to set a signal handler for SIGCHLD, so the code has been modified to always do that. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> I failed to reproduce the bug (it requires precise timing), but it seems real. function old new delta dowait 284 463 +179 setsignal 301 326 +25 signal_handler 59 76 +17 ash_main 1481 1487 +6 localcmd 350 348 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/1 up/down: 227/-2) Total: 225 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> |
||
---|---|---|
.. | ||
ash_test | ||
hush_test | ||
ash_doc.txt | ||
ash_ptr_hack.c | ||
ash.c | ||
brace.txt | ||
Config.src | ||
cttyhack.c | ||
hush_doc.txt | ||
hush_leaktool.sh | ||
hush.c | ||
Kbuild.src | ||
match.c | ||
match.h | ||
math.c | ||
math.h | ||
random.c | ||
random.h | ||
README | ||
README.job | ||
shell_common.c | ||
shell_common.h |
http://www.opengroup.org/onlinepubs/9699919799/ Open Group Base Specifications Issue 7 http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html Shell & Utilities It says that any of the standard utilities may be implemented as a regular shell built-in. It gives a list of utilities which are usually implemented that way (and some of them can only be implemented as built-ins, like "alias"): alias bg cd command false fc fg getopts jobs kill newgrp pwd read true umask unalias wait http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html Shell Command Language It says that shell must implement special built-ins. Special built-ins differ from regular ones by the fact that variable assignments done on special builtin are *PRESERVED*. That is, VAR=VAL special_builtin; echo $VAR should print VAL. (Another distinction is that an error in special built-in should abort the shell, but this is not such a critical difference, and moreover, at least bash's "set" does not follow this rule, which is even codified in autoconf configure logic now...) List of special builtins: . file : [argument...] break [n] continue [n] eval [argument...] exec [command [argument...]] exit [n] export name[=word]... export -p readonly name[=word]... readonly -p return [n] set [-abCefhmnuvx] [-o option] [argument...] set [+abCefhmnuvx] [+o option] [argument...] set -- [argument...] set -o set +o shift [n] times trap n [condition...] trap [action condition...] unset [-fv] name... In practice, no one uses this obscure feature - none of these builtins gives any special reasons to play such dirty tricks. However. This section also says that *function invocation* should act similar to special built-in. That is, variable assignments done on function invocation should be preserved after function invocation. This is significant: it is not unthinkable to want to run a function with some variables set to special values. But because of the above, it does not work: variable will "leak" out of the function.