6

IPC::Open3 (または IPC::Open2、どちらもこの問題を示す) を使用して外部バイナリ (この場合は bogofilter) を呼び出し、子入力ファイルハンドルを介して入力をフィードし、結果を読み取るモジュールがあります。子出力ハンドル。ほとんどの環境で実行すると、コードは正常に機能します。ただし、このモジュールの主な用途は、Apache 2.2.6 で実行される Web サービスです。そして、その環境下では、エラーが発生します:

STDOUT を fdopen できません: 引数が無効です

これは、コードが Apache で実行されている場合にのみ発生します。以前のコードは、入力用のヒアドキュメントを含む非常に複雑なコマンドを作成し、バックティックを使用して実行していました。それは機能しましたが、非常に遅く、独特で複雑な方法で壊れる傾向がありました. 古いバージョンに戻す必要はありませんが、これをクラックすることはできません。

4

4 に答える 4

1

mod_perl 2 が STDOUT を閉じるためでしょうか? 私はこれを発見し、それについて投稿しました:

http://marc.info/?l=apache-modperl&m=126296015910250&w=2

厄介なバグだと思いますが、今のところ誰も気にしていないようです。問題が関連していて、注意を引きたい場合は、mod_perl リストにフォローアップを投稿してください。

ジョン

于 2010-01-20T00:27:39.487 に答える
0

Bogofilter は、スパムと非スパムで異なる終了コードを返します。

stdout を /dev/null にリダイレクトすることで、これを「修正」できます

system("bogofilter < $input > /dev/null") >> 8;

スパムの場合は 0、非スパムの場合は 1、不明の場合は 2 を返します (>> 8 は、perl が終了コードを有効に修正するためであり、これにより損傷が修正されます)。

注: 環境がないと、bogofilter が単語リストを見つけられない可能性もあります。そのため、それも明示的に渡します。

system("bogofilter -d /path/to/.bogofilter/ < $input > /dev/null") >> 8;

(/path/to/.bogofilter には wordlist.db が含まれます)

そのようにして bogofilter が与えた実際の評価を取得することはできませんが、何かを得ることはできます。

于 2011-06-06T05:30:48.453 に答える
0

コードが Linux/Unix システムでのみ実行される場合、STDOUT は実際のファイル ハンドルではないため、失敗しない open3 置換を簡単に作成できます。

sub my_open3 {
    # untested!
    pipe my($inr), my($inw) or die;
    pipe my($outr), my($outw) or die;
    pipe my($errr), my($errw) or die;
    my $pid = fork;
    unless ($pid) {
        defined $pid or die;
        POSIX::dup2($inr, 0);
        POSIX::dup2($outw, 1);
        POSIX::dup2($errw, 2);
        exec @_;
        POSIX::_exit(1);
    }
    return ($inw, $outr, $errr);
}

my ($in, $out, $err) = my_open3('ls /etc/');
于 2011-06-06T07:33:43.787 に答える
0

警告 Emptor: 私は perl ウィザードではありません。

@JonathanSwartz が示唆したように、問題は apache2 mod_perl が STDIN と STDOUT を閉じることだと思います。これは IPC::Open3 が行っていることとは関係ありませんが、ここで説明されているバグがあります。

要約すると (これは私が明確に理解していない部分です)、open3 は子プロセス STDIN/OUT/ERR をプロセスに一致させようとするか、それが要求された場合はそれを複製しようとします。open('>&=X') が機能するいくつかの文書化されていない方法により、STDIN/OUT/ERR が閉じている場合を除いて、通常は正常に機能します。

詳細に深く入る別のリンク。

1 つの解決策は、これらのリンクの両方で説明されているように、IPC::Open3 を修正することです。もう 1 つは、mod_perl コードで一時的に STDIN/OUT を開き、その後閉じることです。

my ($save_stdin,$save_stdout);
open $save_stdin, '>&STDIN';
open $save_stdout, '>&STDOUT';
open STDIN, '>&=0';
open STDOUT, '>&=1';

#make your normal IPC::Open3::open3 call here

close(STDIN);
close(STDOUT);
open STDIN, '>&', $save_stdin;
open STDOUT, '>&', $save_stdout;

また、IPC::Run3 が同じ問題に苦しんでいるというネット上の苦情がたくさんあることに気付きました。そのため、誰かが同じ問題に遭遇した場合、同じ解決策が機能するのではないかと思います。

于 2014-06-19T16:06:10.587 に答える