rt #72866 - add magic to arrayrefs assigned to *Foo::ISA
Tony Cook [Thu, 18 Feb 2010 09:59:33 +0000 (20:59 +1100)]
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
t/mro/basic.t

diff --git a/sv.c b/sv.c
index 53e3410..2f429cc 100644 (file)
--- 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;
 }
 
index a4d3015..fbd3a6d 100644 (file)
@@ -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");