Gmong has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

I am looking for a method that can obtain and process the output of a program as well as detect if the program has thrown a segmentation fault.

I know how to do either but not both.In fact, this script will run the method over ssh on another linux machine as it is part of a distributed system.

Any ideas on how I could achieve this?

Many thanks in advance...

  • Comment on Capturing stdout and segfault of a program

Replies are listed 'Best First'.
Re: Capturing stdout and segfault of a program
by Zaxo (Archbishop) on Mar 07, 2005 at 06:21 UTC

    Under POSIX, the behavior of a program after an involuntary SIGSEGV is undefined. That means that you maybe can kill 11, $pid and catch it in the $pid process, but a genuine segfault may never return from whatever libc call generated it.

    Setting signal handlers and capturing output are quite orthogonal. If you can do each, you can do both. I recommend piped ("magic") open for capturing output with a little more control than is given by backticks.

    my $fh; my $cpid = do { local $SIG{SEGV} = \&myhandler; open $fh, '-|', '/path/to/prog', @args or die $!; };

    After Compline,
    Zaxo

Re: Capturing stdout and segfault of a program
by DrHyde (Prior) on Mar 07, 2005 at 10:05 UTC
Re: Capturing stdout and segfault of a program
by sgifford (Prior) on Mar 07, 2005 at 15:03 UTC
    Do you have to do it from within the program itself, or can you use a wrapper program? You generally can't recover from a SIGSEGV, but a wrapper program can easily see that a child process died from a signal and which one (from $?, and can also easily capture its output by setting up pipes as the child process's STDIN and STDOUT.
      The perl script itself is the wrapper to the program. I have gotten to this stage now

      #!/usr/bin/perl -w use POSIX qw(:signal_h :errno_h :sys_wait_h); $command = $ARGV[0]; parse(); if (!defined ($pid = fork())) { die "cannot fork: $!"; } elsif ($pid == 0) { exec("$command"); } else { waitpid($pid, 0); if (WIFEXITED($?)) { print "Exited\n"; } elsif (WIFSIGNALED($?)) { $sig = WTERMSIG($?); if ($sig == 11) { print "Segfault\n"; exit 11; } print "Signaled $sig\n"; } else { print "EH\n"; } } close STDOUT; exit 0; sub parse { my $pid; return if $pid = open(STDOUT, "|- "); die "cannot fork: $!" unless defined $pid; while (my $line = <STDIN>) { print "$line"; } exit; }
      So I am able to capture the program and take note of when it segfaults, and also parse the programs standard out. All I am missing now is capturing the programs stderr...

      Apart from using IO::Capture is there another way that will simply add to the above code, or is this just wishful thinking?

      Thank you very much to everyone who have replied to my question.

        First, see if IPC::Open3 can do what you want. You would use it instead of fork and exec.

        If it doesn't, you'll want to create filehandles for your child process with pipe, then assign them to STDIN, STDOUT, and STDERR after the fork, using POSIX::dup2 or similar.

Re: Capturing stdout and segfault of a program
by monkey_boy (Priest) on Mar 07, 2005 at 09:42 UTC
    Does the seqmentation fault dump a core file?
    check for this after each run, log it & delete it



    This is not a Signature...
      Nope the program doesnt core dump, but thanks for your help.