You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Jonathan Swartz <sw...@pobox.com> on 2010/01/08 15:15:23 UTC

[mp2] mod_perl closes apache's stdin and/or stdout

(A continuation of:
http://marc.info/?l=apache-modperl&m=117507879929572&w=2
http://marc.info/?l=apache-modperl&m=119072925228529&w=2
)

I've just spent many frustrating days debugging a situation that  
turned out to be caused by mod_perl's closing of file descriptor 1  
(STDOUT).

Here's the reproducible case I ultimately got it down to. Using  
mod_perl 2, with a dead-simple configuration and this handler:

    use DBI;
    sub handler {
        my $dbh = DBI->connect( "DBI:mysql:$database", $user, $pass,  
{ RaiseError => 1 } );
        system('echo "hello"');
        eval { $dbh->do("select 1") };
        print "dbh - " . ( $@ ? "error: $@\n" : "ok" ) . "\n";
        return 0;
    }

This outputs:

    dbh - error: DBD::mysql::db do failed: Lost connection to MySQL  
server during query at...

The DBI connection dies because mod_perl closes fd 1 (STDOUT). So the  
next open - in this case the remote mysql connection created by DBI -  
gets fd 1. The child process created by system() writes innocently to  
STDOUT, which goes to our mysql socket, causing havoc.

We can confirm this by inserting this at the beginning of the handler:

    sub handler {
         open(my $fh, ">/dev/null");
         print "fh - " . fileno($fh) . "\n";
         ...

Now this outputs:

    fh - 1
    dbh - ok

The initial open grabs fd 1, which means that DBI gets a different fd,  
and the connection doesn't die.

Now this example is contrived, but replace 'echo "hello"' with any  
innocuous system() or backtick call that accidentally sends a bit of  
output to STDOUT, and you can see how this would cause all kinds of  
baffling bugs. In my case, it was originally a call to "sendmail" that  
intermittently sent a warning to STDOUT, and thus destroyed our first  
database connection. It worked fine in mod_perl 1, but started  
breaking when we upgraded to mod_perl 2.

Is there really no way to fix this in mod_perl, perhaps by  
automatically opening a /dev/null handle as I did above? Other future  
developers will surely endure the same hours of frustration I did if  
it is left alone.

Thanks
Jon


Re: [mp2] mod_perl closes apache's stdin and/or stdout

Posted by Fred Moyer <fr...@redhotpenguin.com>.
On Tue, Jan 26, 2010 at 5:20 PM, Jonathan Swartz <sw...@pobox.com> wrote:
> This never got a response. Which surprises me, since I think it is a
> legitimate and nasty bug.
>
> So is the silence because
> 1) people don't think it's really a bug
> 2) people glazed over while reading the description
> 3) ??

4) Don't understand how widespread or common this issue is, or if you
are the only one seeing it.

>
> Thanks :)
> Jon
>
> On Jan 8, 2010, at 6:15 AM, Jonathan Swartz wrote:
>
>> (A continuation of:
>> http://marc.info/?l=apache-modperl&m=117507879929572&w=2
>> http://marc.info/?l=apache-modperl&m=119072925228529&w=2
>> )
>>
>> I've just spent many frustrating days debugging a situation that turned
>> out to be caused by mod_perl's closing of file descriptor 1 (STDOUT).
>>
>> Here's the reproducible case I ultimately got it down to. Using mod_perl
>> 2, with a dead-simple configuration and this handler:
>>
>>  use DBI;
>>  sub handler {
>>      my $dbh = DBI->connect( "DBI:mysql:$database", $user, $pass, {
>> RaiseError => 1 } );
>>      system('echo "hello"');
>>      eval { $dbh->do("select 1") };
>>      print "dbh - " . ( $@ ? "error: $@\n" : "ok" ) . "\n";
>>      return 0;
>>  }
>>
>> This outputs:
>>
>>  dbh - error: DBD::mysql::db do failed: Lost connection to MySQL server
>> during query at...
>>
>> The DBI connection dies because mod_perl closes fd 1 (STDOUT). So the next
>> open - in this case the remote mysql connection created by DBI - gets fd 1.
>> The child process created by system() writes innocently to STDOUT, which
>> goes to our mysql socket, causing havoc.
>>
>> We can confirm this by inserting this at the beginning of the handler:
>>
>>  sub handler {
>>       open(my $fh, ">/dev/null");
>>       print "fh - " . fileno($fh) . "\n";
>>       ...
>>
>> Now this outputs:
>>
>>  fh - 1
>>  dbh - ok
>>
>> The initial open grabs fd 1, which means that DBI gets a different fd, and
>> the connection doesn't die.
>>
>> Now this example is contrived, but replace 'echo "hello"' with any
>> innocuous system() or backtick call that accidentally sends a bit of output
>> to STDOUT, and you can see how this would cause all kinds of baffling bugs.
>> In my case, it was originally a call to "sendmail" that intermittently sent
>> a warning to STDOUT, and thus destroyed our first database connection. It
>> worked fine in mod_perl 1, but started breaking when we upgraded to mod_perl
>> 2.
>>
>> Is there really no way to fix this in mod_perl, perhaps by automatically
>> opening a /dev/null handle as I did above? Other future developers will
>> surely endure the same hours of frustration I did if it is left alone.
>>
>> Thanks
>> Jon
>>
>
>

Re: [mp2] mod_perl closes apache's stdin and/or stdout

Posted by Jonathan Swartz <sw...@pobox.com>.
This never got a response. Which surprises me, since I think it is a  
legitimate and nasty bug.

So is the silence because
1) people don't think it's really a bug
2) people glazed over while reading the description
3) ??

Thanks :)
Jon

On Jan 8, 2010, at 6:15 AM, Jonathan Swartz wrote:

> (A continuation of:
> http://marc.info/?l=apache-modperl&m=117507879929572&w=2
> http://marc.info/?l=apache-modperl&m=119072925228529&w=2
> )
>
> I've just spent many frustrating days debugging a situation that  
> turned out to be caused by mod_perl's closing of file descriptor 1  
> (STDOUT).
>
> Here's the reproducible case I ultimately got it down to. Using  
> mod_perl 2, with a dead-simple configuration and this handler:
>
>   use DBI;
>   sub handler {
>       my $dbh = DBI->connect( "DBI:mysql:$database", $user, $pass,  
> { RaiseError => 1 } );
>       system('echo "hello"');
>       eval { $dbh->do("select 1") };
>       print "dbh - " . ( $@ ? "error: $@\n" : "ok" ) . "\n";
>       return 0;
>   }
>
> This outputs:
>
>   dbh - error: DBD::mysql::db do failed: Lost connection to MySQL  
> server during query at...
>
> The DBI connection dies because mod_perl closes fd 1 (STDOUT). So  
> the next open - in this case the remote mysql connection created by  
> DBI - gets fd 1. The child process created by system() writes  
> innocently to STDOUT, which goes to our mysql socket, causing havoc.
>
> We can confirm this by inserting this at the beginning of the handler:
>
>   sub handler {
>        open(my $fh, ">/dev/null");
>        print "fh - " . fileno($fh) . "\n";
>        ...
>
> Now this outputs:
>
>   fh - 1
>   dbh - ok
>
> The initial open grabs fd 1, which means that DBI gets a different  
> fd, and the connection doesn't die.
>
> Now this example is contrived, but replace 'echo "hello"' with any  
> innocuous system() or backtick call that accidentally sends a bit of  
> output to STDOUT, and you can see how this would cause all kinds of  
> baffling bugs. In my case, it was originally a call to "sendmail"  
> that intermittently sent a warning to STDOUT, and thus destroyed our  
> first database connection. It worked fine in mod_perl 1, but started  
> breaking when we upgraded to mod_perl 2.
>
> Is there really no way to fix this in mod_perl, perhaps by  
> automatically opening a /dev/null handle as I did above? Other  
> future developers will surely endure the same hours of frustration I  
> did if it is left alone.
>
> Thanks
> Jon
>