Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Displaying or redirecting a shell's job control messages

TL;DR

All job control / crash messages are hidden when they occur within a function. I go into more detail below, but @Barmar has pointed out that this issue can be reproduced by running a crashing binary inside of a function, e.g:

crun() { 
  /tmp/faulty $1 $2 $3
}

I've defined a function in my .zshrc to compile & run source code with the function below:

crun() {
    local file=$1
    shift
    local exepath="$(mktemp)"

    if [[ $file =~ "\.c$" ]]; then
        gcc -g -Wall $file -o $exepath || return $?
    else
        echo "no filetype detected"
        return 126
    fi

    $exepath "$@"
}

Which can be called in this fashion:

% crun source.cc arg_1 arg_2

This works for normal programs, but has the problem that the shell's job control messages, such as those generated from a segfault, do not appear.

As an example:

% echo 'int main=0;' >> /tmp/faulty.c # a crashing c program
% crun faulty.c
% # no output generated

Whereas the equivalent interactive commands would generate this:

% g++ faulty.c -o /tmp/faulty && /tmp/faulty
[1] 2894 segmentation fault (core dumped) # 🢀 zsh's job control output for SIGSEGV

Is there any way to display these messages for a crashing executable whose path is dynamically calculated? Ideally without writing your own trap/signal handlers + exec, using sh -c "$exepath $@", or writing a totally new system(3) wrapper entirely)

like image 832
ŹV - Avatar asked Nov 08 '22 19:11

ŹV -


1 Answers

You can get zsh to print the segmentation fault message from the job if you start it as a background job and then immediately bring it to the foreground.

"$exepath" "$@" &
fg

This will cause zsh to print out messages for signals on the job started for $exepath.

The downside is that you will get a little bit more than you bargained for:

% crun faulty.c
faulty.c:1:5: warning: ‘main’ is usually a function [-Wmain]
 int main=0;
     ^~~~
[2] 2080
[2]  - running    "$exepath" "$@"
zsh: segmentation fault (core dumped)  "$exepath" "$@"

But as shown, you will get the segfault messages printed in the terminal.

Because the messages are printed by the interactive shell, not the failing process, the job messages won't get redirected should you try to redirect stdout or stderr.

So on the one hand, should you try to take useful output out of your running process and redirect it somewhere else, you don't need to worry about the job messages getting in the way. But this also means you won't get the segfault message should you try to redirect it by redirecting stderr.

Here's a demonstration of this effect, with line breaks added in-between commands for clarity:

% crun good.c > test
[2] 2071
[2]  - running    "$exepath" "$@"

% cat test
Hello, world!

% crun faulty.c 2>test
[2] 2092
[2]  - running    "$exepath" "$@"
zsh: segmentation fault (core dumped)  "$exepath" "$@"

% cat test
faulty.c:1:5: warning: ‘main’ is usually a function [-Wmain]
 int main=0;
     ^~~~

For more information, see zsh's documentation on jobs and signals. You can also poke around the C file where the magic happens.

like image 50
Adaline Simonian Avatar answered Nov 15 '22 06:11

Adaline Simonian