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

UNIVERSAL::AUTOLOAD breaks named captures/%-/%+ #11781

Closed
p5pRT opened this issue Nov 30, 2011 · 7 comments
Closed

UNIVERSAL::AUTOLOAD breaks named captures/%-/%+ #11781

p5pRT opened this issue Nov 30, 2011 · 7 comments

Comments

@p5pRT
Copy link

p5pRT commented Nov 30, 2011

Migrated from rt.perl.org#105024 (status was 'resolved')

Searchable as RT105024$

@p5pRT
Copy link
Author

p5pRT commented Nov 30, 2011

From @mauke

Created by @mauke

% perl -wle '{ package UNIVERSAL; sub AUTOLOAD { warn "$AUTOLOAD(@​_)" } } "a" =~ /(?<X>.)/ or die; print "$+{X}"'
IO​::File​::DESTROY(IO​::File=IO(0x9447790)) at -e line 1.
Use of uninitialized value $+{"X"} in string at -e line 1.

% perl -wle '%- if 0; { package UNIVERSAL; sub AUTOLOAD { warn "$AUTOLOAD(@​_)" } } "a" =~ /(?<X>.)/ or die; print "$+{X}"'
IO​::File​::DESTROY(IO​::File=IO(0x823f798)) at -e line 1.
a
Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x823fba8)) at -e line 1 during global destruction.
Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x823fca8)) at -e line 1 during global destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f078)) at -e line 1 during global destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f0f8)) at -e line 1 during global destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f178)) at -e line 1 during global destruction.

So apparently just creating UNIVERSAL​::AUTOLOAD is enough to break %+, even if
AUTOLOAD is never called. But (for some reason) letting the parser see %+ early
makes things work as expected.

As far as I can tell this is broken in 5.12 and 5.10 but works in 5.14,
probably because Tie​::Hash​::NamedCapture is a real (XS) module there.

Any idea what's going on?

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.12.3:

Configured by mauke at Tue Aug  9 13:00:53 CEST 2011.

Summary of my perl5 (revision 5 version 12 subversion 3) configuration:
   
  Platform:
    osname=linux, osvers=2.6.37-gentoo-r4, archname=i686-linux
    uname='linux nora 2.6.37-gentoo-r4 #5 preempt sun may 8 03:58:55 cest 2011 i686 amd athlon(tm) 64 processor 3200+ authenticamd gnulinux '
    config_args='-de -Dprefix=/home/mauke/usr/perlbrew/perls/perl-5.12.3'
    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-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.4.5', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    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, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
    libc=/lib/libc-2.12.2.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.12.2'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector'

Locally applied patches:
    


@INC for perl 5.12.3:
    /home/mauke/usr/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/i686-linux
    /home/mauke/usr/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3
    /home/mauke/usr/perlbrew/perls/perl-5.12.3/lib/5.12.3/i686-linux
    /home/mauke/usr/perlbrew/perls/perl-5.12.3/lib/5.12.3
    .


Environment for perl 5.12.3:
    HOME=/home/mauke
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LC_COLLATE=POSIX
    LD_LIBRARY_PATH=/home/mauke/usr/local/lib
    LOGDIR (unset)
    PATH=/home/mauke/usr/perlbrew/bin:/home/mauke/usr/perlbrew/perls/perl-5.12.3/bin:/home/mauke/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/i686-pc-linux-gnu/gcc-bin/4.4.5:/opt/sun-jdk-1.4.2.13/bin:/opt/sun-jdk-1.4.2.13/jre/bin:/opt/sun-jdk-1.4.2.13/jre/javaws:/opt/dmd/bin:/usr/games/bin
    PERLBREW_HOME=/home/mauke/.perlbrew
    PERLBREW_PATH=/home/mauke/usr/perlbrew/bin:/home/mauke/usr/perlbrew/perls/perl-5.12.3/bin
    PERLBREW_PERL=perl-5.12.3
    PERLBREW_ROOT=/home/mauke/usr/perlbrew
    PERLBREW_VERSION=0.27
    PERL_BADLANG (unset)
    PERL_UNICODE=SAL
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Dec 1, 2011

From @jkeenan

Additional data points ... This is what I got on Linux for first 5.12.0,
then 5.14.2​:

###
$ /usr/local/bin/perl5.12.0 -wle '{ package UNIVERSAL; sub AUTOLOAD {
warn "$AUTOLOAD(@​_)" } } "a" =~ /(?<X>.)/ or die; print "$+{X}"'
IO​::File​::DESTROY(IO​::File=IO(0x817adf8)) at -e line 1.
Use of uninitialized value $+{"X"} in string at -e line 1.

###
$ perl -wle '{ package UNIVERSAL; sub AUTOLOAD { warn "$AUTOLOAD(@​_)" }
} "a" =~ /(?<X>.)/ or die; print "$+{X}"'
version​::DESTROY(v5.14.0) at -e line 1.
version​::DESTROY(v5.14.0) at -e line 1.
version​::DESTROY(v5.14.0) at -e line 1.
version​::DESTROY(0.08) at -e line 1.
version​::DESTROY(0.08) at -e line 1.
version​::DESTROY(v5.14.0) at -e line 1.
IO​::File​::DESTROY(IO​::File=IO(0x8189ff0)) at -e line 1.
a
Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x8196b68))
at -e line 1 during global destruction.
Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x8196bd8))
at -e line 1 during global destruction.
IO​::File​::DESTROY(IO​::File=IO(0x8189e10)) at -e line 1 during global
destruction.
IO​::File​::DESTROY(IO​::File=IO(0x817ada8)) at -e line 1 during global
destruction.
IO​::File​::DESTROY(IO​::File=IO(0x817ade8)) at -e line 1 during global
destruction.
IO​::File​::DESTROY(IO​::File=IO(0x817ae28)) at -e line 1 during global
destruction.
###

Similar results with these two Perl versions on Darwin.

@p5pRT
Copy link
Author

p5pRT commented Dec 1, 2011

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

@p5pRT
Copy link
Author

p5pRT commented Dec 1, 2011

From @cpansprout

On Wed Nov 30 13​:39​:47 2011, l.mai@​web.de wrote​:

% perl -wle '{ package UNIVERSAL; sub AUTOLOAD { warn "$AUTOLOAD(@​_)"
} } "a" =~ /(?<X>.)/ or die; print "$+{X}"'
IO​::File​::DESTROY(IO​::File=IO(0x9447790)) at -e line 1.
Use of uninitialized value $+{"X"} in string at -e line 1.

% perl -wle '%- if 0; { package UNIVERSAL; sub AUTOLOAD { warn
"$AUTOLOAD(@​_)" } } "a" =~ /(?<X>.)/ or die; print "$+{X}"'
IO​::File​::DESTROY(IO​::File=IO(0x823f798)) at -e line 1.
a

Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x823fba8))

at -e line 1 during global destruction.

Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x823fca8))

at -e line 1 during global destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f078)) at -e line 1 during global
destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f0f8)) at -e line 1 during global
destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f178)) at -e line 1 during global
destruction.

So apparently just creating UNIVERSAL​::AUTOLOAD is enough to break %+,
even if
AUTOLOAD is never called. But (for some reason) letting the parser see
%+ early
makes things work as expected.

As far as I can tell this is broken in 5.12 and 5.10 but works in
5.14,
probably because Tie​::Hash​::NamedCapture is a real (XS) module there.

Any idea what's going on?

It was indeed this commit that made the difference, but I cannot
understand why​:

commit 8dcfe2e
Author​: Nicholas Clark <nick@​ccl4.org>
Date​: Thu Oct 14 15​:34​:03 2010 +0100

  Move remaining Tie​::Hash​::NamedCapture XS code to NamedCapture.xs
 
  Now all the support code for %+ and %- is contained in the module in
ext/

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Dec 1, 2011

From @cpansprout

On Wed Nov 30 17​:49​:48 2011, sprout wrote​:

On Wed Nov 30 13​:39​:47 2011, l.mai@​web.de wrote​:

% perl -wle '{ package UNIVERSAL; sub AUTOLOAD { warn "$AUTOLOAD(@​_)"
} } "a" =~ /(?<X>.)/ or die; print "$+{X}"'
IO​::File​::DESTROY(IO​::File=IO(0x9447790)) at -e line 1.
Use of uninitialized value $+{"X"} in string at -e line 1.

% perl -wle '%- if 0; { package UNIVERSAL; sub AUTOLOAD { warn
"$AUTOLOAD(@​_)" } } "a" =~ /(?<X>.)/ or die; print "$+{X}"'
IO​::File​::DESTROY(IO​::File=IO(0x823f798)) at -e line 1.
a

Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x823fba8))

at -e line 1 during global destruction.

Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x823fca8))

at -e line 1 during global destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f078)) at -e line 1 during global
destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f0f8)) at -e line 1 during global
destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f178)) at -e line 1 during global
destruction.

So apparently just creating UNIVERSAL​::AUTOLOAD is enough to break %+,
even if
AUTOLOAD is never called. But (for some reason) letting the parser see
%+ early
makes things work as expected.

As far as I can tell this is broken in 5.12 and 5.10 but works in
5.14,
probably because Tie​::Hash​::NamedCapture is a real (XS) module there.

Any idea what's going on?

It was indeed this commit that made the difference, but I cannot
understand why​:

commit 8dcfe2e
Author​: Nicholas Clark <nick@​ccl4.org>
Date​: Thu Oct 14 15​:34​:03 2010 +0100

Move remaining Tie&#8203;::Hash&#8203;::NamedCapture XS code to NamedCapture\.xs

Now all the support code for %\+ and %\- is contained in the module in

ext/

I’ve just figured it out. In gv.c​:

S_require_tie_mod(pTHX_ GV *gv, const char *varpv, SV* namesv, const
char *methpv,const U32 flags)
{
  dVAR;
  HV* stash = gv_stashsv(namesv, 0);

  PERL_ARGS_ASSERT_REQUIRE_TIE_MOD;

  if (!stash || !(gv_fetchmethod(stash, methpv))) {

In gv.h​:

#define gv_fetchmethod(stash, name) gv_fetchmethod_autoload(stash, name,
TRUE)

So, if either the stash does not exist (as in 5.14; in 5.12 parts of it
are in core), or the method (TIEHASH in this case) cannot be found, even
by autoloading, then the module is loaded.

That means the problem still persists in 5.14. You just have to mention
the package (e.g., ‘Tie​::Hash​::NamedCapture​::Googoo() if 0’) and the
presence of a universal autoload sub will stop (compilation of) %- and
%+ from loading the module.

S_require_tie_mod probably should not be autoloading.

Errno and arybase have the same problem​:

$ ./perl -Ilib -le 'arybase​::Googoo() if 0; { package UNIVERSAL; sub
AUTOLOAD { warn "$AUTOLOAD(@​_)" } } $[ = 1; print qw(a b c)[2]'
IO​::File​::DESTROY(IO​::File=IO(0x823220)) at -e line 1.
c

(should print b)

$ ./perl -Ilib -le 'Errno​::onrrE() if 0; { package UNIVERSAL; sub
AUTOLOAD { warn "$AUTOLOAD(@​_)" } } $!=20; print $!{ENOTDIR}'
IO​::File​::DESTROY(IO​::File=IO(0x823220)) at -e line 1.

(should print 20, on Unix at least)

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Dec 1, 2011

From @cpansprout

On Wed Nov 30 18​:04​:50 2011, sprout wrote​:

On Wed Nov 30 17​:49​:48 2011, sprout wrote​:

On Wed Nov 30 13​:39​:47 2011, l.mai@​web.de wrote​:

% perl -wle '{ package UNIVERSAL; sub AUTOLOAD { warn "$AUTOLOAD(@​_)"
} } "a" =~ /(?<X>.)/ or die; print "$+{X}"'
IO​::File​::DESTROY(IO​::File=IO(0x9447790)) at -e line 1.
Use of uninitialized value $+{"X"} in string at -e line 1.

% perl -wle '%- if 0; { package UNIVERSAL; sub AUTOLOAD { warn
"$AUTOLOAD(@​_)" } } "a" =~ /(?<X>.)/ or die; print "$+{X}"'
IO​::File​::DESTROY(IO​::File=IO(0x823f798)) at -e line 1.
a

Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x823fba8))

at -e line 1 during global destruction.

Tie​::Hash​::NamedCapture​::DESTROY(Tie​::Hash​::NamedCapture=SCALAR(0x823fca8))

at -e line 1 during global destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f078)) at -e line 1 during global
destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f0f8)) at -e line 1 during global
destruction.
IO​::File​::DESTROY(IO​::File=IO(0x823f178)) at -e line 1 during global
destruction.

So apparently just creating UNIVERSAL​::AUTOLOAD is enough to break %+,
even if
AUTOLOAD is never called. But (for some reason) letting the parser see
%+ early
makes things work as expected.

As far as I can tell this is broken in 5.12 and 5.10 but works in
5.14,
probably because Tie​::Hash​::NamedCapture is a real (XS) module there.

Any idea what's going on?

It was indeed this commit that made the difference, but I cannot
understand why​:

commit 8dcfe2e
Author​: Nicholas Clark <nick@​ccl4.org>
Date​: Thu Oct 14 15​:34​:03 2010 +0100

Move remaining Tie&#8203;::Hash&#8203;::NamedCapture XS code to NamedCapture\.xs

Now all the support code for %\+ and %\- is contained in the module in

ext/

I’ve just figured it out. In gv.c​:

S_require_tie_mod(pTHX_ GV *gv, const char *varpv, SV* namesv, const
char *methpv,const U32 flags)
{
dVAR;
HV* stash = gv_stashsv(namesv, 0);

PERL\_ARGS\_ASSERT\_REQUIRE\_TIE\_MOD;

if \(\!stash || \!\(gv\_fetchmethod\(stash\, methpv\)\)\) \{

In gv.h​:

#define gv_fetchmethod(stash, name) gv_fetchmethod_autoload(stash, name,
TRUE)

So, if either the stash does not exist (as in 5.14; in 5.12 parts of it
are in core), or the method (TIEHASH in this case) cannot be found, even
by autoloading, then the module is loaded.

That means the problem still persists in 5.14. You just have to mention
the package (e.g., ‘Tie​::Hash​::NamedCapture​::Googoo() if 0’) and the
presence of a universal autoload sub will stop (compilation of) %- and
%+ from loading the module.

S_require_tie_mod probably should not be autoloading.

Errno and arybase have the same problem​:

$ ./perl -Ilib -le 'arybase​::Googoo() if 0; { package UNIVERSAL; sub
AUTOLOAD { warn "$AUTOLOAD(@​_)" } } $[ = 1; print qw(a b c)[2]'
IO​::File​::DESTROY(IO​::File=IO(0x823220)) at -e line 1.
c

(should print b)

$ ./perl -Ilib -le 'Errno​::onrrE() if 0; { package UNIVERSAL; sub
AUTOLOAD { warn "$AUTOLOAD(@​_)" } } $!=20; print $!{ENOTDIR}'
IO​::File​::DESTROY(IO​::File=IO(0x823220)) at -e line 1.

(should print 20, on Unix at least)

Now fixed with commit 0ea0399. I hope my responses have given you
enough information to pick the workaround of your choice.

Now, back to tending the COWs....

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Dec 1, 2011

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

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

No branches or pull requests

1 participant