binmode + mod_perl 2.0.5 + Parse::RecDescent = segmentaion fault
Asked Answered
L

1

6

Important update: the problem is nothing to do with Apache or mod_perl. The easiest demonstration:

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

In fact binmode is performed by my code and open (ERROR, ">&STDERR"); by Parse::RecDescent.


Original question:

I have a problem with Spreadsheet::WriteExcel under mod_perl 2.0.5 Apache dies with segmentation fault, and I found out that it occurs on require Parse::RecDescent statement within Spreadsheet::WriteExcel package.

strace shows that last things that happens is dup'ing 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) ---

I read through the code of Parse::RecDescent and noticed statements like open (ERROR, ">&STDERR");

Well, after some additional experiments I have this minimalistic Plack app to reproduce the 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;

(In fact I use binmode layer other than PerlIO::via::QuotedPrint, but effect is the same)

If I don't perform binmode(\*STDERR, ":via(PerlIO..., apache doesn't segfault.

If I don't duplicate STDERR, apache doesn't segfault.

If I do the both, it segfaults.

As a workaround I can avoid using binmode on STDERR, but it's not good.

Any suggestions on where and how should be fixed this?

Thanks.

My environment:

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: the same code works well under outdated Ubuntu 8.04 + perl 5.8.8 + mod_perl2 2.0.3

Upd2: FreeBSD 9.1 + perl 5.14 + mod_perl 2.0.8 -- segfault repeats

uname -a                              
FreeBSD liruoko.ru 9.1-RELEASE-p5 FreeBSD 9.1-RELEASE-p5 #7 r253740: Sun Jul 28 16:53:08 MSK 2013     [email protected]:/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
Lexicology answered 30/8, 2013 at 12:59 Comment(11)
Provide more info. What's the operating system, Perl distribution and version? In case the software is outdated, what happens if you upgrade?Inkhorn
Ubuntu 12.04 (LTS), perl 5.14, detailed report added to questionLexicology
Right, both Perl and mod_perl had a couple of releases since then, fixing a number of crash bugs. Does the crash still occur with mod_perl 2.0.8 and perl 5.18.1? If yes, see perl.apache.org/docs/2.0/devel/debug/…Inkhorn
BTW, If I downgrade (to perl 5.8.8 + Ubuntu 8.04), both the minimal example and the Spreadsheet::WriteExcel work wellLexicology
Inappropriate ioctl for device makes me think of permissions on a socket or file somewhere. Perhaps your kernel, apache, mod_perl or perl IO:: layers have changed the way they handle these. Are apache and mod_perl compiled from source?Culdesac
@G.Cito Don't get midled by the ioctl error: this happens for every open() in Perl and seems to be "normal".Criminal
@Helena I fear strace (or ltrace) does not give enough information here — maybe you should try gdb?Criminal
@Helena - see my post below. I think it's pretty clear you have found a perl bug. Congratulations! In case you want to file this bug yourself (see perldoc perlbug), I will wait awhile before filing it. If I file the bug I will link to this question. Good detective work!Culdesac
@G.Cito thanks for advice! I filed the bug: rt.perl.org/rt3/Public/Bug/Display.html?id=119653Lexicology
I figured out the problem, see rt.perl.org/rt3/Ticket/Display.html?id=119653#txn-1252071 for more information. Stopping it from crashing will be easy, making it work correctly is more difficult.Bushel
See also: perl5.git.perl.org/perl.git/commitdiff/…Bushel
C
2

If it works without binmode set, then perhaps you have a solution (if not a real answer to why this is happening). c.f. this extract from 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.   ...

In the inimitable style of perldoc I think that might be suggesting you could set binmode for certain filehandles/sockets and not for others adjusting until the "bug" (if it is one) does not appear.

EDIT:

Thanks to your simple and reproducible error / test case I think this will get fixed. I built a debug version of perl to try tracing the error and it is in liberperl.so - somewhere in PerlIOBase_dup(). I also mentioned this on IRC to people who would know, and they concluded this is a real (i.e reportable) perl bug.

Here's how I ran gdb:

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

and this was how things ended up:

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;

Cheers, you made perl better!

Culdesac answered 30/8, 2013 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.