diff options
author | Father Chrysostomos <sprout@cpan.org> | 2018-02-13 13:36:22 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2018-02-18 16:25:42 -0800 |
commit | 7406cffe8ec122fcc2500115f8ed1742385893e1 (patch) | |
tree | 85cd52b856bf70d6a188cf3d1c166c38f15b5138 | |
parent | c46431c409d5cdb3c1c17c039a19e0e03356c7a6 (diff) | |
download | perl-7406cffe8ec122fcc2500115f8ed1742385893e1.tar.gz |
Fix two bugs when calling &xsub when @_ has holes
This fixes #132729 in the particular instance where an XSUB is
called via ampersand syntax when @_ has ‘holes’, or nonexistent ele-
ments, as in:
@_ = ();
$_[1] = 1;
&xsub;
This means that if the XSUB or something it calls unshifts @_, the
first argument passed to the XSUB will now refer to $_[1], not $_[0];
i.e., as of this commit it is correctly shifted over. Previously, a
‘defelem’ was used, which is a magical scalar that remembers its index
in the array, independent of whether the array was shifted.
In addition, the old code failed to mortalize the defelem, so this
commit fixes a memory leak with the new ‘non-elem’ mechanism (a spe-
cially-marked element stored in the array itself).
-rw-r--r-- | ext/XS-APItest/APItest.xs | 7 | ||||
-rw-r--r-- | pp_hot.c | 2 | ||||
-rw-r--r-- | t/op/sub.t | 12 | ||||
-rw-r--r-- | t/op/svleak.t | 6 |
4 files changed, 24 insertions, 3 deletions
diff --git a/ext/XS-APItest/APItest.xs b/ext/XS-APItest/APItest.xs index 4e5bf3cf1a..1fead70ee9 100644 --- a/ext/XS-APItest/APItest.xs +++ b/ext/XS-APItest/APItest.xs @@ -4398,6 +4398,13 @@ get_cv_flags(SV *sv, UV flags) OUTPUT: RETVAL +void +unshift_and_set_defav(SV *sv,...) + CODE: + av_unshift(GvAVn(PL_defgv), 1); + av_store(GvAV(PL_defgv), 0, newSVuv(42)); + sv_setuv(sv, 43); + PerlIO * PerlIO_stderr() @@ -5215,7 +5215,7 @@ PP(pp_entersub) else sv = AvARRAY(av)[i]; if (sv) SP[i+1] = sv; else { - SP[i+1] = newSVavdefelem(av, i, 1); + SP[i+1] = av_nonelem(av, i); } } SP += items; diff --git a/t/op/sub.t b/t/op/sub.t index c8bf72d680..2b8ebcc463 100644 --- a/t/op/sub.t +++ b/t/op/sub.t @@ -6,7 +6,7 @@ BEGIN { set_up_inc('../lib'); } -plan(tests => 61); +plan(tests => 62); sub empty_sub {} @@ -403,6 +403,16 @@ is ref($main::{rt_129916}), 'CODE', 'simple sub stored as CV in stash (main::)'; is ref($RT129916::{foo}), 'CODE', 'simple sub stored as CV in stash (non-main::)'; } +# Calling xsub via ampersand syntax when @_ has holes +SKIP: { + skip "no XS::APItest on miniperl" if is_miniperl; + require XS::APItest; + local *_; + $_[1] = 1; + &XS::APItest::unshift_and_set_defav; + is "@_", "42 43 1" +} + # [perl #129090] Crashes and hangs watchdog 10; { no warnings; diff --git a/t/op/svleak.t b/t/op/svleak.t index 59bd7d9d7f..05ae01f792 100644 --- a/t/op/svleak.t +++ b/t/op/svleak.t @@ -15,7 +15,7 @@ BEGIN { use Config; -plan tests => 147; +plan tests => 148; # run some code N times. If the number of SVs at the end of loop N is # greater than (N-1)*delta at the end of loop 1, we've got a leak @@ -326,6 +326,10 @@ leak(2, 0, sub { bless \&recredef, "Recursive::Redefinition"; eval "sub recredef{}" }, 'recursive sub redefinition'); +# Sub calls +leak(2, 0, sub { local *_; $_[1]=1; &re::regname }, + 'passing sparse array to xsub via ampersand call'); + # Syntax errors eleak(2, 0, '"${<<END}" ', 'unterminated here-doc in quotes in multiline eval'); |