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

PL_last_in_gv paradigm conflict #11813

Open
p5pRT opened this issue Dec 19, 2011 · 1 comment
Open

PL_last_in_gv paradigm conflict #11813

p5pRT opened this issue Dec 19, 2011 · 1 comment

Comments

@p5pRT
Copy link

p5pRT commented Dec 19, 2011

Migrated from rt.perl.org#106536 (status was 'new')

Searchable as RT106536$

@p5pRT
Copy link
Author

p5pRT commented Dec 19, 2011

From @cpansprout

Background​:

PL_last_in_gv is where perl remembers the last-accessed filehandle. This is what $. and tell and eof without arguments use. It is set by readline, tell, eof and seek.

This variable is not reference-counted, so when a gv is freed PL_last_in_gv is set to null if it points to it.

As of perl 5.14, rv2gv (*{...}) returns a mortal copy of the glob, with the FAKE flag off, that shares the same glob pointer.

(The FAKE flag on a glob means that assignment to it will clobber it. *foo has the FAKE flag off. my $fh = *foo results in $fh being a glob with the FAKE flag on.)

tell, eof and seek all supply an implicit *{...} around their (first) argument. readline, oddly enough, does not.

Before I fixed it just recently, PL_last_in_gv could point to a freed scalar as a result of​:

  $f{g} = *foo;
  readline($f{g});
  $f{g} = 3;
  undef %h;

The $f{g} = 3 assignment would cause PL_last_in_gv to cease being a glob. undef %h would free the scalar in PL_last_in_gv. Since it was the glob-freeing code that cleared PL_last_in_gv, it would not get called when the scalar was freed, because it was no longer a glob. I fixed this by making glob coercion (during the $f{g} = 3 assignment) also unset PL_last_in_gv.

There was also a regression in 5.14 that I fixed recently​: tell($glob_copy) would, due to its implicit *{}, set PL_last_in_gv to a mortal copy of $glob_copy, which would be freed at the end of the statement, resulting in PL_last_in_gv simply not being set. I fixed it by flagging the rv2gv so that it will return a fake glob if passed one.


Problem​:

Now we have an interesting discrepancy​: tell(*$glob_copy) will set PL_last_in_gv, but tell(*{*$glob_copy}) won’t, because the inner * doesn’t get the flag set. (For those who don’t know, *{...} returns its argument if it is a glob not flagged FAKE, so *{*{*{*{*foo}}}} is the same as *foo.)

Also, it used to be possible to write

  $fh = *STDOUT;
  readline($fh);
  $fh = 3;
  $fh = *STDOUT;

And have PL_last_in_gv still pointing to $fh (effectively to STDOUT). Now it’s not.

We have three expectations that we are trying to meet, which are in conflict​:

1. PL_last_in_gv remembers the last filehandle that was accessed.
2. Assigning to the last handle’s glob can change what handle it
  points to one (<STDOUT>; *STDOUT = *foo).
3. Filehandles are closed automatically on scope exit if they are only
  referenced in that scope.

Item number 1 can be solved by making PL_last_in_gv reference-counted. But that will break number 3.

Item number 2 is probably impossible to solve in the presence of fake globs, except perhaps by discouraging their use. Yet they actually provide a very useful feature​:

  $fh = *STDOUT;
  $fh->autoflush(1); # ok
  $fh = \*STDOUT;
  $fh->autoflush(1); # Can't call a method on a unblessed reference


One possible solution​:

To make PL_last_in_gv remember the last filehandle even when fake globs are involved, when a glob is freed or coerced, and that glob is in PL_last_in_gv, set PL_last_in_gv to a new glob with the same name and the same IO but with a weak reference in its IO slot. PL_last_in_gv with hold a reference count on that glob. Since there can only be one such glob, we need only one gv flag for that. When the IO thing is freed and the backreference killed, we can free the glob in PL_last_in_gv and set the latter to null.

That would allow 1 to work, without breaking 3, but it’s a twisted maze of action at a distance (like the rest of perl, come to think of it).

As for number 2, it already works with normal globs, but not with fake globs. I don’t think we can make it work. It is currently the same with select().


Conclusion​:

This is a mess.


Flags​:
  category=core
  severity=low


Site configuration information for perl 5.15.5​:

Configured by sprout at Sun Dec 18 11​:26​:14 PST 2011.

Summary of my perl5 (revision 5 version 15 subversion 5) configuration​:
Snapshot of​: 5dca8ed
Platform​:
  osname=darwin, osvers=10.5.0, archname=darwin-2level
  uname='darwin pint.local 10.5.0 darwin kernel version 10.5.0​: fri nov 5 23​:20​:39 pdt 2010; root​:xnu-1504.9.17~1release_i386 i386 '
  config_args='-de -Dusedevel -DDEBUGGING=-g'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=undef, usemultiplicity=undef
  useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
  use64bitint=undef, use64bitall=undef, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
Compiler​:
  cc='cc', ccflags ='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include',
  optimize='-O3 -g',
  cppflags='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
  ccversion='', gccversion='4.2.1 (Apple Inc. build 5664)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
  ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=8, prototype=define
Linker and Libraries​:
  ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib
  libs=-ldbm -ldl -lm -lutil -lc
  perllibs=-ldl -lm -lutil -lc
  libc=, so=dylib, useshrplib=false, libperl=libperl.a
  gnulibc_version=''
Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
  cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup -L/usr/local/lib -fstack-protector'

Locally applied patches​:


@​INC for perl 5.15.5​:
  /usr/local/lib/perl5/site_perl/5.15.5/darwin-2level
  /usr/local/lib/perl5/site_perl/5.15.5
  /usr/local/lib/perl5/5.15.5/darwin-2level
  /usr/local/lib/perl5/5.15.5
  /usr/local/lib/perl5/site_perl
  .


Environment for perl 5.15.5​:
  DYLD_LIBRARY_PATH (unset)
  HOME=/Users/sprout
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/usr/bin​:/bin​:/usr/sbin​:/sbin​:/usr/local/bin​:/usr/X11/bin​:/usr/local/bin
  PERL_BADLANG (unset)
  SHELL=/bin/bash

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

No branches or pull requests

2 participants