This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Handle non-PV $_ in @INC filters
authorFather Chrysostomos <sprout@cpan.org>
Thu, 8 Aug 2013 19:49:57 +0000 (12:49 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 11 Aug 2013 14:50:22 +0000 (07:50 -0700)
@INC filters (code refs returned by code refs in @INC) are given the
current line of code in $_ and can modify it.  The C code that invokes
the Perl filter is in pp_ctl.c:S_run_user_filter.  It was not taking
into account that $_ might not have a PV pointer when it is returned,
and so this could result in crashes or assertion failures.

This commit forces the scalar to be a string before returning it to
the lexer, unless it is undef.  If we force it to be a string when it
is undef, then existing tests start producing uninitialized warnings.

The logic is still faulty in places.  Subsequent commits will
address that.

pp_ctl.c
t/op/incfilter.t

index 85149fe..aa11d58 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -5506,6 +5506,7 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
         (SvOK(upstream) || SvGMAGICAL(upstream))) {
        sv_catsv(buf_sv, upstream);
     }
+    else if (SvOK(upstream)) (void)SvPV_force_nolen(buf_sv);
 
     if (status <= 0) {
        IoLINES(datasv) = 0;
index e07526c..8a3fd63 100644 (file)
@@ -13,7 +13,7 @@ use strict;
 use Config;
 use Filter::Util::Call;
 
-plan(tests => 148);
+plan(tests => 150);
 
 unshift @INC, sub {
     no warnings 'uninitialized';
@@ -237,6 +237,14 @@ do [\'pa', \&generator_with_state,
 do \&generator or die;
 is $origlines[0], "1\n+\n2\n", 'ink filters do not mangle cow buffers';
 
+@lines = ('$::the_array = "', [], '"');
+do \&generator or die;
+like ${$::{the_array}}, qr/^ARRAY\(0x.*\)\z/,
+   'setting $_ to ref in inc filter';
+@lines = ('$::the_array = "', *foo, '"');
+do \&generator or die;
+is ${$::{the_array}}, "*main::foo", 'setting $_ to glob in inc filter';
+
 # d8723a6a74b2c12e wasn't perfect, as the char * returned by SvPV*() can be
 # a temporary, freed at the next FREETMPS. And there is a FREETMPS in
 # pp_require