mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Fix signal exit status of last command in subshell (re: b3050769
)
Reproducer (on macOS/*BSD where SIGUSR1 has signal number 30): $ ksh -c '(sh -c '\''kill -s USR1 $$'\''); echo $?' ksh: 54220: User signal 1 30 Expected output for $?: 286, not 30. The signal is not reflected in the 9th bit of the exit status. This bug was introduced for virtual subshells inb3050769
but exists in every ksh93 version for real (forked) subshells: $ ksh -c '(ulimit -t unlimited; trap : EXIT; \ sh -c '\''kill -s USR1 $$'\''); echo $?' ksh: 54267: User signal 1 30 (As ofd6c9821c
, a dummy trap is needed to trigger the bug, or it will be masked by the exec optimization for the sh invocation.) This is caused by the exit status being masked to 8 bits when a subshell terminates. For a real subshell, this is inevitable as the kernel does this. As ofb3050769
, virtual subshells behave in a manner consistent with real subshells in this regard. However, for both virtual and real subshells, if its last command was terminated by a signal, then that should still be reflected in the 9th bit of ksh's exit stauts. The root of the problem is that ksh simply cannot rely internally on the 9th bit of the exit status to determine if a command exited due to a signal. The 9th bit may be trimmed by a subshell or may be set by 'return' without a signal being involved. This commit fixes it by introducing a separate flag which will be a reliable indicator of this. src/cmd/ksh93/include/shell.h: - Add sh.chldexitsig flag (set if the last command was a child process that exited due to a signal). src/cmd/ksh93/sh/jobs.c: job_wait(): - When the last child process exited due to a signal, not only set the 9th (SH_EXITSIG) bit of sh.exitval but also sh.chldexitsig. src/cmd/ksh93/sh/subshell.c: sh_subshell(): - Fix the virtual subshell reproducer above. After trimming the exit status to 8 bit, set the 9th bit if sh.chldexitsig is set. This needs to be done in two places: one that runs in the parent process after sh_subfork() and one for the regular virtual subshell exit. src/cmd/ksh93/sh/fault.c: - sh_trap(): Save and restore sh.chldexitsig so that this fix does not get deactivated if a trap is set. - sh_done(): - Fix the real subshell reproducer above. When the last command of a real subshell is a child process that exited due to a signal (i.e., if (sh.chldexitsig && sh.realsubshell)), then activate the code to pass down the signal to the parent process. Since there is no way to pass a 9-bit exit status to a parent process, this is the only way to ensure a correct exit status in the parent shell environment. - When exiting the main shell, use sh.chldexitsig and not the unreliable SH_EXITSIG bit to determine if the 8th bit needs to be set for a portable exit status indicating its last command exited due to a signal.
This commit is contained in:
parent
3688842b72
commit
4df6d674a0
8 changed files with 38 additions and 7 deletions
6
NEWS
6
NEWS
|
@ -3,6 +3,12 @@ For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0
|
|||
|
||||
Any uppercase BUG_* names are modernish shell bug IDs.
|
||||
|
||||
2022-07-02:
|
||||
|
||||
- Fixed a bug where, if the last command in a subshell was an external
|
||||
command that was terminated by a signal, the exit status ($?) of the
|
||||
subshell did not reflect this by adding 256 to the signal number.
|
||||
|
||||
2022-07-01:
|
||||
|
||||
- In scripts, $COLUMNS and $LINES are now kept up to date in scripts at
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue