« first day (82 days earlier)      last day (2317 days later) » 

12:51 AM
@Zanna Thanks! So I think I've figured out why ksh93 raises whatever signal the last command had when you exit it -- as well as why, when pipefail is on and the leftmost command in a pipe that fails (a) does so by crashing and (b) is not also the rightmost command in the pipe, the exit status of the pipe is raw signal number instead of that number plus 256.
 
 
2 hours later…
3:09 AM
So, when a process terminates normally (i.e., not by crashing), it returns a number to the system. That number is represented as an int but only the low order byte is used (at least on Unix-like systems), so it's quite inadvisable to return any value a single byte can't represent. Most shells pretend the exit status of a command that has terminated abnormally, i.e., crashed, is a number in the upper half of the range 0 to 255, or if you think in signed terms, the lower half of -128 to 127.
[C ABIs of all systems I've used use 2's complement to represent negative values of all integral types. But no C standard requires it, and I don't think POSIX does. With other schemes, I think one would want to avoid exiting with anything higher than 127 if the value will ever be interpreted as signed, and need to avoid exiting with anything negative. In most alternatives to 2's complement there's no bijection between unsigned and signed.]
Bash's handling of exit statuses is covered in section 3.7.5 Exit Status of the Bash reference manual. The section is short and I recommend reading it if you haven't. But here's an excerpt that describes the behavior I'm saying most shells have:
> For the shell’s purposes, a command which exits with a zero exit status has succeeded. A non-zero exit status indicates failure. This seemingly counter-intuitive scheme is used so there is one well-defined way to indicate success and a variety of ways to indicate various failure modes. When a command terminates on a fatal signal whose number is N, Bash uses the value 128+N as the exit status.
 
3:37 AM
That demonstrated ksh93 acts differently. It normally considers as exit statuses to be 256 plus the signal number, rather than 128 plus the signal number. It can do this as it lets its special parameter $? take values outside the actual exit status range.
Outside the weird pipefail situation we've been investigating, it looks like there is also an exception to this ksh93 rule of adding to 255 instead of 128 for signal 8 (SIGFPE). But I believe the rule is being followed here, too, and that the program is actually really not crashing. I don't know why, but raising a floating point exception doesn't terminate the process at all. This is not specific to ksh93 callers. It could be a perl thing but I don't see a handler for it. From bash:
ek@Io:~$ perl -we 'use POSIX; raise 8; print "Done.\n"'
Done.
ek@Io:~$
Running those commands in an interactive bash or zsh shell -- but enclosing the last one in ( ) or running set +m to turn off job control first (another difference vs. ksh93, that this is necessary) -- shows the typical (non-ksh93) behavior of treating 128 plus the signal number as though it were the exit status. In bash:
ek@Io:~$ dosig() { perl -we 'use POSIX; raise $ARGV[0]' "$1"; }
ek@Io:~$ trysig() { printf 'Trying signal %d:\n' "$1"; dosig "$1"; echo "$?"; }
ek@Io:~$ trypipedsig() { printf 'Trying signal %d in a pipe:\n' "$1"; dosig "$1" | cat; echo "$?"; }
ek@Io:~$ set -o pipefail
ek@Io:~$ set +m
ek@Io:~$ for i in {1..15}; do trysig "$i"; trypipedsig "$i"; echo; done
Trying signal 1:
129
Trying signal 1 in a pipe:
129

Trying signal 2:
130
Trying signal 2 in a pipe:
130

Trying signal 3:
131
Trying signal 3 in a pipe:
So, now, here is the crux of the whole thing: under most circumstances, a shell returns the exit status of the last command that was run as its own exit status. The major exception is when you run exit N with some number N. But unlike in some languages, exit without no argument in Bourne-style shells doesn't imply 0, unless the shell ran no previous commands. It uses the exit status of the last command.
That is, it uses $?, which is also what it does when it terminates normally because a script is finished. Normally this is fine, because in most shells -- all I've encountered but ksh93 -- $? can only ever take on the value of a valid exit status. Even when its value indicates how a program crashed, it's a value that a program could've actually exited with. ksh93 avoids this "problem," but at the cost that it has to do something when it can't use $? as its own real exit status.
So the solution ksh93 uses is that, when a value of $? is higher than 255, it is converted back into the signal it represents, and ksh93 raises that signal on itself.
 
 
4 hours later…
7:47 AM
@EliahKagan aha 11+128!
 
8:10 AM
@EliahKagan oh yeah, trying signal 8 returned 0. Let's pretend that exception never happened...
@EliahKagan and thus crashes itself if the signal crashes it...
 
 
12 hours later…
8:26 PM
@EliahKagan can you tell me whats wrong with my answer here: askubuntu.com/a/977146/522934
 
8:43 PM
or @Zanna ^
 

« first day (82 days earlier)      last day (2317 days later) »