stas 2004/02/16 17:22:42
Modified: src/modules/perl modperl_io.c . Changes Added: t/response/TestModperl io_nested_with_closed_stds.pm io_with_closed_stds.pm Log: Fix the STDIN/OUT overriding process to handle gracefully cases, when either or both are closed/bogus (the problem was only with useperlio enabled perl) + tests Revision Changes Path 1.23 +93 -47 modperl-2.0/src/modules/perl/modperl_io.c Index: modperl_io.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_io.c,v retrieving revision 1.22 retrieving revision 1.23 diff -u -u -r1.22 -r1.23 --- modperl_io.c 22 Nov 2003 20:38:54 -0000 1.22 +++ modperl_io.c 17 Feb 2004 01:22:41 -0000 1.23 @@ -92,25 +92,34 @@ { dHANDLE("STDIN"); int status; - GV *handle_save = gv_fetchpv(Perl_form(aTHX_ "Apache::RequestIO::_GEN_%ld", - (long)PL_gensym++), - TRUE, SVt_PVIO); + GV *handle_save = (GV*)Nullsv; SV *sv = sv_newmortal(); - sv_setref_pv(sv, "Apache::RequestRec", (void*)r); MP_TRACE_o(MP_FUNC, "start"); - /* open my $oldout, "<&STDIN" or die "Can't dup STDIN: $!"; */ - status = Perl_do_open(aTHX_ handle_save, "<&STDIN", 7, FALSE, O_RDONLY, - 0, Nullfp); - if (status == 0) { - Perl_croak(aTHX_ "Failed to dup STDIN: %_", get_sv("!", TRUE)); + sv_setref_pv(sv, "Apache::RequestRec", (void*)r); + + /* STDIN could be closed or invalid */ + if (handle && SvTYPE(handle) == SVt_PVGV && + IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) { + handle_save = gv_fetchpv(Perl_form(aTHX_ + "Apache::RequestIO::_GEN_%ld", + (long)PL_gensym++), + TRUE, SVt_PVIO); + + /* open my $oldout, "<&STDIN" or die "Can't dup STDIN: $!"; */ + status = Perl_do_open(aTHX_ handle_save, "<&STDIN", 7, FALSE, + O_RDONLY, 0, Nullfp); + if (status == 0) { + Perl_croak(aTHX_ "Failed to dup STDIN: %_", get_sv("!", TRUE)); + } + + /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't + * have file descriptors, so STDIN must be closed before it can + * be reopened */ + Perl_do_close(aTHX_ handle, TRUE); } - /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't - * have file descriptors, so STDIN must be closed before it can - * be reopened */ - Perl_do_close(aTHX_ handle, TRUE); status = Perl_do_open9(aTHX_ handle, "<:Apache", 8, FALSE, O_RDONLY, 0, Nullfp, sv, 1); if (status == 0) { @@ -127,26 +136,34 @@ { dHANDLE("STDOUT"); int status; - GV *handle_save = gv_fetchpv(Perl_form(aTHX_ "Apache::RequestIO::_GEN_%ld", - (long)PL_gensym++), - TRUE, SVt_PVIO); + GV *handle_save = (GV*)Nullsv; SV *sv = sv_newmortal(); MP_TRACE_o(MP_FUNC, "start"); sv_setref_pv(sv, "Apache::RequestRec", (void*)r); - /* open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; */ - status = Perl_do_open(aTHX_ handle_save, ">&STDOUT", 8, FALSE, O_WRONLY, - 0, Nullfp); - if (status == 0) { - Perl_croak(aTHX_ "Failed to dup STDOUT: %_", get_sv("!", TRUE)); + /* STDOUT could be closed or invalid */ + if (handle && SvTYPE(handle) == SVt_PVGV && + IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) { + handle_save = gv_fetchpv(Perl_form(aTHX_ + "Apache::RequestIO::_GEN_%ld", + (long)PL_gensym++), + TRUE, SVt_PVIO); + + /* open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; */ + status = Perl_do_open(aTHX_ handle_save, ">&STDOUT", 8, FALSE, + O_WRONLY, 0, Nullfp); + if (status == 0) { + Perl_croak(aTHX_ "Failed to dup STDOUT: %_", get_sv("!", TRUE)); + } + + /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't + * have file descriptors, so STDOUT must be closed before it can + * be reopened */ + Perl_do_close(aTHX_ handle, TRUE); } - /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't - * have file descriptors, so STDOUT must be closed before it can - * be reopened */ - Perl_do_close(aTHX_ handle, TRUE); status = Perl_do_open9(aTHX_ handle, ">:Apache", 8, FALSE, O_WRONLY, 0, Nullfp, sv, 1); if (status == 0) { @@ -166,20 +183,33 @@ MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle) { GV *handle_orig = gv_fetchpv("STDIN", FALSE, SVt_PVIO); - int status; MP_TRACE_o(MP_FUNC, "start"); - /* Perl_do_close(aTHX_ handle_orig, FALSE); */ + /* close the overriding filehandle */ + Perl_do_close(aTHX_ handle_orig, FALSE); - /* open STDIN, "<&STDIN_SAVED" or die "Can't dup STDIN_SAVED: $!"; */ - status = Perl_do_open9(aTHX_ handle_orig, "<&", 2, FALSE, O_RDONLY, - 0, Nullfp, (SV*)handle, 1); - Perl_do_close(aTHX_ handle, FALSE); - (void)hv_delete(gv_stashpv("Apache::RequestIO", TRUE), - GvNAME(handle), GvNAMELEN(handle), G_DISCARD); - if (status == 0) { - Perl_croak(aTHX_ "Failed to restore STDIN: %_", get_sv("!", TRUE)); + /* + * open STDIN, "<&STDIN_SAVED" or die "Can't dup STDIN_SAVED: $!"; + * close STDIN_SAVED; + */ + if (handle != (GV*)Nullsv) { + SV *err = Nullsv; + + MP_TRACE_o(MP_FUNC, "restoring STDIN"); + + if (Perl_do_open9(aTHX_ handle_orig, "<&", 2, FALSE, + O_RDONLY, 0, Nullfp, (SV*)handle, 1) == 0) { + err = get_sv("!", TRUE); + } + + Perl_do_close(aTHX_ handle, FALSE); + (void)hv_delete(gv_stashpv("Apache::RequestIO", TRUE), + GvNAME(handle), GvNAMELEN(handle), G_DISCARD); + + if (err != Nullsv) { + Perl_croak(aTHX_ "Failed to restore STDIN: %_", err); + } } MP_TRACE_o(MP_FUNC, "end\n"); @@ -188,7 +218,6 @@ MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle) { GV *handle_orig = gv_fetchpv("STDOUT", FALSE, SVt_PVIO); - int status; MP_TRACE_o(MP_FUNC, "start"); @@ -199,18 +228,35 @@ * level STDOUT is attempted to be closed. To prevent this * situation always explicitly flush STDOUT, before reopening it. */ - if (GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig))) { - PerlIO_flush(IoOFP(GvIOn(handle_orig))); + if (GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) && + (PerlIO_flush(IoOFP(GvIOn(handle_orig))) == -1)) { + Perl_croak(aTHX_ "Failed to flush STDOUT: %_", get_sv("!", TRUE)); } - /* open STDOUT, ">&STDOUT_SAVED" or die "Can't dup STDOUT_SAVED: $!"; */ - /* open first closes STDOUT */ - status = Perl_do_open9(aTHX_ handle_orig, ">&", 2, FALSE, O_WRONLY, - 0, Nullfp, (SV*)handle, 1); - Perl_do_close(aTHX_ handle, FALSE); - (void)hv_delete(gv_stashpv("Apache::RequestIO", TRUE), - GvNAME(handle), GvNAMELEN(handle), G_DISCARD); - if (status == 0) { - Perl_croak(aTHX_ "Failed to restore STDOUT: %_", get_sv("!", TRUE)); + + /* close the overriding filehandle */ + Perl_do_close(aTHX_ handle_orig, FALSE); + + /* + * open STDOUT, ">&STDOUT_SAVED" or die "Can't dup STDOUT_SAVED: $!"; + * close STDOUT_SAVED; + */ + if (handle != (GV*)Nullsv) { + SV *err = Nullsv; + + MP_TRACE_o(MP_FUNC, "restoring STDOUT"); + + if (Perl_do_open9(aTHX_ handle_orig, ">&", 2, FALSE, + O_WRONLY, 0, Nullfp, (SV*)handle, 1) == 0) { + err = get_sv("!", TRUE); + } + + Perl_do_close(aTHX_ handle, FALSE); + (void)hv_delete(gv_stashpv("Apache::RequestIO", TRUE), + GvNAME(handle), GvNAMELEN(handle), G_DISCARD); + + if (err != Nullsv) { + Perl_croak(aTHX_ "Failed to restore STDOUT: %_", err); + } } MP_TRACE_o(MP_FUNC, "end\n"); 1.1 modperl-2.0/t/response/TestModperl/io_nested_with_closed_stds.pm Index: io_nested_with_closed_stds.pm =================================================================== package TestModperl::io_nested_with_closed_stds; # test that we can successfully override STD(IN|OUT) for # 'perl-script', even if they are closed. Here we use # internal_redirect(), which causes a nested override of already # overriden STD streams use strict; use warnings FATAL => 'all'; use Apache::RequestRec (); use Apache::RequestIO (); use Apache::SubRequest (); use Apache::Test; use Apache::Const -compile => 'OK'; sub handler { my $r = shift; my $args = $r->args || ''; if ($args eq 'redirect') { # sub-req $r->content_type('text/plain'); # do not use plan() here, since it messes up with STDOUT, # which affects this test. print "1..1\nok 1\n"; } else { # main-req my $redirect_uri = $r->uri . "?redirect"; # we must close STDIN as well, due to a perl bug (5.8.0 - 5.8.3 # w/useperlio), which emits a warning if dup is called with # one of the STD streams is closed. # but we must restore the STD streams so not to affect other # tests. open my $oldin, "<&STDIN" or die "Can't dup STDIN: $!"; open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; close STDIN; close STDOUT; $r->internal_redirect($redirect_uri); open STDIN, "<&", $oldin or die "Can't dup \$oldin: $!"; open STDOUT, ">&", $oldout or die "Can't dup \$oldout: $!"; close $oldin; close $oldout; } Apache::OK; } 1; __DATA__ SetHandler perl-script 1.1 modperl-2.0/t/response/TestModperl/io_with_closed_stds.pm Index: io_with_closed_stds.pm =================================================================== package TestModperl::io_with_closed_stds; # test that we can successfully override STD(IN|OUT) for # 'perl-script', even if they are closed. use strict; use warnings FATAL => 'all'; use Apache::RequestRec (); use Apache::RequestUtil (); use Apache::RequestIO (); use Apache::SubRequest (); use Apache::Test; use Apache::Const -compile => 'OK'; sub fixup { my $r = shift; # we must close STDIN as well, due to a perl bug (5.8.0 - 5.8.3 # w/useperlio), which emits a warning if dup is called with # one of the STD streams is closed. open my $oldin, "<&STDIN" or die "Can't dup STDIN: $!"; open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; close STDIN; close STDOUT; $r->pnotes(oldin => $oldin); $r->pnotes(oldout => $oldout); Apache::OK; } sub handler { my $r = shift; plan $r, tests => 1; ok 1; Apache::OK; } sub cleanup { my $r = shift; # restore the STD(IN|OUT) streams so not to affect other tests. my $oldin = $r->pnotes('oldin'); my $oldout = $r->pnotes('oldout'); open STDIN, "<&", $oldin or die "Can't dup \$oldin: $!"; open STDOUT, ">&", $oldout or die "Can't dup \$oldout: $!"; close $oldin; close $oldout; Apache::OK; } 1; __DATA__ PerlModule TestModperl::io_with_closed_stds SetHandler perl-script PerlFixupHandler TestModperl::io_with_closed_stds::fixup PerlResponseHandler TestModperl::io_with_closed_stds PerlCleanupHandler TestModperl::io_with_closed_stds::cleanup 1.332 +4 -0 modperl-2.0/Changes Index: Changes =================================================================== RCS file: /home/cvs/modperl-2.0/Changes,v retrieving revision 1.331 retrieving revision 1.332 diff -u -u -r1.331 -r1.332 --- Changes 16 Feb 2004 19:58:18 -0000 1.331 +++ Changes 17 Feb 2004 01:22:42 -0000 1.332 @@ -12,6 +12,10 @@ =item 1.99_13-dev +Fix the STDIN/OUT overriding process to handle gracefully cases, when +either or both are closed/bogus (the problem was only with useperlio +enabled perl) [Stas] + copy apr_table_compress logic from later httpd versions in case mod_perl is built against 2.0.46, as mod_perl now requires it internally. users should be aware that 2.0.47 may become the oldest supported httpd version