Segfaulting Program – Piping Output from a Segfaulting Program

iopipesegmentation faultshell

I have a script that calls a program (specifically, ttf2afm, part of tetex 3.0) that sometimes segfaults and sometimes doesn't. The information I need is always printed out before it segfaults, but I'm having a hard time stopping the pipe redirection from failing and not outputting anything to the pipe when the program fails.

I've tried redirecting through a FIFO, parenthesizing the process with a true at the end, executing from a shell function and encasing in sh -c, but the script never seems to let the process output anything, redirected or otherwise–not even to stderr.

I know it is capable of output, being that it's perfectly capable of giving it from the command-line, but not from a script for some reason.

My question is, is there any way for the script to ignore the fact that the program segfaults and give me the output anyway?

I'm running BASH 4.1.10(2)-release.

Best Answer

Programs typically buffer their output for efficiency. That is, they accumulate output in a memory area (called a buffer), and they actually get the output out only when the buffer is full or at certain key points in the program. When the program ends normally, it flushes the output buffer (i.e. prints out any data that's left in it). When it segfaults, the content of the buffer is lost.

You don't observe this effect when running the program directly in a terminal because the behavior is different when the program's output is connected to a terminal (as opposed to a regular file or a pipe). In a terminal, the default behavior is to flush the buffer at the end of each line. Therefore you'll see every complete line that's produced up to the point when the program segfaults.

You can force the program to run in a terminal and collect its output. The simplest way is to run script. There are a number of annoyances that you'll need to work around:

  • script adds a header line to the transcript file, which you'll need to remove afterwards.
  • script doesn't return the status code of the command, so you'll need to save it somewhere if you want to know about the segfault or any other error.
  • script will cause normal output and error out; you'd better save the error output to a separate file.
export FONT="foo"
script -q -c '
    ttf2afm "$FONT.ttf" 2>"$FONT.ttf2afm-err";
    echo $? >"$FONT.ttf2afm-status"
' "$FONT.ttf2afm-typescript"
tail -n +2 <"$FONT.ttf2afm-typescript" >"foo.afm"
rm "$FONT.ttf2afm-typescript"
if [ "$(cat "$FONT.ttf2afm-status")" -ne 0 ]; then
  echo 1>&2 "Warning: ttf2afm failed"
  cat "$FONT.ttf2afm-err"
fi