Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.91k stars 542 forks source link

Bug in if(open(my $fh,...)) { } scoping #9302

Open p5pRT opened 16 years ago

p5pRT commented 16 years ago

Migrated from rt.perl.org#53294 (status was 'open')

Searchable as RT53294$

p5pRT commented 16 years ago

From matt@sergeant.org

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.

p5pRT commented 16 years ago

From query1000@gmail.com

Created by query1000@gmail.com

Type following script and save it with UTF-8\, and run with Perl 5.10.0 and Windows XP SP2 DOS BOX. The DOS BOX will be frozen.

Some how the filename of the program matters with the phenomenon.

I saved the program as; C​:\Documents and Settings\fuc\Ç_ÇQÇGÇ`Ç[Ço\test\test.pl (Ç_ÇQÇGÇ`Ç[Ço is Japanese pathname Desktop) and run it as following command; C​:\> cd Documents and Settings\fuc\Ç_ÇQÇGÇ`Ç[Ço C​:\Documents and Settings\fuc\Ç_ÇQÇGÇ`Ç[Ço\> .\test.pl and it will cause the freeze.

But when I saved the program as; C​:\Documents and Settings\fuc\Ç_ÇQÇGÇ`Ç[Ço\test\bug.pl and run it as following command; C​:\> cd Documents and Settings\fuc\Ç_ÇQÇGÇ`Ç[Ço C​:\Documents and Settings\fuc\Ç_ÇQÇGÇ`Ç[Ço\> .\bug.pl and it WON'T cause the freeze.

Thank you !

#! /bin/perl -w # # if you run this program wirh ActivePerl 5.10.0 and Windows XP\, the Dos Box will be frozen

use utf8; binmode STDERR\, "encoding(​:cp932)";

while (\) { if (m|^"(.+?)"|) {   warn "$1"; } else {   warn "no hit"; } print; } # data is QUOTATION MARK+BULLET+SPACE+BULLET+QUOTATION MARK # SPACE U+0020 http​://www.fileformat.info/info/unicode/char/0020/index.htm # BULLET U+0022 http​://www.fileformat.info/info/unicode/char/2022/index.htm # BULLET U+2022 http​://www.fileformat.info/info/unicode/char/2022/index.htm __DATA__ "¡E ¡E" -- Regards\, Chihiro

Perl Info ``` Flags: category=library severity=high Site configuration information for perl 5.10.0: Configured by SYSTEM at Thu Jan 10 11:00:30 2008. Summary of my perl5 (revision 5 version 10 subversion 0) configuration: Platform: osname=MSWin32, osvers=5.00, archname=MSWin32-x86-multi-thread uname='' config_args='undef' hint=recommended, useposix=true, d_sigaction=undef useithreads=define, usemultiplicity=define useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef use64bitint=undef, use64bitall=undef, uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='cl', ccflags ='-nologo -GF -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT -DUSE_SITECUSTOMIZE -DPRIVLIB_LAST_IN_INC -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_MSVCRT_READFIX', optimize='-MD -Zi -DNDEBUG -O1', cppflags='-DWIN32' ccversion='12.00.8804', gccversion='', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234 d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=10 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='__int64', lseeksize=8 alignbytes=8, prototype=define Linker and Libraries: ld='link', ldflags ='-nologo -nodefaultlib -debug -opt:ref,icf -libpath:"C:\Perl\lib\CORE" -machine:x86' libpth=\lib libs= oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib msvcrt.lib perllibs= oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib msvcrt.lib libc=msvcrt.lib, so=dll, useshrplib=true, libperl=perl510.lib gnulibc_version='' Dynamic Linking: dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' ' cccdlflags=' ', lddlflags='-dll -nologo -nodefaultlib -debug -opt:ref,icf -libpath:"C:\Perl\lib\CORE" -machine:x86' Locally applied patches: ACTIVEPERL_LOCAL_PATCHES_ENTRY 32809 Load 'loadable object' with non-default file extension 32728 64-bit fix for Time::Local @INC for perl 5.10.0: C:\Perl\mylib C:/Perl/site/lib C:/Perl/lib Environment for perl 5.10.0: HOME (unset) LANG=ja_JP.SJIS LANGUAGE (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=C:\Perl\site\bin;C:\Perl\bin;C:\namazu\bin;C:\CFusionMX7\verity\k2\_nti40\bin;C:\Perl\bin\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\Common Files\Adobe\AGL;C:\Perl\perl;C:\Documents and Settings\All Users\Application Data\Logoport;C:\Program Files\QuickTime\QTSystem\;C:\mojicode_script;C:\Perl\perl;C:\Perl\perl_bak PERL5LIB=C:\Perl\mylib PERL_BADLANG (unset) SHELL (unset) ```
p5pRT commented 16 years ago

From matt@sergeant.org

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.

p5pRT commented 16 years ago

From @druud62

Matt Sergeant schreef​:

# New Ticket Created by Matt Sergeant # Please include the string​: [perl #53504] # in the subject line of all future correspondence about this issue. # \<URL​: http​://rt.perl.org/rt3/Ticket/Display.html?id=53504 >

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.

I agree it is kind of an error.

That do{} needs a ";" at the end. But you can do without the do.

I frequently put an extra block around the file stuff​:

  my $filename = "/etc/passwd";   ...   { local $\ = "\n";   open my $fh\, "\<"\, $filename or die "error with '$filename'​:\n\t$!";   ...   }

such that the close() will happen automagically.

-- Affijn\, Ruud

"Gewoon is een tijger."

p5pRT commented 16 years ago

The RT System itself - Status changed from 'new' to 'open'

p5pRT commented 16 years ago

From @tux

On Mon\, 28 Apr 2008 23​:57​:01 -0700\, Matt Sergeant (via RT) \perlbug\-followup@&#8203;perl\.org wrote​:

# New Ticket Created by Matt Sergeant # Please include the string​: [perl #53504] # in the subject line of all future correspondence about this issue. # \<URL​: http​://rt.perl.org/rt3/Ticket/Display.html?id=53504 >

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.

related nuisance​:

/home/merijn 102 > cat xx.pl #!/pro/bin/perl

use strict; use warnings;

if (my @​scr = glob ("*.sh")) {   print "I have shell scripts here\n";   } elsif (my @​scr = glob ("*.pl")) {   print "I have perl scripts here\n";   } /home/merijn 103 > perl xx.pl "my" variable @​scr masks earlier declaration in same scope at xx.pl line 9. I have perl scripts here /home/merijn 104 >

-- H.Merijn Brand Amsterdam Perl Mongers (http​://amsterdam.pm.org/) using & porting perl 5.6.2\, 5.8.x\, 5.10.x on HP-UX 10.20\, 11.00\, 11.11\, & 11.23\, SuSE 10.1 & 10.2\, AIX 5.2\, and Cygwin. http​://qa.perl.org http​://mirrors.develooper.com/hpux/ http​://www.test-smoke.org   http​://www.goldmark.org/jeff/stupid-disclaimers/

p5pRT commented 16 years ago

From @rgs

2008/4/29 H.Merijn Brand \h\.m\.brand@&#8203;xs4all\.nl​:

related nuisance​:

/home/merijn 102 > cat xx.pl #!/pro/bin/perl

use strict; use warnings;

if (my @​scr = glob ("*.sh")) { print "I have shell scripts here\n"; } elsif (my @​scr = glob ("*.pl")) { print "I have perl scripts here\n"; } /home/merijn 103 > perl xx.pl "my" variable @​scr masks earlier declaration in same scope at xx.pl line 9. I have perl scripts here /home/merijn 104 >

That's exactly the opposite problem you're having there. Just remove the 2nd my...

p5pRT commented 16 years ago

From @tux

On Wed\, 30 Apr 2008 09​:01​:22 +0200\, "Rafael Garcia-Suarez" \rgarciasuarez@&#8203;gmail\.com wrote​:

2008/4/29 H.Merijn Brand \h\.m\.brand@&#8203;xs4all\.nl​:

related nuisance​:

/home/merijn 102 > cat xx.pl #!/pro/bin/perl

use strict; use warnings;

if (my @​scr = glob ("*.sh")) { print "I have shell scripts here\n"; } elsif (my @​scr = glob ("*.pl")) { print "I have perl scripts here\n"; } /home/merijn 103 > perl xx.pl "my" variable @​scr masks earlier declaration in same scope at xx.pl line 9. I have perl scripts here /home/merijn 104 >

That's exactly the opposite problem you're having there. Just remove the 2nd my...

I know. The `problem' is that the scoping doesn't DWIM. At least not for me. I don't expect the 'if (my $x = ...) {}' to live on in the else branch\, which is why I expect the above snippet to work. I also know it to not work when I see the error\, and then I usually change the code to

{ my @​scr;   if (@​scr = ...) {   :   }   elsif (@​scr = ...) {   }   }

-- H.Merijn Brand Amsterdam Perl Mongers (http​://amsterdam.pm.org/) using & porting perl 5.6.2\, 5.8.x\, 5.10.x on HP-UX 10.20\, 11.00\, 11.11\, & 11.23\, SuSE 10.1 & 10.2\, AIX 5.2\, and Cygwin. http​://qa.perl.org http​://mirrors.develooper.com/hpux/ http​://www.test-smoke.org   http​://www.goldmark.org/jeff/stupid-disclaimers/

p5pRT commented 16 years ago

From matt@sergeant.org

On 30-Apr-08\, at 7​:32 AM\, H. Merijn Brand via RT wrote​:

That's exactly the opposite problem you're having there. Just remove the 2nd my...

I know. The `problem' is that the scoping doesn't DWIM. At least not for me. I don't expect the 'if (my $x = ...) {}' to live on in the
else branch\, which is why I expect the above snippet to work. I also
know it to not work when I see the error\, and then I usually change the
code to

{ my @​scr; if (@​scr = ...) { : } elsif (@​scr = ...) { } }

Yup\, IMHO this was an error in judgement by whoever chose this
behaviour originally. But we're stuck with it now.

Matt.

p5pRT commented 16 years ago

From @rgs

2008/4/30 Matt Sergeant \matt@&#8203;sergeant\.org​:

I know. The `problem' is that the scoping doesn't DWIM. At least not for me. I don't expect the 'if (my $x = ...) {}' to live on in the else branch\, which is why I expect the above snippet to work. I also know it to not work when I see the error\, and then I usually change the code to

{ my @​scr; if (@​scr = ...) { : } elsif (@​scr = ...) { } }

Yup\, IMHO this was an error in judgement by whoever chose this behaviour originally. But we're stuck with it now.

I don't think so. I think the intent behind this feature's design was to allow :

if ((my $ret = somecall()) == 0) {   # profit ! } elsif ($ret == -1) {   # handle error code -1 } elsif ($ret == -2) {   # handle error code -2 } else { etc... }

p5pRT commented 16 years ago

From matt@sergeant.org

On 30-Apr-08\, at 10​:04 AM\, Rafael Garcia-Suarez via RT wrote​:

Yup\, IMHO this was an error in judgement by whoever chose this
behaviour originally. But we're stuck with it now.

I don't think so. I think the intent behind this feature's design was to allow :

if ((my $ret = somecall()) == 0) { # profit ! } elsif ($ret == -1) { # handle error code -1 } elsif ($ret == -2) { # handle error code -2 } else { etc... }

I know. I just don't think it's used like that very much (if at
all?)\, and I don't think the chosen implementation makes visual sense.

If we'd have had given/when back then I suspect the scoping would
have been implemented differently.

Matt.

p5pRT commented 16 years ago

From @gbarr

On Apr 30\, 2008\, at 9​:03 AM\, Rafael Garcia-Suarez wrote​:

2008/4/30 Matt Sergeant \matt@&#8203;sergeant\.org​:

I know. The `problem' is that the scoping doesn't DWIM. At least not for me. I don't expect the 'if (my $x = ...) {}' to live on in
the else branch\, which is why I expect the above snippet to work. I also
know it to not work when I see the error\, and then I usually change the
code to

{ my @​scr; if (@​scr = ...) { : } elsif (@​scr = ...) { } }

Yup\, IMHO this was an error in judgement by whoever chose this
behaviour originally. But we're stuck with it now.

I don't think so. I think the intent behind this feature's design was to allow :

if ((my $ret = somecall()) == 0) { # profit ! } elsif ($ret == -1) { # handle error code -1 } elsif ($ret == -2) { # handle error code -2 } else { etc... }

Yes. I cannot find the email thread that led up to the change but it
was added in 5.003_08

  Title​: "Defined scoping for C\ in control structures"   (Finally defines semantics of "my" in control expressions\,   like the condition of "if" and "while". In all cases\, scope   of a "my" var extends to the end of the entire control   structure. Also adds new construct "for my"\, which   automatically declares the control variable "my" and limits   its scope to the loop.)   From​: Chip Salzenberg   Files​: op.c perly.c perly.c.diff perly.h perly.y proto.h toke.c

There is also a mention\, with an example\, in

http​://search.cpan.org/dist/perl/pod/ perl5004delta.pod#New_and_changed_builtin_functions

page down a bit to my() in Control Structures

Graham.

p5pRT commented 16 years ago

From @ap

* Matt Sergeant \matt@&#8203;sergeant\.org [2008-04-30 16​:15]​:

If we'd have had given/when back then I suspect the scoping would have been implemented differently.

Well yeah – one of the many things Perl 6 canonicalises is that there are no edge cases in scoping. A variable declared within a pair of curlies is local to it\, and a variable declared outside is not\, and no constructs leak scopes across blocks somehow.

Regards\, -- Aristotle Pagaltzis // \<http​://plasmasturm.org/>

p5pRT commented 16 years ago

From schmorp@schmorp.de

On Wed\, Apr 30\, 2008 at 10​:14​:15AM -0400\, Matt Sergeant \matt@&#8203;sergeant\.org wrote​:

if ((my $ret = somecall()) == 0) { # profit !

I know. I just don't think it's used like that very much (if at
all?)\, and I don't think the chosen implementation makes visual sense.

For what it's worth\, C++ has the same scoping rule (else scope included\, and I use it a lot in C++\, but little in Perl\, for some reason I cannot quite explain).

So at least c++ and perl programmers have one difference less to remember (not that it matters).

On Thu\, May 01\, 2008 at 12​:14​:55PM +0200\, Aristotle Pagaltzis \pagaltzis@&#8203;gmx\.de wrote​:

* Matt Sergeant \matt@&#8203;sergeant\.org [2008-04-30 16​:15]​:

If we'd have had given/when back then I suspect the scoping would have been implemented differently.

Well yeah – one of the many things Perl 6 canonicalises is that there are no edge cases in scoping. A variable declared within a pair of curlies is local to it\, and a variable declared outside is not\, and no constructs leak scopes across blocks somehow.

So the my variable would not be local to the if at all in this case\, but to the outer block? Thats quite horrible\, IMnsHO (even C++ managed to correct this mistake in scoping :) But then\, perl6 r.i.p. :=)

--   The choice of a Deliantra\, the free code+content MORPG   -----==- _GNU_ http​://www.deliantra.net   ----==-- _ generation   ---==---(_)__ __ ____ __ Marc Lehmann   --==---/ / _ \/ // /\ \/ / pcg@​goof.com   -=====/_/_//_/\_\,_/ /_/\_\

p5pRT commented 16 years ago

From @ap

* Marc Lehmann \schmorp@&#8203;schmorp\.de [2008-05-02 19​:05]​:

On Thu\, May 01\, 2008 at 12​:14​:55PM +0200\, Aristotle Pagaltzis \pagaltzis@&#8203;gmx\.de wrote​:

* Matt Sergeant \matt@&#8203;sergeant\.org [2008-04-30 16​:15]​:

If we'd have had given/when back then I suspect the scoping would have been implemented differently.

Well yeah – one of the many things Perl 6 canonicalises is that there are no edge cases in scoping. A variable declared within a pair of curlies is local to it\, and a variable declared outside is not\, and no constructs leak scopes across blocks somehow.

So the my variable would not be local to the if at all in this case\, but to the outer block? Thats quite horrible\, IMnsHO (even C++ managed to correct this mistake in scoping :)

No. My description was slightly incomplete in that all blocks are closures in Perl 6 and so all of them can have formal parameters\, which\, of course\, are declared in front and outside of the block. So this Perl 5 construct​:

  if ( my $foo = \<$bar> ) { ... }

in Perl 6 becomes​:

  if =$bar -> $foo { ... }

However\, there is no exception for having that declaration remain in scope for the conditional and block of a following `elsif`. In instances where you think you want that\, you want `given`/`when` instead​:

  given foo() {   when 'bar' { ... }   when 'baz' { ... }   else { ... }   }

Again the rule is very simple​: the block always denotes the exact scope of a variable – there is no cross-scope declaration leak magic anywhere.

But then\, perl6 r.i.p. :=)

Careful with such proclamations\, this list is archived in many places… :-)

Regards\, -- Aristotle Pagaltzis // \<http​://plasmasturm.org/>

p5pRT commented 14 years ago

From @cpansprout

On Mon Apr 28 23​:56​:54 2008\, query1000@​gmail.com wrote​:

This is a bug report for perl from query1000@​gmail.com\, generated with the help of perlbug 1.36 running under perl 5.10.0.

etc.

I’ve gone and done it again. I meant to merge this into 53276. Please just disregard this message. It’s not part of this ticket.

p5pRT commented 14 years ago

@cpansprout - Status changed from 'new' to 'open'