The Perl system call calls the main dump, but $? stays equal to zero

I have a Perl script (runs on Xubuntu Lucid Lynx in VirtualBox) that wraps several C / C ++ binaries by inserting the inputs of one into the others. One of the lines consists in general:

my $ret_code=`cat $input | c_binary`; my $ret_val= $?; 

For some input files, the code calls coredump, but both $ret_val and $ret_code are 0 and "respectively. I see errors scrolling when I run them, but I don't seem to be able to" capture "this programmatically. How can I do this do? The goal is to mistakenly delete some lines from the input and repeat the parsing.

Here are the errors:

 *** stack smashing detected ***: code/parser terminated ======= Backtrace: ========= /lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x50)[0x798390] /lib/tls/i686/cmov/libc.so.6(+0xe233a)[0x79833a] code/parser[0x804edd8] [0x2e303039] ======= Memory map: ======== 0043b000-0043c000 r-xp 00000000 00:00 0 [vdso] 0045a000-00475000 r-xp 00000000 08:01 11041 /lib/ld-2.11.1.so 00475000-00476000 r--p 0001a000 08:01 11041 /lib/ld-2.11.1.so 00476000-00477000 rw-p 0001b000 08:01 11041 /lib/ld-2.11.1.so 006b6000-00809000 r-xp 00000000 08:01 10897 /lib/tls/i686/cmov/libc-2.11.1.so 00809000-0080a000 ---p 00153000 08:01 10897 /lib/tls/i686/cmov/libc-2.11.1.so 0080a000-0080c000 r--p 00153000 08:01 10897 /lib/tls/i686/cmov/libc-2.11.1.so 0080c000-0080d000 rw-p 00155000 08:01 10897 /lib/tls/i686/cmov/libc-2.11.1.so 0080d000-00810000 rw-p 00000000 00:00 0 008ba000-008d7000 r-xp 00000000 08:01 8268 /lib/libgcc_s.so.1 008d7000-008d8000 r--p 0001c000 08:01 8268 /lib/libgcc_s.so.1 008d8000-008d9000 rw-p 0001d000 08:01 8268 /lib/libgcc_s.so.1 00c89000-00cad000 r-xp 00000000 08:01 10901 /lib/tls/i686/cmov/libm-2.11.1.so 00cad000-00cae000 r--p 00023000 08:01 10901 /lib/tls/i686/cmov/libm-2.11.1.so 00cae000-00caf000 rw-p 00024000 08:01 10901 /lib/tls/i686/cmov/libm-2.11.1.so 08048000-08055000 r-xp 00000000 08:01 407893 /home/abugorsk/Documents/code/stepbystep/collins-parser/code/parser 08055000-08056000 r--p 0000c000 08:01 407893 /home/abugorsk/Documents/code/stepbystep/collins-parser/code/parser 08056000-08057000 rw-p 0000d000 08:01 407893 /home/abugorsk/Documents/code/stepbystep/collins-parser/code/parser 08057000-0c50f000 rw-p 00000000 00:00 0 0e168000-0fa57000 rw-p 00000000 00:00 0 [heap] b44a3000-b77c9000 rw-p 00000000 00:00 0 b77da000-b77dc000 rw-p 00000000 00:00 0 bff2b000-bff40000 rw-p 00000000 00:00 0 [stack] Aborted 

Return Values:

 LOG: Parser return code: 0 LOG: Parser return value: 

Actual piece of code in question:

 my $command = "cd $STEPBYSTEP_HOME/collins-parser; cat models/model$model_num/events | code/parser $src models/model$model_num/grammar 10000 1 1 1 1 1> $dest 2> $parse_log"; llog "Executing command: $command"; my $ret_code = $?; llog "Parser return code: $ret_code"; my $ret_val = `$command`; 
+4
source share
4 answers

Firstly, you have a useless cat on the command line, which can easily be replaced with redirection.

I would try changing the command to the following:

 my $command = "cd $STEPBYSTEP_HOME/collins-parser && code/parser $src models/model$model_num/grammar 10000 1 1 1 1 < models/model$model_num/events 1> $dest 2> $parse_log"; 

Alternatively, if you are trying to minimize your input file to find the cause of the failure, I highly recommend using Delta , which effectively automates this process.

0
source

Firstly, there is something suspicious in the code you are showing: are you getting the value $? before the actual launch of the command. I will now discuss what I think you wanted to write:

 my $command = "cd $STEPBYSTEP_HOME/collins-parser;" . "cat models/model$model_num/events | code/parser $src models/model$model_num/grammar 10000 1 1 1 1 1> $dest 2> $parse_log"; my $ret_val = `$command`; my $ret_code = $?; 

After that, $ret_code contains the status of the entire shell command. This, in turn, is the status of the last team on the list, which is the cat ... | code/parser ... pipeline cat ... | code/parser ... cat ... | code/parser ... Depending on the shell, this can be either the status of the last command in the pipeline, i.e. code/parser (ksh, zsh), or always be 0 (most shells, including ash, bash and pdksh).

In your case, there is a simple fix that should get rid of the useless use of cat :

 my $command = "cd $STEPBYSTEP_HOME/collins-parser &&" . "<models/model$model_num/events code/parser $src models/model$model_num/grammar 10000 1 1 1 1 1> $dest 2> $parse_log"; my $ret_val = `$command`; my $ret_code = $?; 

If you had a useful command instead of cat , the best option would be to do without a shell at all. It also has other minor advantages: one development tool; Easier to port to non-unix systems works with names of files containing shell metacharacters (this can also be achieved by the systematic use of quotemeta ). Here is the essence of the idea (untested); perldoc -f open and perldoc perlipc can help.

 use File::Slurp; if (open my $fh, "|-") { # Parent code my $ret_val = read_file($fh); close($ret_code); my $ret_code = $?; ... } else { # Child code chdir "$ENV{STEPBYSTEP_HOME}/collins-parser" or die $!; open STDIN, "<", "models/model$model_num/events" or die $!; open STDOUT, ">", $dest or die $!; open STDERR, ">", $parse_log or die $!; exec "code/parser", $src, "models/model$model_num/grammar", "1", "1", "1", "1", "1"; die $!; } 
+1
source

Since the CRT interrupts the program (that is, it does not actually crash with the signal, the CRT saw a confused glass canary and manually interrupted the process), its return value will be zero. I think the best you can do here is:

 `cat $input | c_binary 2>&1` 

so that the CRT capture is captured, and you can detect it in a Perl script.

0
source

Compile this simple backup for c_binary

 #include <string.h> void f(void) { char smallbuf[9]; strcpy(smallbuf, "dy-no-MITE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } int main(void) { f(); return 0; } 

and this perl program to run the image

 #! /usr/bin/perl use warnings; use strict; use POSIX; if (system("./c_binary") == 0) { print "$0: c_binary exited normally\n"; } else { warn "$0: c_binary exited ", ($? >> 8), "\n", WIFSIGNALED($?) ? (" - terminated by signal ", WTERMSIG($?), "\n") : (); } 

I get

  $ ./boom

 *** stack smashing detected ***: ./c_binary terminated
 ./prog.pl: c_binary exited 0
   - terminated by signal 11 

So, as you can see, you need to use WIFSIGNALED and WTERMSIG from the POSIX module to programmatically determine that c_binary was killed by a signal - not just the exit status itself:

WIFSIGNALED

WIFSIGNALED($?) Returns true if the child process terminated due to a signal

WTERMSIG

WTERMSIG($?) Returns a signal for which the child process terminated (only if the value WIFSIGNALED($?) true)

0
source

All Articles