binmode+mod_perl 2.0.5+解析::RecDescent=分段故障



重要更新:问题与Apache或mod_perl无关。最简单的演示:

> perl -le 'use PerlIO::via::QuotedPrint; binmode(*STDERR, ":via(PerlIO::via::QuotedPrint):utf8"); open (ERROR, ">&STDERR");'
zsh: segmentation fault  perl -le

事实上,binmode是由我的代码执行的,open (ERROR, ">&STDERR");是由Parse::RecDescent执行的。


原始问题:

我对mod_perl 2.0.5下的Spreadsheet::WriteExcel有问题Apache死于分段错误,我发现它发生在Spreadsheet::WriteExcel包中的require Parse::RecDescent语句上。

strace表明,最后发生的事情是重复STDERR:

[pid 31253] dup(2)                      = 8
[pid 31253] ioctl(8, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fffcf66a328) = -1 ENOTTY (Inappropriate ioctl for device)
[pid 31253] lseek(8, 0, SEEK_CUR)       = 0
[pid 31253] --- SIGSEGV (Segmentation fault) @ 0 (0) ---

我通读了Parse::RecDescent的代码,注意到像open (ERROR, ">&STDERR"); 这样的语句

好吧,经过一些额外的实验,我有了这个极简主义的Plack应用程序来复制segfault:

use strict;
use warnings;
# DANGEROUS
use PerlIO::via::QuotedPrint;
binmode(*STDERR, ":via(PerlIO::via::QuotedPrint):utf8");
my $app = sub {
    my $env = shift;
    open (ERROR, ">&STDERR");  # segmenatation fault
    return [
        '200',
        [ 'Content-Type' => 'text/plain' ],
        [ "hello world" ],
    ];
};
$app;

(事实上,我使用的是PerlIO::via::QuotedPrint以外的binmode层,但效果相同)

如果我不执行binmode(*STDERR, ":via(PerlIO...,apache就不会segfault。

如果我不复制STDERR,apache就不会出错。

如果我两者都做,就会出错。

作为一种变通方法,我可以避免在STDERR上使用binmode,但这并不好。

关于在哪里以及如何解决这个问题,有什么建议吗?

谢谢。

我的环境:

perl -v |grep version 
This is perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux-gnu-thread-multi
uname -a
Linux thinkpad 3.2.0-32-generic #51-Ubuntu SMP Wed Sep 26 21:33:09 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
lsb_release -c
Codename:       precise
dpkg -l |grep mod-perl
ii  libapache2-mod-perl2  2.0.5-5ubuntu1   Integration of perl with the Apache2 web server

Upd:同样的代码在过时的Ubuntu 8.04+perl 5.8.8+mod_perl2 2.0.3 下运行良好

更新2:FreeBSD 9.1+perl 5.14+mod_perl 2.0.8--segfault重复

uname -a                              
FreeBSD liruoko.ru 9.1-RELEASE-p5 FreeBSD 9.1-RELEASE-p5 #7 r253740: Sun Jul 28 16:53:08 MSK 2013     roman@thor.cmc.msu.ru:/usr/obj/usr/src/sys/MINI  amd64
pkg info |grep apache                     
apache22-itk-mpm-2.2.25        Version 2.2.x of Apache web server with itk MPM.
pkg info |grep mod_perl               
ap22-mod_perl2-2.0.8,3         Embeds a Perl interpreter in the Apache2 server
perl -v |grep version
This is perl 5, version 14, subversion 4 (v5.14.4) built for amd64-freebsd

如果它在没有设置binmode的情况下工作,那么也许您有了一个解决方案(如果不是为什么会发生这种情况的真正答案)c.f.perldoc -f binmode:的提取物

On some systems (in general, DOS- and Windows-based systems) binmode() is 
necessary when you're not working with a text file.  For the sake of portability 
it is a good idea always to use it when appropriate, and never to use it when it 
isn't appropriate.  Also, people can set their I/O to be by default UTF8-encoded 
Unicode, not bytes.
In other words: regardless of platform, use binmode() on binary data, like 
images, for example.   ...

perldoc的无与伦比的风格中,我认为这可能意味着你可以为某些文件句柄/套接字设置binmode,而不是为其他文件句柄/插座设置,直到"bug"(如果是bug)没有出现为止。

编辑

感谢你的简单和可重复的错误/测试用例,我认为这将得到修复。我构建了perl的调试版本来尝试跟踪错误,它位于liberperl.so中,位于PerlIOBase_dup()中的某个位置。我还在IRC上向知情人士提到了这一点,他们得出结论,这是一个真实的(,即可报告)perl错误。

以下是我如何运行gdb:

(gdb) run -Dx -le 'use PerlIO::via::QuotedPrint; binmode(*STDERR, 
":via(PerlIO::via::QuotedPrint):utf8"); open (ERROR,      ">&STDERR");'

事情就是这样结束的:

Program received signal SIGSEGV, Segmentation fault.
PerlIOBase_dup (f=0x0, o=0x801551060, param=0x0, flags=2) at perlio.c:2307 
2307 PerlIOBase(f)->flags |= PERLIO_F_UTF8;

干杯,你让perl变得更好!

相关内容

  • 没有找到相关文章

最新更新