7

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     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
Hln
  • 749
  • 5
  • 15
  • Provide more info. What's the operating system, Perl distribution and version? In case the software is outdated, what happens if you upgrade? – daxim Aug 30 '13 at 13:24
  • Ubuntu 12.04 (LTS), perl 5.14, detailed report added to question – Hln Aug 30 '13 at 13:47
  • 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 http://perl.apache.org/docs/2.0/devel/debug/c.html#Analyzing_Dumped_Core_Files – daxim Aug 30 '13 at 13:56
  • BTW, If I _downgrade_ (to perl 5.8.8 + Ubuntu 8.04), both the minimal example and the Spreadsheet::WriteExcel work well – Hln Aug 30 '13 at 13:57
  • `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? – G. Cito Aug 30 '13 at 15:05
  • @G.Cito Don't get midled by the ioctl error: this happens for every `open()` in Perl and seems to be "normal". – Slaven Rezic Aug 30 '13 at 19:06
  • @Helena I fear strace (or ltrace) does not give enough information here — maybe you should try gdb? – Slaven Rezic Aug 30 '13 at 19:07
  • @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`](http://perldoc.perl.org/perlbug.html)), I will wait awhile before filing it. If I file the bug I will link to this question. Good detective work! – G. Cito Sep 04 '13 at 15:57
  • @G.Cito thanks for advice! I filed the bug: https://rt.perl.org/rt3/Public/Bug/Display.html?id=119653 – Hln Sep 06 '13 at 19:40
  • I figured out the problem, see https://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. – Leon Timmermans Sep 07 '13 at 06:34
  • See also: http://perl5.git.perl.org/perl.git/commitdiff/df8c7dee25da69fc88678b8949166e08fb686037 – Leon Timmermans Sep 07 '13 at 07:03

1 Answers1

3

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!

G. Cito
  • 6,210
  • 3
  • 29
  • 42