Make PL_argvgv refcounted
authorFather Chrysostomos <sprout@cpan.org>
Sun, 27 Oct 2013 21:37:10 +0000 (14:37 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Mon, 28 Oct 2013 23:15:09 +0000 (16:15 -0700)
Otherwise one can free it and cause assertion failures when other
things do SvREFCNT_inc on a freed scalar:

$ ./miniperl -le 'undef *x; delete $::{ARGV}; $x++; eval "BEGIN{undef *x} readline"'
Assertion failed: (SvTYPE(sv) != (svtype)SVTYPEMASK), function Perl_sv_clear, file sv.c, line 6215.
Abort trap: 6

perl.c
sv.c
t/io/argv.t

diff --git a/perl.c b/perl.c
index 1361f58..011b0a2 100644 (file)
--- a/perl.c
+++ b/perl.c
@@ -952,7 +952,6 @@ perl_destruct(pTHXx)
     PL_incgv = NULL;
     PL_hintgv = NULL;
     PL_errgv = NULL;
-    PL_argvgv = NULL;
     PL_argvoutgv = NULL;
     PL_stdingv = NULL;
     PL_stderrgv = NULL;
@@ -966,10 +965,12 @@ perl_destruct(pTHXx)
     PL_debstash = NULL;
 
     SvREFCNT_dec(PL_envgv);
+    SvREFCNT_dec(PL_argvgv);
     SvREFCNT_dec(PL_DBgv);
     SvREFCNT_dec(PL_DBline);
     SvREFCNT_dec(PL_DBsub);
     PL_envgv = NULL;
+    PL_argvgv = NULL;
     PL_DBgv = NULL;
     PL_DBline = NULL;
     PL_DBsub = NULL;
@@ -4261,6 +4262,7 @@ Perl_init_argv_symbols(pTHX_ int argc, char **argv)
        }
     }
     if ((PL_argvgv = gv_fetchpvs("ARGV", GV_ADD|GV_NOTQUAL, SVt_PVAV))) {
+       SvREFCNT_inc_simple_void_NN(PL_argvgv);
        GvMULTI_on(PL_argvgv);
        av_clear(GvAVn(PL_argvgv));
        for (; argc > 0; argc--,argv++) {
diff --git a/sv.c b/sv.c
index f649ad9..f17508b 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -13609,7 +13609,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_stdingv         = gv_dup(proto_perl->Istdingv, param);
     PL_stderrgv                = gv_dup(proto_perl->Istderrgv, param);
     PL_defgv           = gv_dup(proto_perl->Idefgv, param);
-    PL_argvgv          = gv_dup(proto_perl->Iargvgv, param);
+    PL_argvgv          = gv_dup_inc(proto_perl->Iargvgv, param);
     PL_argvoutgv       = gv_dup(proto_perl->Iargvoutgv, param);
     PL_argvout_stack   = av_dup_inc(proto_perl->Iargvout_stack, param);
 
index 95e962d..a1febaf 100644 (file)
@@ -7,7 +7,7 @@ BEGIN {
 
 BEGIN { require "./test.pl"; }
 
-plan(tests => 23);
+plan(tests => 24);
 
 my ($devnull, $no_devnull);
 
@@ -147,6 +147,16 @@ close IN;
 unlink "Io_argv3.tmp";
 **PROG**
 
+# This used to fail an assertion.
+# The tricks with *x and $x are to make PL_argvgv point to a freed SV when
+# the readline op does SvREFCNT_inc on it.  undef *x clears the scalar slot
+# ++$x vivifies it, reusing the just-deleted GV that PL_argvgv still points
+# to.  The BEGIN block ensures it is freed late enough that nothing else
+# has reused it yet.
+is runperl(prog => 'undef *x; delete $::{ARGV}; $x++;'
+                  .'eval q-BEGIN{undef *x} readline-; print qq-ok\n-'),
+  "ok\n", 'deleting $::{ARGV}';
+
 END {
     unlink_all 'Io_argv1.tmp', 'Io_argv1.tmp_bak',
        'Io_argv2.tmp', 'Io_argv2.tmp_bak', 'Io_argv3.tmp';