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

Clearing @ISA via it's typeglob breaks in 5.10.1 and 5.11.4 #10179

Closed
p5pRT opened this issue Feb 16, 2010 · 12 comments
Closed

Clearing @ISA via it's typeglob breaks in 5.10.1 and 5.11.4 #10179

p5pRT opened this issue Feb 16, 2010 · 12 comments

Comments

@p5pRT
Copy link

p5pRT commented Feb 16, 2010

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

Searchable as RT72866$

@p5pRT
Copy link
Author

p5pRT commented Feb 16, 2010

From Bernhard.Schmalhofer@gmx.de

Created by bernhard@heist.nonet

A bug on 5.10.1 surfaced with the webapplication OTRS in a mod_perl
environment.
After Apache2​::Reload kicked in, inheritance was broken, methods from
parent modules were no longer found. The bug was triggered by code in
ModPerl​::Util​::unload_package_pp().

I have boiled it down to a simple test script. Assigning a empty array ref
to a typeglob of @​ISA seems to mess up @​ISA or the method caching.

Here is a test script that works under 5.10.0 and fails under 5.10.1.

use strict;
use warnings;

use Data​::Dumper;
use Test​::More tests => 2;

#use MRO​::Compat;
#mro​::invalidate_all_method_caches();

push @​Bla​::ISA, 'Blubber';

diag( 'initial' );
{
  no strict 'refs';
  diag( Data​::Dumper->Dump( [ \%{ 'Bla​::' }, \@​Bla​::ISA ], [
qw(Symbols ISA) ] ) );
}
diag( Bla->hi_from_blubber() );
can_ok( 'Bla', 'hi_from_blubber' );

# broken in 5.10.1, as used in ModPerl​::Util​::unload_package_pp()
*{$fullname} = [];
*{Bla​::ISA} = [];

# works in 5.10.1
#my $ref_to_isa = \@​Bla​::ISA;
#$ref_to_isa = [];

# works in 5.10.1
#@​Bla​::ISA = ();

push @​Bla​::ISA, 'Blubber';

diag( 'after reloading' );
{
  no strict 'refs';
  diag( Data​::Dumper->Dump( [ \%{ 'Bla​::' }, \@​Bla​::ISA ], [
qw(Symbols ISA) ] ) );
}
can_ok( 'Bla', 'hi_from_blubber' );

package Blubber;

sub hi_from_blubber {
  return "Hi from Blubber\n";
}

Perl Info

Flags:
    category=core
    severity=medium

Site configuration information for perl 5.10.1:

Configured by bernhard at Sat Feb 13 12:32:45 CET 2010.

Summary of my perl5 (revision 5 version 10 subversion 1) configuration:
   
  Platform:
    osname=linux, osvers=2.6.31-19-generic, archname=i686-linux
    uname='linux heist 2.6.31-19-generic #56-ubuntu smp thu jan 28 
01:26:53 utc 2010 i686 gnulinux '
    config_args='-des -Dprefix=/home/bernhard/devel/Perl/5.10.1'
    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.1', 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 /usr/lib64
    libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
    libc=/lib/libc-2.10.1.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.10.1'
  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.10.1:
    /home/bernhard/devel/Perl/5.10.1/lib/perl5/5.10.1/i686-linux
    /home/bernhard/devel/Perl/5.10.1/lib/perl5/5.10.1
    /home/bernhard/devel/Perl/5.10.1/lib/perl5/site_perl/5.10.1/i686-linux
    /home/bernhard/devel/Perl/5.10.1/lib/perl5/site_perl/5.10.1
    .


Environment for perl 5.10.1:
    HOME=/home/bernhard
    LANG=de_DE.UTF-8
    LANGUAGE=
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    
PATH=/home/bernhard/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
    PERL_BADLANG (unset)
    SHELL=/bin/bash


 

@p5pRT
Copy link
Author

p5pRT commented Feb 16, 2010

From Bernhard.Schmalhofer@gmx.de

Because of c&p error the script in the initial message does not compile.
I have attached a working version.

--
/* Bernhard.Schmalhofer@​gmx.de */

@p5pRT
Copy link
Author

p5pRT commented Feb 16, 2010

From Bernhard.Schmalhofer@gmx.de

use strict;
use warnings;

use Data​::Dumper;
use Test​::More tests => 2;

#use MRO​::Compat;
#mro​::invalidate_all_method_caches();

push @​Bla​::ISA, 'Blubber';

diag( 'initial' );
{
  no strict 'refs';
  diag( Data​::Dumper->Dump( [ \%{ 'Bla​::' }, \@​Bla​::ISA ], [ qw(Symbols ISA) ] ) );
}
diag( Bla->hi_from_blubber() );
can_ok( 'Bla', 'hi_from_blubber' );

# broken in 5.10.1, as used in ModPerl​::Util​::unload_package_pp() *{$fullname} = [];
*{Bla​::ISA} = [];

# works in 5.10.1
#my $ref_to_isa = \@​Bla​::ISA;
#$ref_to_isa = [];

# works in 5.10.1
#@​Bla​::ISA = ();

push @​Bla​::ISA, 'Blubber';

diag( 'after reloading' );
{
  no strict 'refs';
  diag( Data​::Dumper->Dump( [ \%{ 'Bla​::' }, \@​Bla​::ISA ], [ qw(Symbols ISA) ] ) );
}
can_ok( 'Bla', 'hi_from_blubber' );

package Blubber;

sub hi_from_blubber {
  return "Hi from Blubber\n";
}

@p5pRT
Copy link
Author

p5pRT commented Feb 16, 2010

Bernhard.Schmalhofer@gmx.de - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Feb 16, 2010

From Bernhard.Schmalhofer@gmx.de

On Di. 16. Feb. 2010, 02​:54​:37, bernhard wrote​:

Michiel Beijen tested on 5.11.4.
It shows the same behavior as in 5.10.1.

--
/* Bernhard.Schmalhofer@​gmx.de */

@p5pRT
Copy link
Author

p5pRT commented Feb 17, 2010

From @tonycoz

On Tue, Feb 16, 2010 at 12​:59​:22AM -0800, Bernhard Schmalhofer wrote​:

-----------------------------------------------------------------
[Please describe your issue here]

A bug on 5.10.1 surfaced with the webapplication OTRS in a mod_perl
environment.
After Apache2​::Reload kicked in, inheritance was broken, methods from
parent modules were no longer found. The bug was triggered by code in
ModPerl​::Util​::unload_package_pp().

I have boiled it down to a simple test script. Assigning a empty array ref
to a typeglob of @​ISA seems to mess up @​ISA or the method caching.

Here is a test script that works under 5.10.0 and fails under 5.10.1.

A simpler script​:

use Test​::More tests => 3;

{
  # assigning @​ISA via arrayref then modifying it RT 72866
  {
  package R1;
  sub bar { }
  package R2;
  sub foo { }
  package R3;
  }
  @​R3​::ISA = qw(R1);
  can_ok("R3", "bar");
  *R3​::ISA = [];
  push @​R3​::ISA, "R2";
  can_ok("R3", "foo");
  ok(!R3->can("bar"), "can't call bar method anymore");
}

Commit 26d68d8 added a check for assigning an arrayref to an *ISA
glob to fix rt #60220, but didn't add magic to the new @​ISA arrayref,
so while the isa cache for the derived class is updated on the
arrayref assignment, any further modifications don't cause any
updates.

Attached patch adds the magic, but I'm not sure it's correct,
hopefully someone with a better understanding of magic can review it.

Tony

@p5pRT
Copy link
Author

p5pRT commented Feb 17, 2010

From @tonycoz

0001-rt-72866-add-magic-to-arrayrefs-assigned-to-Foo.patch
From fe74387abd9163ee49fc1976a490ffe05e14c965 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Wed, 17 Feb 2010 23:31:28 +1100
Subject: [PATCH] rt #72866 - add magic to arrayrefs assigned to *Foo::ISA

The fix for rt #60220 (26d68d86) updated the isa cache when an
arrayref was assigned to some *ISA, but didn't add the magic to the
new @ISA to catch any further updates to it.  Add the magic, and
tests.
---
 sv.c          |    5 ++++-
 t/mro/basic.t |   24 +++++++++++++++++++++++-
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/sv.c b/sv.c
index 40c95d5..c898727 100644
--- a/sv.c
+++ b/sv.c
@@ -3786,7 +3786,10 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
     SvREFCNT_dec(dref);
     if (SvTAINTED(sstr))
 	SvTAINT(dstr);
-    if (mro_changes) mro_isa_changed_in(GvSTASH(dstr));
+    if (mro_changes) {
+	sv_magic(*location, dstr, PERL_MAGIC_isa, NULL, 0);
+	mro_isa_changed_in(GvSTASH(dstr));
+    }
     return;
 }
 
diff --git a/t/mro/basic.t b/t/mro/basic.t
index a4d3015..843d052 100644
--- a/t/mro/basic.t
+++ b/t/mro/basic.t
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-require q(./test.pl); plan(tests => 44);
+require q(./test.pl); plan(tests => 48);
 
 require mro;
 
@@ -250,6 +250,28 @@ is(eval { MRO_N->testfunc() }, 123);
 }
 
 {
+  # assigning @ISA via arrayref then modifying it RT 72866
+  {
+    package Q1;
+    sub foo {  }
+
+    package Q2;
+    sub bar { }
+
+    package Q3;
+  }
+  @Q3::ISA = qw(Q1);
+  can_ok("Q3", "foo");
+  *Q3::ISA = [];
+  push @Q3::ISA, "Q1";
+  can_ok("Q3", "foo");
+  *Q3::ISA = [];
+  push @Q3::ISA, "Q2";
+  can_ok("Q3", "bar");
+  ok(!Q3->can("foo"), "can't call foo method any longer");
+}
+
+{
     # test mro::method_changed_in
     my $count = mro::get_pkg_gen("MRO_A");
     mro::method_changed_in("MRO_A");
-- 
1.5.6.5

@p5pRT
Copy link
Author

p5pRT commented Feb 17, 2010

From @tonycoz

On Wed, Feb 17, 2010 at 11​:42​:12PM +1100, Tony Cook wrote​:

diff --git a/sv.c b/sv.c
index 40c95d5..c898727 100644
--- a/sv.c
+++ b/sv.c
@​@​ -3786,7 +3786,10 @​@​ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
SvREFCNT_dec(dref);
if (SvTAINTED(sstr))
SvTAINT(dstr);
- if (mro_changes) mro_isa_changed_in(GvSTASH(dstr));
+ if (mro_changes) {
+ sv_magic(*location, dstr, PERL_MAGIC_isa, NULL, 0);
+ mro_isa_changed_in(GvSTASH(dstr));
+ }
return;
}

Actually, I don't like this patch, or rather the action at a distance
introduced in my older patch.

I'll make another one tonight.

Tony

@p5pRT
Copy link
Author

p5pRT commented Feb 18, 2010

From @tonycoz

On Thu, Feb 18, 2010 at 10​:07​:30AM +1100, Tony Cook wrote​:

Actually, I don't like this patch, or rather the action at a distance
introduced in my older patch.

I'll make another one tonight.

The attached removes the action at a distance and adds the isa magic
to the new @​ISA.

@p5pRT
Copy link
Author

p5pRT commented Feb 18, 2010

From @tonycoz

0001-rt-72866-add-magic-to-arrayrefs-assigned-to-Foo.patch
From 142b577e212a00f52d31e528a3319131c94b59e9 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Thu, 18 Feb 2010 20:59:33 +1100
Subject: [PATCH] rt #72866 - add magic to arrayrefs assigned to *Foo::ISA

The fix for rt #60220 (26d68d86) updated the isa cache when an
arrayref was assigned to some *ISA, but didn't add the magic to the
new @ISA to catch any further updates to it.  Add the magic, and
tests.
---
 sv.c          |    8 ++++----
 t/mro/basic.t |   24 +++++++++++++++++++++++-
 2 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/sv.c b/sv.c
index 40c95d5..7db4281 100644
--- a/sv.c
+++ b/sv.c
@@ -3685,7 +3685,6 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
     SV **location;
     U8 import_flag = 0;
     const U32 stype = SvTYPE(sref);
-    bool mro_changes = FALSE;
 
     PERL_ARGS_ASSERT_GLOB_ASSIGN_REF;
 
@@ -3706,8 +3705,6 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
 	goto common;
     case SVt_PVAV:
 	location = (SV **) &GvAV(dstr);
-        if (strEQ(GvNAME((GV*)dstr), "ISA"))
-	    mro_changes = TRUE;
 	import_flag = GVf_IMPORTED_AV;
 	goto common;
     case SVt_PVIO:
@@ -3781,12 +3778,15 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
 	    && CopSTASH_ne(PL_curcop, GvSTASH(dstr))) {
 	    GvFLAGS(dstr) |= import_flag;
 	}
+	if (stype == SVt_PVAV && strEQ(GvNAME((GV*)dstr), "ISA")) {
+	    sv_magic(sref, dstr, PERL_MAGIC_isa, NULL, 0);
+	    mro_isa_changed_in(GvSTASH(dstr));
+	}
 	break;
     }
     SvREFCNT_dec(dref);
     if (SvTAINTED(sstr))
 	SvTAINT(dstr);
-    if (mro_changes) mro_isa_changed_in(GvSTASH(dstr));
     return;
 }
 
diff --git a/t/mro/basic.t b/t/mro/basic.t
index a4d3015..fbd3a6d 100644
--- a/t/mro/basic.t
+++ b/t/mro/basic.t
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-require q(./test.pl); plan(tests => 44);
+require q(./test.pl); plan(tests => 48);
 
 require mro;
 
@@ -250,6 +250,28 @@ is(eval { MRO_N->testfunc() }, 123);
 }
 
 {
+  # assigning @ISA via arrayref then modifying it RT 72866
+  {
+    package Q1;
+    sub foo {  }
+
+    package Q2;
+    sub bar { }
+
+    package Q3;
+  }
+  push @Q3::ISA, "Q1";
+  can_ok("Q3", "foo");
+  *Q3::ISA = [];
+  push @Q3::ISA, "Q1";
+  can_ok("Q3", "foo");
+  *Q3::ISA = [];
+  push @Q3::ISA, "Q2";
+  can_ok("Q3", "bar");
+  ok(!Q3->can("foo"), "can't call foo method any longer");
+}
+
+{
     # test mro::method_changed_in
     my $count = mro::get_pkg_gen("MRO_A");
     mro::method_changed_in("MRO_A");
-- 
1.5.6.5

@p5pRT
Copy link
Author

p5pRT commented Feb 18, 2010

From @obra

On Thu Feb 18 02​:04​:53 2010, tonyc wrote​:

On Thu, Feb 18, 2010 at 10​:07​:30AM +1100, Tony Cook wrote​:

Actually, I don't like this patch, or rather the action at a distance
introduced in my older patch.

I'll make another one tonight.

The attached removes the action at a distance and adds the isa magic
to the new @​ISA.

Thanks. Applied. Resolving.

@p5pRT p5pRT closed this as completed Feb 18, 2010
@p5pRT
Copy link
Author

p5pRT commented Feb 18, 2010

@obra - 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