如何保护 Perl 程序免受模块中 abort() 调用的影响?

问题描述 投票:0回答:1

考虑这个例子:

#!/usr/bin/perl
use strict;
use warnings;
require 5.006_001;
use Graphics::Magick;
use sigtrap qw( die any );

sub try { my ($err) = @_; die("$err\n") if $err; }

my $image = Graphics::Magick->new;

sub process {
    my ($file) = @_;

    my $result = eval {
        kill 'ABRT',$$ if $file eq "magic";
        try $image->Read($file);
    };

    if (defined $result) { print "Yay :)\n"; }
    else { warn($@); }
}

process "good.gif";  # works
process "MINN.XK4";  # needs font that doesn't exist
process "magic";     # trigger abort manually
process "foo";       # file doesn't exist

我原以为这可以保护主程序免受模块中问题的影响,而且大多数情况下确实如此。然而,我最近遇到了一种情况,模块的某些实现触发断言失败。

在大多数系统上,我会看到类似的内容:

Yay :)
Exception 405: Unable to read font (/usr/share/fonts/type1/gsfonts/n021003l.pfb)
Caught a SIGABRT at ./example line 18.
Exception 430: Unable to open file (foo)

然而,事实证明这也是可能的:

Yay :)
perl: magick/draw.c:1777: DrawSetFont: Assertion `font_name != (const char *) NULL' failed.
Aborted

我应该如何重写以更好地将主程序与模块中的故障隔离?


多年来我似乎一直误解

eval
的用途,而且显然我并不真正了解信号处理。为什么模块中的assert()调用触发的ABORT/IOT与我上面触发的不同?
我的 abort(3) 手册页说:

abort() 函数首先解锁 SIGABRT 信号,然后为调用进程引发该信号(就像调用 raise(3) 一样)。这会导致进程异常终止,除非捕获到 SIGABRT 信号并且信号处理程序不会返回(请参阅 longjmp(3))。

那么也许 Perl 有一种“不返回”的方法?
.so

告诉我:


当即将抛出致命异常时,将调用
perldoc perlvar

指示的例程。错误消息作为第一个参数传递。当“

$SIG{__DIE__}
”钩子例程返回时,异常处理将像没有钩子时一样继续,除非钩子例程本身通过“
__DIE__
”、循环退出或“
goto &sub
”退出”。 “
die()
”处理程序在调用期间被显式禁用,因此您可能会死于“
__DIE__
”处理程序。对于“
__DIE__
”也是如此。

但我不知道如何使用这些信息。

perl module ipc
1个回答
0
投票
%SIG

(而不是 __WARN__

)为其安装钩子来捕获它
eval

perl -wE'say $$; kill "ABRT", $$; say "bye"'

但是

17807 Aborted (core dumped)

在信号中幸存

perl -wE'say $$; $SIG{ABRT} = sub { say "got ya" }; kill "ABRT", $$; say "bye"'

但我不确定我是否理解了问题的全部要点。但如果您的程序确实被 
17832 got ya bye

杀死,那么安装

SIGABRT
将使您免受这种情况。
    

© www.soinside.com 2019 - 2024. All rights reserved.