[英]Perl system call causes core dump but $? remains zero
我有一个Perl脚本(在VirtualBox中的Xubuntu Lucid Lynx上运行)包含几个C / C ++二进制文件,将一个输入提供给其他人。 其中一条通常包括:
my $ret_code=`cat $input | c_binary`;
my $ret_val= $?;
对于某些输入文件,代码会导致coredump,但$ret_val
和$ret_code
分别为0和“”。 我可以看到运行它时滚动的错误,但我似乎无法以编程方式“捕获”此错误。 我怎么能这样做? 意图是在错误中从输入中删除一些行并重试解析。
以下是错误:
*** 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
返回的值是:
LOG: Parser return code: 0
LOG: Parser return value:
有问题的实际代码段:
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`;
首先,你展示的代码中有一些可疑的东西:你得到$?
的价值$?
在实际运行命令之前。 我现在将讨论我认为你打算写的内容:
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 = $?;
在此之后, $ret_code
包含整个shell命令的状态。 反过来,这是列表中最后一个命令的状态,它是一个管道cat ... | code/parser ...
cat ... | code/parser ...
根据shell,这可能是管道中最后一个命令的状态,即code/parser
(ksh,zsh),或者总是为0(大多数shell,包括ash,bash和pdksh)。
在你的情况下,有一个简单的解决方法,即摆脱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 = $?;
如果你有一个有用的命令而不是cat
,你最好的选择是完全免除shell。 这也有其他一些小的好处:少掌握一个工具; 更容易移植到非unix系统; 使用包含shell元字符的文件名(这也可以通过系统使用quotemeta
来实现)。 这是这个想法的要点(未经测试); perldoc -f open
和perldoc perlipc
可能有所帮助。
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 $!;
}
由于CRT正在中止程序(即它实际上并没有通过信号崩溃 ,CRT看到了被破坏的堆栈金丝雀并手动中止了该过程),它的返回值将为零。 我认为你能做的最好的事情是:
`cat $input | c_binary 2>&1`
这样就可以捕获CRT gunk,你可以在Perl脚本中检测它。
首先,你的命令行中有一只无用的cat
可以很容易地被重定向取代。
我尝试将命令更改为以下内容
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";
或者,如果您尝试最小化输入文件以查找导致崩溃的任何内容,我强烈建议使用Delta ,它可以有效地自动执行此操作
为c_binary
编译这个简单的c_binary
#include <string.h>
void f(void)
{
char smallbuf[9];
strcpy(smallbuf, "dy-no-MITE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
int main(void)
{
f();
return 0;
}
和这个Perl程序来运行它的图像
#! /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") : ();
}
我明白了
$ ./boom *** stack smashing detected ***: ./c_binary terminated ./prog.pl: c_binary exited 0 - terminated by signal 11
正如您所看到的,您需要使用POSIX
模块中的WIFSIGNALED
和WTERMSIG
以编程方式检测c_binary
是否被信号杀死 - 而不仅仅是退出状态本身:
WIFSIGNALED
如果子进程因信号而终止,则
WIFSIGNALED($?)
返回trueWTERMSIG
WTERMSIG($?)
返回子进程终止的信号(仅在WIFSIGNALED($?)
为真时才有意义)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.