Teach mro code about null array elements
authorFather Chrysostomos <sprout@cpan.org>
Sun, 1 Sep 2013 21:47:38 +0000 (14:47 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 1 Sep 2013 21:47:38 +0000 (14:47 -0700)
This is part of ticket #119433.

Commit ce0d49f changed AVs to use NULL for nonexistent elements.  The
mro lookup code was not accounting for that, causing Class::Contract’s
tests to crash (and perhaps other modules, too).

ext/mro/mro.xs
mro.c
t/mro/basic.t
t/mro/isa_c3.t

index 78fa8df..81539b0 100644 (file)
@@ -80,8 +80,9 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
         SSize_t items = AvFILLp(isa) + 1;
         SV** isa_ptr = AvARRAY(isa);
         while(items--) {
-            SV* const isa_item = *isa_ptr++;
+            SV* const isa_item = *isa_ptr ? *isa_ptr : &PL_sv_undef;
             HV* const isa_item_stash = gv_stashsv(isa_item, 0);
+            isa_ptr++;
             if(!isa_item_stash) {
                 /* if no stash, make a temporary fake MRO
                    containing just itself */
diff --git a/mro.c b/mro.c
index 2ce9fa2..18dfa8c 100644 (file)
--- a/mro.c
+++ b/mro.c
@@ -269,10 +269,11 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level)
 
         /* foreach(@ISA) */
         while (items--) {
-            SV* const sv = *svp++;
+            SV* const sv = *svp ? *svp : &PL_sv_undef;
             HV* const basestash = gv_stashsv(sv, 0);
            SV *const *subrv_p;
            I32 subrv_items;
+           svp++;
 
             if (!basestash) {
                 /* if no stash exists for this @ISA member,
index 6509073..5625b51 100644 (file)
@@ -8,7 +8,7 @@ BEGIN {
     @INC = '../lib';
     require q(./test.pl);
 }
-plan(tests => 60);
+plan(tests => 61);
 
 require mro;
 
@@ -389,3 +389,9 @@ undef $x; # should use the new DESTROY
 is $destroy_output, "new",
     'Changes to UNIVERSAL::DESTROY invalidate DESTROY caches';
 undef *UNIVERSAL::DESTROY;
+
+{
+    no warnings 'uninitialized';
+    $#_119433::ISA++;
+    pass "no crash when ISA contains nonexistent elements";
+}
index dd129cf..20ae5f0 100644 (file)
@@ -67,3 +67,10 @@ foreach my $package (qw(klonk urkkk kapow kayo thwacke zzzzzwap whamm)) {
        object_ok($ref, $class, $package);
     }
 }
+
+package _119433 {
+    use mro 'c3';
+    no warnings 'uninitialized';
+    $#_119433::ISA++;
+    ::pass "no crash when ISA contains nonexistent elements";
+}