Fix potential SEGVs for OP_AELEMFAST on a lexical.
Nicholas Clark [Sat, 23 Apr 2011 20:07:10 +0000 (21:07 +0100)]
OP_AELEMFAST is wonderfully special, in that it can be used to replace both
OP_GV and OP_PADAV. The latter is only a baseop, whereas OP_AELEMFAST is a
flagged as a padop/svop. baseops are smaller, and (therefore) don't have memory
allocated where op_sv "should" be.

CHANGES
Size.xs
t/code.t

diff --git a/CHANGES b/CHANGES
index c9eae16..f07437e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,8 @@
 Revision history for Perl extension Devel::Size.
 
+0.74_52 2011-04-23 nicholas
+ * Fix potential SEGVs for OP_AELEMFAST on a lexical (eg $foo[3])
+
 0.74_51 2011-04-22 nicholas
  * Don't count PL_sv_{undef,no,yes} in the size returned
  * total_size() was double-counting entries in typeglobs
diff --git a/Size.xs b/Size.xs
index 654ff39..2a210e3 100644 (file)
--- a/Size.xs
+++ b/Size.xs
@@ -408,7 +408,11 @@ op_size(pTHX_ const OP * const baseop, struct state *st)
            TAG;break;
        case OPc_SVOP: TAG;
            st->total_size += sizeof(struct pmop);
-           sv_size(aTHX_ st, cSVOPx(baseop)->op_sv, TRUE);
+           if (!(baseop->op_type == OP_AELEMFAST
+                 && baseop->op_flags & OPf_SPECIAL)) {
+               /* not an OP_PADAV replacement */
+               sv_size(aTHX_ st, cSVOPx(baseop)->op_sv, TRUE);
+           }
            TAG;break;
       case OPc_PADOP: TAG;
          st->total_size += sizeof(struct padop);
index 65aca0e..ab5d514 100644 (file)
--- a/t/code.t
+++ b/t/code.t
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -w
 
 use strict;
-use Test::More tests => 8;
+use Test::More tests => 10;
 use Devel::Size ':all';
 
 sub zwapp;
@@ -29,3 +29,14 @@ cmp_ok($anon_size, '>', 0, 'anonymous subroutines have a size');
 cmp_ok(length prototype $anon_proto, '>', 0, 'prototype has a length');
 cmp_ok($anon_proto_size, '>', $anon_size + length prototype $anon_proto,
        'prototypes add to the size');
+
+{
+    use vars '@b';
+    my $aelemfast_lex = total_size(sub {my @a; $a[0]});
+    my $aelemfast = total_size(sub {my @a; $b[0]});
+
+    cmp_ok($aelemfast_lex, '>', $anon_size,
+          'aelemfast for a lexical is handled correctly');
+    cmp_ok($aelemfast, '>', $aelemfast_lex,
+          'aelemfast for a package variable is larger');
+}