I have a simple c++ program that raises SIGSEGV:
#include <iostream>
#include <signal.h>
int main() {
std::cout << "Raising seg fault..." << std::endl;
raise(SIGSEGV);
return 0;
}
When running this program I get the following output
Raising seg fault...
Segmentation fault
But when I run my program inside a perl script using pipe, the segmentation fault disappears.
Here is my Perl script:
use strict;
use warnings;
my $cmd ="./test";
open (OUTPUT, "$cmd 2>&1 |") || die();
while (<OUTPUT>) {
print;
}
close (OUTPUT);
my $exit_status = $?>>8;
print "exit status: $exit_status\n";
I get the following output when running the script:
Raising seg fault...
exit status: 0
How could this be possible? Where is the segmentation fault and why is the exit status 0?
You are specifically ignoring the parts of $? that indicate if the process was killed by a signal.
Replace
my $exit_status = $?>>8;
print "exit status: $exit_status\n";
with
die("Killed by signal ".( $? & 0x7F )."\n") if $? & 0x7F;
die("Exited with error ".( $? >> 8 )."\n") if $? >> 8;
print("Completed successfully\n");
Related
This question already has an answer here:
Require exit status !=0 for the main script if script within the system command/backtick fails
(1 answer)
Closed 1 year ago.
Code of inter.pl is:
use strict;
use warnings;
my $var1=`cat /gra/def/ment/ckfile.txt`; #ckfile.txt doesn't exist
print "Hello World";
exit 0;
Code of ext.pl
my $rc = system ("perl inter.pl");
print "$rc is rc\n";
Here, when I run "perl ext.pl", $rc is coming as 0.
Although file inside inter.pl (/gra/def/ment/ckfile.txt) doesn’t exist, I am getting $rc as 0.
I would want $rc to be != 0 (as in one way, it should be an error as file ckfile.txt doesn't exist) in this same scenario.
Note: I can't do any modification in inter.pl
How can it be implemented?
Thanks In Advance.
If you want the program to have an non-zero exit status, you'll need to replace the (useless) exit 0;.
my $var1=`cat /gra/def/ment/ckfile.txt`;
exit 1 if $?;
or
my $var1=`cat /gra/def/ment/ckfile.txt`;
die("Can't spawn child: $!\n") if $? == -1;
die("Child killed by signal ".( $? & 0x7F )."\n") if $? & 0x7F;
die("Child exited with error ".( $? >> 8 )."\n") if $? >> 8;
I am using system to call an external application and I need to interpret its exit code.
I know that system returns the exit code from the command multiplied by 256, but when in foo.bat I write exit 256 the result is zero.
Why is this happening?
Windows uses 32-bit exit codes, so exit 256 is perfectly valid.
>cmd /c exit 256
>echo %ERRORLEVEL%
256
However, Perl only keeps the least significant 8 bits.
>perl -e"system 'exit 256'; CORE::say $?>>8"
0
>perl -e"system 'exit 266'; CORE::say $?>>8"
10
This is a Perl defect for which there's no good reason. If you use Win32::Process instead of system, you can obtain the correct exit code.
>perl -MWin32::Process=NORMAL_PRIORITY_CLASS,INFINITE -e"Win32::Process::Create(my $proc, $ENV{COMSPEC}, 'cmd /c exit 256', 0, NORMAL_PRIORITY_CLASS, '.') or die $^E; $proc->Wait(INFINITE); $proc->GetExitCode(my $exit_code); CORE::say $exit_code;"
256
The return code is a single-byte value from zero to 255.
The most reliable way to check the status of a system call is to examine $?. It's documented in perldoc perlfunc like this
if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
All the possibilities of failure can be obtained by examining $?.
$exit_val = $? >> 8;
$signal = $? & 127;
$dumped_core = $? & 128;`
To quote from perldoc perlvar :
$CHILD_ERROR
$?
The status returned by the last pipe close, backtick (``) command, successful call to wait() or waitpid(), or from the system() operator. This is just the 16-bit status word returned by the traditional Unix wait() system call (or else is made up to look like it). Thus, the exit value of the subprocess is really ($? >> 8 ), and $? & 127 gives which signal, if any, the process died from, and $? & 128 reports whether there was a core dump.
This question already has answers here:
Why is Perl's $? returning the wrong value for the exit code of a forked process?
(2 answers)
Closed 6 years ago.
I have the following perl script (test.pl):
my $exit_code = system('./test.py');
print $exit_code."\n";
that is trying to capture the exit code from a python executable (test.py):
#!/bin/env python
import sys
sys.exit(2)
Directly running python executable returns 2, which is what I expected:
> ./test.py
> echo $?
2
However, running perl returns something different:
> perl test.pl
512
Why did perl capture a different exit code from python?
The child might not even have gotten to call exit. As such, system's returns value (aka $?) packs more information than just the exit parameter.
if ( $? == -1 ) { die "Can't launch child: $!\n"; }
elsif ( $? & 0x7F ) { die "Child killed by signal ".( $? & 0x7F )."\n"; }
elsif ( $? >> 8 ) { die "Child exited with error ".( $? >> 8 )."\n"; }
else { print "Child executed successfully\n"; }
This is documented.
The documentation says "To get the actual exit value, shift right by eight".
Following is C code that is destined to crash:
#include<stdio.h>
#include<stdlib.h>
int main() {
char *p = NULL;
printf("Value at P: %c\n", *p);
return 0;
}
When I compile and run it (RH4 machine with gcc 4.5.2), it predictably gives a segmentation fault:
% ./a.out
Segmentation fault
% echo $status
139
If I run it with Perl v5.8.5, this happens:
% perl -e 'system("./a.out") and die "Status: $?"'
Status: 11 at -e line 1.
The perlvar documentation for $? says that
Thus, the exit value of the subprocess is really ($?>> 8 ), and $? &
127 gives which signal, if any, the process died from, and $? & 128
reports whether there was a core dump.
11 >> 8 is 0, and 11 & 127 is 11.
Why the different exit statuses? If we cannot depend on the exit status, what should be the way to detect segmentation fault in an external command?
Reading the documentation for system might answer your question:
system('a.out');
if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
Output:
child died with signal 11, without coredump
The shell just encodes the signal in the status in a different way: 139 - 128 = 11. For example, man bash says:
The return value of a simple command is its exit status, or 128+n if the command is terminated by signal n.
The OS always sees the same thing... what is returned by the wait(2) family of functions. system(3), et. all, call wait(2). How it peculates up you is what is causing the differences. The shell and the programs do different things and report different ways. Having to shift right 8 to get the most common exit status would be very annoying in shell programs and confuse less tech savvy users.
While the very first UNIX systems I used (genuine Unix) had the same returns I have always wondered if pre-release versions were different and returning the signal and core/dump were a later addition.
My preferred reporting of exit status tends to have the computer split my bits for me.
my $x = $?; #save status
print( "Exit status: %d.%d%s\n",
$x>>8, $x&127, ($x&128)?"*":"" );
I have a Perl script which calls another script. The Perl script should be propagating the script's return code but seems to be returning zero to its caller (a Java application) desipte the explicit call to exit $scriptReturnCode.
Code and output as follows (I realise that <=> could/should be != but that's what I have):
print "INFO: Calling ${scriptDirectory}/${script} ${args}"
$scriptReturnCode = system("${scriptDirectory}/${script} ${args}");
if ( $scriptReturnCode <=> 0 ) {
print "ERROR: The script returned $scriptReturnCode\n";
exit $scriptReturnCode;
} else {
print "INFO: The script returned $scriptReturnCode.\n";
exit 0;
}
The output I have from my Java is:
20/04/2010 14:40:01 - INFO: Calling /path/to/script/script.ksh arg1 arg2
20/04/2010 14:40:01 - Could not find installer files <= this is from the script.ksh
20/04/2010 14:40:01 - ERROR: The script returned 256
20/04/2010 14:40:01 - Command Finished. Exit Code: 0 <= this is the Java app.
You need to shift the return code from system() call by 8 bits.
E.g. $exit_value = $? >> 8; # In your script the $? is $scriptReturnCode
From http://perldoc.perl.org/perlfaq8.html :
system() runs a command and returns exit status information (as a 16 bit value: the low 7 bits are the signal the process died from, if any, and the high 8 bits are the actual exit value
A more expanded code checking for coredumps as well could look like this:
system();
if ($? == -1) {
print "failed to execute: $!\n";
} elsif ($? & 127) {
printf "child died - signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
} else {
printf "child exited with value %d\n", $? >> 8;
}
UPDATE: As per ysth's excellent reminder, the exit codes are truncated at 8 (low) bits, so returning 256 instead of the intended 1 ends up as 0. Similarly, returning 257 ends up as 1.
If capturing $? and shifting its value is too much trouble to remember, you can simplify that code by using IPC::System::Simple, which enhances system() and backticks with more error checking and diagnostics, e.g.:
use IPC::System::Simple qw(run EXIT_ANY);
my $command = "${scriptDirectory}/${script} ${args}";
print "INFO: Calling $command\n";
# runs command through a shell first; does not die on any exit value
run(EXIT_ANY, $command);
my $scriptReturnCode = $IPC::System::Simple::EXITVAL;