Ovid has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

I've been banging my head for quite a while on a bad file descriptor problem. Basically, I have TAPx::Parser 0.12 in development and I have tried to clean up the 'tprove' script by adding TAPx::Parser::Source::Perl. That package basically tries to execute some perl code and return a stream:

use TAPx::Parser::Source::Perl; my $source = TAPx::Parser::Source::Perl->new; my $file = 't/00-load.t'; my $stream = $source->filename($file)->get_stream; while ( defined( my $line = $stream->next ) ) { print "$line\n"; }

It executes the code with the following:

sub get_stream { my ( $self ) = @_; my $command = $self->_get_command; local *FH; # -| is safer, but not portable. if ( open FH, "$command |" ) { return TAPx::Parser::Iterator->new(\*FH); } else { $self->error("Could not execute ($command): $!"); return; } }

However, whenever I try to run it, I get this error message:

% perl -Ilib examples/tprove2 t/00-load.t Can't dup STDOUT: Bad file descriptor at /usr/local/lib/perl5/5.8.7/T +est/Builder.pm line 1322. Compilation failed in require at /usr/local/lib/perl5/5.8.7/Test/Build +er/Module.pm line 3. BEGIN failed--compilation aborted at /usr/local/lib/perl5/5.8.7/Test/B +uilder/Module.pm line 3. Compilation failed in require at /usr/local/lib/perl5/5.8.7/Test/More. +pm line 22. BEGIN failed--compilation aborted at /usr/local/lib/perl5/5.8.7/Test/M +ore.pm line 22. Compilation failed in require at t/00-load.t line 3. BEGIN failed--compilation aborted at t/00-load.t line 3. ...

I am autoflushing STDERR and STDOUT in new(), but now I'm stumped. Any suggestions? If you download the tarball, you'll find that examples/tprove has the old code and examples/tprove2 has the new code. tprove does almost exactly the same thing as what I describe above, but it works fine.

Sorry I don't have a smaller test case handy. I can reproduce this error with smaller code, but so far, I'm not sure if there's something else in my distribution which might be affecting things. Also, any solution should be as portable as possible, but to different operating systems and older versions of Perl.

Update: after struggling with this for over an hour, I think I finally found the problem. If I don't localize the filehandle, this problem goes away. Apparently, localizing that typeglob caused the underlying descriptor to disappear once the localized typeglob went out of scope.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re: Can't dup STDOUT in TAPx::Harness 0.12
by bart (Canon) on Jul 30, 2006 at 11:39 UTC
    after struggling with this for over an hour, I think I finally found the problem. If I don't localize the filehandle, this problem goes away. Apparently, localizing that typeglob caused the underlying descriptor to disappear once the localized typeglob went out of scope.
    Perhaps you should try one of the other filehandle related modules, to produce the filehandle (and assign to a scalar). For example: FileHandle, IO::Handle, or even gensym().

    I remember having similar problems on an older perl, 5.005, and fixing it this way. Later perls didn't need it, <stroke>in part</stroke> mainly because they provide lexical filehandles... Until this.

Re: Can't dup STDOUT in TAPx::Harness 0.12
by Aristotle (Chancellor) on Jul 30, 2006 at 11:53 UTC

    Why aren’t you using a lexical filehandle? Seems that should cure your problem quite thoroughly.

    Makeshifts last the longest.

      Because this code, as noted, should be able to run on older Perls. No sense writing a brand new test harness if older Perls can't run it..

      Cheers,
      Ovid

      New address of my CGI Course.

        Hasn’t Symbol::gensym always been around in Perl 5?

        Makeshifts last the longest.