Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*FH{IO} and $. scoping ickiness #1420

Open
p5pRT opened this issue Mar 22, 2000 · 6 comments · May be fixed by #19125
Open

*FH{IO} and $. scoping ickiness #1420

p5pRT opened this issue Mar 22, 2000 · 6 comments · May be fixed by #19125

Comments

@p5pRT
Copy link

p5pRT commented Mar 22, 2000

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

Searchable as RT2566$

@p5pRT
Copy link
Author

p5pRT commented Mar 22, 2000

From @simoncozens

othersideofthe:simon ~ % perl -wle 'my $a;
my $f=do { local *FH; open(FH,"/etc/passwd"); *FH; };
0 while <$f>; print $.'
48

othersideofthe:simon ~ % perl -wle 'my $a;
my $f=do { local *FH; open(FH,"/etc/passwd"); *FH{IO}; };
0 while <$f>; print $.'
Use of uninitialized value in print at -e line 1.

othersideofthe:simon ~ % perl -wle 'my $a;
my $f=do { local *FH; open(FH,"/etc/passwd"); *FH{IO}; };
$a=$. while <$f>; print $.'
48
Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl v5.6.0:

Configured by simon at Wed Mar 22 01:37:29 JST 2000.

Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration:
  Platform:
    osname=linux, osvers=2.2.14, archname=i686-linux
    uname='linux othersideofthe.earth.li 2.2.14 #3 smp mon mar 13 02:10:19 jst 2000 i686 unknown '
    config_args='-d'
    hint=previous, useposix=true, d_sigaction=define
    usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
    useperlio=undef d_sfio=undef uselargefiles=define 
    use64bitint=undef use64bitall=undef uselongdouble=undef usesocks=undef
  Compiler:
    cc='cc', optimize='-g', gccversion=2.95.2 20000220 (Debian GNU/Linux)
    cppflags='-fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
    ccflags ='-fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
    stdchar='char', d_stdstdio=define, usevfork=false
    intsize=4, longsize=4, ptrsize=4, doublesize=8
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, usemymalloc=n, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lnsl -lndbm -lgdbm -ldb -ldl -lm -lc -lposix -lcrypt
    libc=/lib/libc-2.1.3.so, so=so, useshrplib=false, libperl=libperl.a
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic'
    cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    v5.6.0-RC3


@INC for perl v5.6.0:
    /usr/local/lib/perl5/5.6.0/i686-linux
    /usr/local/lib/perl5/5.6.0
    /usr/local/lib/perl5/site_perl/5.6.0/i686-linux
    /usr/local/lib/perl5/site_perl/5.6.0
    /usr/local/lib/perl5/site_perl/5.5.670
    /usr/local/lib/perl5/site_perl
    .


Environment for perl v5.6.0:
    HOME=/home/simon
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/simon/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/rhs/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/kde/bin:/home/simon/bin
    PERL_BADLANG (unset)
    SHELL=/bin/zsh

@p5pRT
Copy link
Author

p5pRT commented Dec 13, 2004

From @schwern

This appears to have gotten worse.

> othersideofthe:simon ~ % perl -wle 'my $a;
> my $f=do { local *FH; open(FH,"/etc/passwd"); *FH; };
> 0 while <$f>; print $.'
> 48

[~] perl5.6.2 -wle 'my $a;
my $f=do { local *FH; open(FH,"/etc/passwd"); *FH; };
0 while <$f>; print $.'
28
[~] perl5.8.6 -wle 'my $a;
my $f=do { local *FH; open(FH,"/etc/passwd"); *FH; };
0 while <$f>; print $.'
readline() on unopened filehandle FH at -e line 3.
0


> othersideofthe:simon ~ % perl -wle 'my $a;
> my $f=do { local *FH; open(FH,"/etc/passwd"); *FH{IO}; };
> 0 while <$f>; print $.'
> Use of uninitialized value in print at -e line 1.

[~] perl5.6.2 -wle 'my $a;
my $f=do { local *FH; open(FH,"/etc/passwd"); *FH{IO}; };
0 while <$f>; print $.'
Use of uninitialized value in print at -e line 3.

[~] perl5.8.6 -wle 'my $a;
my $f=do { local *FH; open(FH,"/etc/passwd"); *FH{IO}; };
0 while <$f>; print $.'
Use of uninitialized value in print at -e line 3.


> othersideofthe:simon ~ % perl -wle 'my $a;
> my $f=do { local *FH; open(FH,"/etc/passwd"); *FH{IO}; };
> $a=$. while <$f>; print $.'
> 48

[~] perl5.6.2 -wle 'my $a;
my $f=do { local *FH; open(FH,"/etc/passwd"); *FH{IO}; };
$a=$. while <$f>; print $.'
28
[~] perl5.8.6 -wle 'my $a;
my $f=do { local *FH; open(FH,"/etc/passwd"); *FH{IO}; };
$a=$. while <$f>; print $.'
28

@p5pRT
Copy link
Author

p5pRT commented Jan 17, 2020

@simoncozens, thank you for reporting Perl RT 2566. Your ticket has been moved to #1420

@toddr
Copy link
Member

toddr commented Feb 3, 2020

This appears to still be an issue on perl 5.30. $. is not set if you do <$f> where $f was assigned from *FH{IO}

@Leont
Copy link
Contributor

Leont commented Feb 3, 2020

This appears to still be an issue on perl 5.30. $. is not set if you do <$f> where $f was assigned from *FH{IO}

This can also be formulated as «$^LAST_FH is not set if you do <$f> where $f was an IO reference instead of a glob reference»

@tonycoz
Copy link
Contributor

tonycoz commented Dec 10, 2020

This appears to still be an issue on perl 5.30. $. is not set if you do <$f> where $f was assigned from *FH{IO}

This can also be formulated as $^LAST_FH is not set if you do <$f> where $f was an IO reference instead of a glob reference

It's not so much that it's not set, it's that it's set and then immediately cleared.

Each of the I/O ops either has a rv2gv generated for it (most) or calls rv2gv itself (readline), which for an IO ref create a mortal GV which is then assigned to PL_last_in_gv, on the next FREETMPS that's released and PL_last_in_gv is cleared (in Perl_sv_clear()).

tonycoz added a commit to tonycoz/perl5 that referenced this issue Sep 14, 2021
It's always been possible to extract a reference to the IO SV from
a glob, and use that for I/O, but such use would set PL_last_in_gv
to a temporary GV which would almost immediately be released,
clearing PL_last_in_gv.

This would result in reads from $. returning its most recently read
value (even from another handle) and modification being ignored, while
${^LAST_FH} would return undef, even though the file handle is still
open.

To fix this, store the underlying IO object as well as the GV.
Retaining the GV lets errors continue to report the GV name where
possible, while the IO object means $. and ${^LAST_FH} can still work
if the IO object still exists.

This does not try to fix the problem where localization can leave
PL_last_in_gv (and now PL_last_in_io) pointing at a SV that has been
destroyed, the original changes that introduced PL_last_in_gv didn't
keep a reference count for the GV, since this would prevent the file
being close automatically when the reference to to the glob went out
of scope.

Fixes Perl#1420
@xenu xenu removed the Severity Low label Dec 29, 2021
tonycoz added a commit to tonycoz/perl5 that referenced this issue Jul 11, 2022
It's always been possible to extract a reference to the IO SV from
a glob, and use that for I/O, but such use would set PL_last_in_gv
to a temporary GV which would almost immediately be released,
clearing PL_last_in_gv.

This would result in reads from $. returning its most recently read
value (even from another handle) and modification being ignored, while
${^LAST_FH} would return undef, even though the file handle is still
open.

To fix this, store the underlying IO object as well as the GV.
Retaining the GV lets errors continue to report the GV name where
possible, while the IO object means $. and ${^LAST_FH} can still work
if the IO object still exists.

This does not try to fix the problem where localization can leave
PL_last_in_gv (and now PL_last_in_io) pointing at a SV that has been
destroyed, the original changes that introduced PL_last_in_gv didn't
keep a reference count for the GV, since this would prevent the file
being close automatically when the reference to to the glob went out
of scope.

Fixes Perl#1420
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants