develooper Front page | perl.perl5.porters | Postings from April 2008

Re: bug in if(open(my $fh,...))

Thread Previous | Thread Next
From:
Bram
Date:
April 28, 2008 00:28
Subject:
Re: bug in if(open(my $fh,...))
Message ID:
op.uaa8b50r5efjgi@darwin.mechelen.pearldoc.com
On Mon, 28 Apr 2008 01:45:43 +0200, Matt Sergeant <matt@sergeant.org>  
wrote:

> (I did post this via perlbug and to perlbug@perl.org but both appear to  
> have gone into a black hole)

Did you send them from the same emailaddress as this message?

>
> The following code:
>
>    if (open(my $fh, "/etc/passwd")) {
>      ...
>    }
>
> Leaves the file open at the exit of the scope (in fact to the end of the  
> program). But $fh is out of scope, meaning the file should be closed.
>
> (you can confirm with system(qq(ls -l /proc/$$/fd)) on Linux)
>
> Using:
>
>    do { my $fh;
>    if (open($fh, "/etc/passwd")) {
>      ...
>    }
>    }
>
> Does the right thing and closes the file handle at the end of the scope,  
> but that's ugly.
>
> (confirmed on both 5.10 and 5.8)
>
> Matt.

Confirmed with blead.

For example:

#!/usr/bin/perl

use strict;
use warnings;

my $foo = 1;
if (open(my $fh, "/etc/passwd") and ! $foo) {
#  ...
}
elsif ($foo) {
   print while <$fh>;
}

system(qq(ls -l /proc/$$/fd));
__END__

Will print the contents of /etc/passwd.
Followed by:

total 0
lrwx------ 1 bram users 64 2008-04-28 09:11 0 -> /dev/pts/2
lrwx------ 1 bram users 64 2008-04-28 09:11 1 -> /dev/pts/2
lrwx------ 1 bram users 64 2008-04-28 09:11 2 -> /dev/pts/2
lr-x------ 1 bram users 64 2008-04-28 09:11 3 -> /etc/passwd
lr-x------ 1 bram users 64 2008-04-28 09:11 4 -> pipe:[462056431]


Putting it in another block does make the fh go out of scope.

#!/usr/bin/perl

use strict;
use warnings;

{
   my $foo = 1;
   if (open(my $fh, "/etc/passwd") and ! $foo) {
     #  ...
   }
   elsif ($foo) {
     print while <$fh>;
   }
}
system(qq(ls -l /proc/$$/fd));
__END__
(Small note: you do not need the  do)


Will print the contents of /etc/passwd
Followed by:

total 0
lrwx------ 1 bram users 64 2008-04-28 09:11 0 -> /dev/pts/2
lrwx------ 1 bram users 64 2008-04-28 09:11 1 -> /dev/pts/2
lrwx------ 1 bram users 64 2008-04-28 09:11 2 -> /dev/pts/2
lr-x------ 1 bram users 64 2008-04-28 09:11 3 -> pipe:[462053596]



Of course this fails:

#!/usr/bin/perl

use strict;
use warnings;

if (open(my $fh, "/etc/passwd")) {
   #  ...
}
print while <$fh>;
system(qq(ls -l /proc/$$/fd));
__END__

Global symbol "$fh" requires explicit package name at x.pl line 9.
Execution of x.pl aborted due to compilation errors.

Another, perhaps easier to test, example:

#!/usr/bin/perl -l

use strict;
use warnings;

{
   if (my $foo = bless { }, "Foo") {
     print "in if";
   }
   print "End of block";
}
print "After block";


package Foo;
DESTROY { print "Foo destroyed"; }


Outputs:

in if
End of block
Foo destroyed
After block

Which (to me) means that  $foo  - incorrectly - gets freed after the block  
and not after the if.


Kind regards,

Bram

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About