In perl.git, the branch blead has been updated <https://perl5.git.perl.org/perl.git/commitdiff/2a05854a1ad5472d00de22f8fcc284cdc8fd1503?hp=6de18f4499a45f0d6876f2aca180b8a9f06e9240>
- Log ----------------------------------------------------------------- commit 2a05854a1ad5472d00de22f8fcc284cdc8fd1503 Merge: 6de18f4499 957ac2541b Author: Father Chrysostomos <spr...@cpan.org> Date: Sun Feb 18 16:41:09 2018 -0800 [Merge] ‘Nonelem’ scalars commit 957ac2541beb14cbb7de197c83c0f7132c06a9ed Author: Father Chrysostomos <spr...@cpan.org> Date: Sun Feb 18 16:41:02 2018 -0800 perldelta for non-elems I don’t think the bug involving defelems, which this branch partially fixes is significant enough to be mentioned in the bugs section. Likewise, the memory leaks fixed (some of them introduced in the same dev cycle) are so rare that it would add unnecessary verbiage to perldelta. commit 9ef753fe465d865deeba96157242bc98c0afe412 Author: Father Chrysostomos <spr...@cpan.org> Date: Sun Feb 18 16:12:11 2018 -0800 Fix ary shifting when sparse ary is passed to sub This commit fixes #132729 in the specific case where a nonexistent element within a sparse array is passed to a subroutine. Prior to this commit, some_sub($sparse_array[$n]) where $n <= $#sparse_array and the element does not exist, would exhi- bit erroneous behaviour if some_sub shifted or unshifted the original @sparse_array. Any ‘holes’ (nonexistent elements) in the array would show up in @_ as deferred element (defelem) scalars, magic scalars that remember their index in the array. This index is not updated and gets out of synch when the array is shifted. This commit fixes the bug for elements within the array by using the new ‘nonelem’ magic introduced a few commits ago. It stores within the array a magic scalar that is marked as being nonexistent. It also reduced the number of scalars that need to be created if such a sub call happens repeatedly. commit 7406cffe8ec122fcc2500115f8ed1742385893e1 Author: Father Chrysostomos <spr...@cpan.org> Date: Tue Feb 13 13:36:22 2018 -0800 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). commit c46431c409d5cdb3c1c17c039a19e0e03356c7a6 Author: Father Chrysostomos <spr...@cpan.org> Date: Sun Feb 11 17:14:20 2018 -0800 Test #132729 with array flattening Other instances of this bug have not yet been fixed. This commit’s grandparent fixed the case where an array with holes in it is flat- tened in lvalue context, and then gets shifted/unshifted before an element is vivified. commit eb2991224f3c7972426fe6ab6b3fe5c08699e502 Author: Father Chrysostomos <spr...@cpan.org> Date: Sun Feb 11 17:01:26 2018 -0800 svleak.t: Test for leak fixed by prev. commit commit 1f1dcfb516e063c29a4b9823ad97b1fc58ffc930 Author: Father Chrysostomos <spr...@cpan.org> Date: Sun Jan 21 21:55:00 2018 -0800 ‘Nonelems’ for pushing sparse array on the stack To avoid having to create deferred elements every time a sparse array is pushed on to the stack, store a magic scalar in the array itself, which av_exists and refto recognise as not existing. This means there is only a one-time cost for putting such arrays on the stack. It also means that deferred elements that live long enough don’t start pointing to the wrong array entry if the array gets shifted (or unshifted/spliced) in the mean time. Instead, the scalar is already in the array, so it cannot lose its place. This fix only applies when the array as a whole is pushed on to the stack, but it could be extended in future commits to apply to other places where we currently use deferred elements. ----------------------------------------------------------------------- Summary of changes: av.c | 13 +++++++++++++ embed.fnc | 2 ++ embed.h | 2 ++ ext/XS-APItest/APItest.xs | 7 +++++++ mg.c | 9 +++++++++ mg_names.inc | 1 + mg_raw.h | 2 ++ mg_vtable.h | 5 +++++ pod/perldelta.pod | 13 +++++++++++++ pod/perlguts.pod | 2 ++ pp.c | 2 ++ pp_hot.c | 44 +++++++++++++++++++++++++++---------------- proto.h | 6 ++++++ regen/mg_vtable.pl | 3 +++ t/op/array.t | 48 ++++++++++++++++++++++++++++++++++++++++++++++- t/op/sub.t | 12 +++++++++++- t/op/svleak.t | 14 +++++++++++++- 17 files changed, 166 insertions(+), 19 deletions(-) diff --git a/av.c b/av.c index ba97fed31c..f6ffea627b 100644 --- a/av.c +++ b/av.c @@ -1015,6 +1015,9 @@ Perl_av_exists(pTHX_ AV *av, SSize_t key) if (key <= AvFILLp(av) && AvARRAY(av)[key]) { + if (SvSMAGICAL(AvARRAY(av)[key]) + && mg_find(AvARRAY(av)[key], PERL_MAGIC_nonelem)) + return FALSE; return TRUE; } else @@ -1070,6 +1073,16 @@ Perl_av_iter_p(pTHX_ AV *av) { } } +SV * +Perl_av_nonelem(pTHX_ AV *av, SSize_t ix) { + SV * const sv = newSV(0); + PERL_ARGS_ASSERT_AV_NONELEM; + if (!av_store(av,ix,sv)) + return sv_2mortal(sv); /* has tie magic */ + sv_magic(sv, NULL, PERL_MAGIC_nonelem, NULL, 0); + return sv; +} + /* * ex: set ts=8 sts=4 sw=4 et: */ diff --git a/embed.fnc b/embed.fnc index e748639e1a..3c66fa426b 100644 --- a/embed.fnc +++ b/embed.fnc @@ -282,6 +282,7 @@ ApdR |SV** |av_fetch |NN AV *av|SSize_t key|I32 lval Apd |void |av_fill |NN AV *av|SSize_t fill ApdR |SSize_t|av_len |NN AV *av ApdR |AV* |av_make |SSize_t size|NN SV **strp +p |SV* |av_nonelem |NN AV *av|SSize_t ix Apd |SV* |av_pop |NN AV *av ApdoxM |void |av_create_and_push|NN AV **const avp|NN SV *const val Apd |void |av_push |NN AV *av|NN SV *val @@ -1026,6 +1027,7 @@ p |int |magic_freearylen_p|NN SV* sv|NN MAGIC* mg p |int |magic_setdbline|NN SV* sv|NN MAGIC* mg p |int |magic_setdebugvar|NN SV* sv|NN MAGIC* mg p |int |magic_setdefelem|NN SV* sv|NN MAGIC* mg +p |int |magic_setnonelem|NN SV* sv|NN MAGIC* mg p |int |magic_setenv |NN SV* sv|NN MAGIC* mg dp |int |magic_sethint |NN SV* sv|NN MAGIC* mg p |int |magic_setisa |NN SV* sv|NN MAGIC* mg diff --git a/embed.h b/embed.h index b417aaf083..f964e99245 100644 --- a/embed.h +++ b/embed.h @@ -1169,6 +1169,7 @@ #define amagic_is_enabled(a) Perl_amagic_is_enabled(aTHX_ a) #define apply(a,b,c) Perl_apply(aTHX_ a,b,c) #define av_extend_guts(a,b,c,d,e) Perl_av_extend_guts(aTHX_ a,b,c,d,e) +#define av_nonelem(a,b) Perl_av_nonelem(aTHX_ a,b) #define bind_match(a,b,c) Perl_bind_match(aTHX_ a,b,c) #define boot_core_PerlIO() Perl_boot_core_PerlIO(aTHX) #define boot_core_UNIVERSAL() Perl_boot_core_UNIVERSAL(aTHX) @@ -1324,6 +1325,7 @@ #define magic_setlvref(a,b) Perl_magic_setlvref(aTHX_ a,b) #define magic_setmglob(a,b) Perl_magic_setmglob(aTHX_ a,b) #define magic_setnkeys(a,b) Perl_magic_setnkeys(aTHX_ a,b) +#define magic_setnonelem(a,b) Perl_magic_setnonelem(aTHX_ a,b) #define magic_setpack(a,b) Perl_magic_setpack(aTHX_ a,b) #define magic_setpos(a,b) Perl_magic_setpos(aTHX_ a,b) #define magic_setregexp(a,b) Perl_magic_setregexp(aTHX_ a,b) 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() diff --git a/mg.c b/mg.c index c8bb49e27b..331f96639e 100644 --- a/mg.c +++ b/mg.c @@ -2527,6 +2527,15 @@ Perl_vivify_defelem(pTHX_ SV *sv) mg->mg_flags &= ~MGf_REFCOUNTED; } +int +Perl_magic_setnonelem(pTHX_ SV *sv, MAGIC *mg) +{ + PERL_ARGS_ASSERT_MAGIC_SETNONELEM; + PERL_UNUSED_ARG(mg); + sv_unmagic(sv, PERL_MAGIC_nonelem); + return 0; +} + int Perl_magic_killbackrefs(pTHX_ SV *sv, MAGIC *mg) { diff --git a/mg_names.inc b/mg_names.inc index fde6872fa9..7eb9033675 100644 --- a/mg_names.inc +++ b/mg_names.inc @@ -45,6 +45,7 @@ { PERL_MAGIC_vec, "vec(v)" }, { PERL_MAGIC_utf8, "utf8(w)" }, { PERL_MAGIC_substr, "substr(x)" }, + { PERL_MAGIC_nonelem, "nonelem(Y)" }, { PERL_MAGIC_defelem, "defelem(y)" }, { PERL_MAGIC_lvref, "lvref(\\)" }, { PERL_MAGIC_checkcall, "checkcall(])" }, diff --git a/mg_raw.h b/mg_raw.h index b3e25d646b..2f4863b08e 100644 --- a/mg_raw.h +++ b/mg_raw.h @@ -78,6 +78,8 @@ "/* utf8 'w' Cached UTF-8 information */" }, { 'x', "want_vtbl_substr | PERL_MAGIC_VALUE_MAGIC", "/* substr 'x' substr() lvalue */" }, + { 'Y', "want_vtbl_nonelem | PERL_MAGIC_VALUE_MAGIC", + "/* nonelem 'Y' Array element that does not exist */" }, { 'y', "want_vtbl_defelem | PERL_MAGIC_VALUE_MAGIC", "/* defelem 'y' Shadow \"foreach\" iterator variable / smart parameter vivification */" }, { '\\', "want_vtbl_lvref", diff --git a/mg_vtable.h b/mg_vtable.h index c71a988cf7..e4f3f3889d 100644 --- a/mg_vtable.h +++ b/mg_vtable.h @@ -52,6 +52,7 @@ #define PERL_MAGIC_vec 'v' /* vec() lvalue */ #define PERL_MAGIC_utf8 'w' /* Cached UTF-8 information */ #define PERL_MAGIC_substr 'x' /* substr() lvalue */ +#define PERL_MAGIC_nonelem 'Y' /* Array element that does not exist */ #define PERL_MAGIC_defelem 'y' /* Shadow "foreach" iterator variable / smart parameter vivification */ #define PERL_MAGIC_lvref '\\' /* Lvalue reference constructor */ @@ -76,6 +77,7 @@ enum { /* pass one of these to get_vtbl */ want_vtbl_lvref, want_vtbl_mglob, want_vtbl_nkeys, + want_vtbl_nonelem, want_vtbl_ovrld, want_vtbl_pack, want_vtbl_packelem, @@ -112,6 +114,7 @@ EXTCONST char * const PL_magic_vtable_names[magic_vtable_max] = { "lvref", "mglob", "nkeys", + "nonelem", "ovrld", "pack", "packelem", @@ -171,6 +174,7 @@ EXT_MGVTBL PL_magic_vtables[magic_vtable_max] = { { 0, Perl_magic_setlvref, 0, 0, 0, 0, 0, 0 }, { 0, Perl_magic_setmglob, 0, 0, 0, 0, 0, 0 }, { Perl_magic_getnkeys, Perl_magic_setnkeys, 0, 0, 0, 0, 0, 0 }, + { 0, Perl_magic_setnonelem, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, Perl_magic_freeovrld, 0, 0, 0 }, { 0, 0, Perl_magic_sizepack, Perl_magic_wipepack, 0, 0, 0, 0 }, { Perl_magic_getpack, Perl_magic_setpack, 0, Perl_magic_clearpack, 0, 0, 0, 0 }, @@ -216,6 +220,7 @@ EXT_MGVTBL PL_magic_vtables[magic_vtable_max]; #define PL_vtbl_lvref PL_magic_vtables[want_vtbl_lvref] #define PL_vtbl_mglob PL_magic_vtables[want_vtbl_mglob] #define PL_vtbl_nkeys PL_magic_vtables[want_vtbl_nkeys] +#define PL_vtbl_nonelem PL_magic_vtables[want_vtbl_nonelem] #define PL_vtbl_ovrld PL_magic_vtables[want_vtbl_ovrld] #define PL_vtbl_pack PL_magic_vtables[want_vtbl_pack] #define PL_vtbl_packelem PL_magic_vtables[want_vtbl_packelem] diff --git a/pod/perldelta.pod b/pod/perldelta.pod index 00a33b60c2..e640f76c9a 100644 --- a/pod/perldelta.pod +++ b/pod/perldelta.pod @@ -390,6 +390,19 @@ A new API function L<perlapi/Perl_setlocale> has been added. L<perlapi/sync_locale> has been revised to return a boolean as to whether the system was using the global locale or not. +=item * + +A new kind of magic scalar, called a "nonelem" scalar, has been introduced. +It is stored in an array to denote a nonexistent element, whenever such an +element is accessed in a potential lvalue context. It replaces the +existing "defelem" (deferred element) magic wherever this is possible, +being significantly more efficient. This means that +C<some_sub($sparse_array[$nonelem])> no longer has to create a new magic +defelem scalar each time, as long as the element is within the array. + +It partially fixes the rare bug of deferred elements getting out of synch +with their arrays when the array is shifted or unshifted. [perl #132729] + =back =head1 Selected Bug Fixes diff --git a/pod/perlguts.pod b/pod/perlguts.pod index 54a76dac45..5d11da6bfc 100644 --- a/pod/perlguts.pod +++ b/pod/perlguts.pod @@ -1271,6 +1271,8 @@ will be lost. v PERL_MAGIC_vec vtbl_vec vec() lvalue w PERL_MAGIC_utf8 vtbl_utf8 Cached UTF-8 information x PERL_MAGIC_substr vtbl_substr substr() lvalue + Y PERL_MAGIC_nonelem vtbl_nonelem Array element that does not + exist y PERL_MAGIC_defelem vtbl_defelem Shadow "foreach" iterator variable / smart parameter vivification diff --git a/pp.c b/pp.c index b3bf35d17e..4c0a5b34b7 100644 --- a/pp.c +++ b/pp.c @@ -467,6 +467,8 @@ S_refto(pTHX_ SV *sv) else if (SvPADTMP(sv)) { sv = newSVsv(sv); } + else if (UNLIKELY(SvSMAGICAL(sv) && mg_find(sv, PERL_MAGIC_nonelem))) + sv_unmagic(SvREFCNT_inc_simple_NN(sv), PERL_MAGIC_nonelem); else { SvTEMP_off(sv); SvREFCNT_inc_void_NN(sv); diff --git a/pp_hot.c b/pp_hot.c index 1b9fb9427a..328d6f0659 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -1167,7 +1167,7 @@ S_pushav(pTHX_ AV* const av) SP[i+1] = LIKELY(svp) ? *svp : UNLIKELY(PL_op->op_flags & OPf_MOD) - ? newSVavdefelem(av,i,1) + ? av_nonelem(av,i) : &PL_sv_undef; } } @@ -1178,7 +1178,7 @@ S_pushav(pTHX_ AV* const av) SP[i+1] = LIKELY(sv) ? sv : UNLIKELY(PL_op->op_flags & OPf_MOD) - ? newSVavdefelem(av,i,1) + ? av_nonelem(av,i) : &PL_sv_undef; } } @@ -3630,13 +3630,19 @@ PP(pp_multideref) if (!defer) DIE(aTHX_ PL_no_aelem, elem); len = av_tindex(av); - sv = sv_2mortal(newSVavdefelem(av, - /* Resolve a negative index now, unless it points - * before the beginning of the array, in which - * case record it for error reporting in - * magic_setdefelem. */ - elem < 0 && len + elem >= 0 - ? len + elem : elem, 1)); + /* Resolve a negative index that falls within + * the array. Leave it negative it if falls + * outside the array. */ + if (elem < 0 && len + elem >= 0) + elem = len + elem; + if (elem >= 0 && elem <= len) + /* Falls within the array. */ + sv = av_nonelem(av,elem); + else + /* Falls outside the array. If it is neg- + ative, magic_setdefelem will use the + index for error reporting. */ + sv = sv_2mortal(newSVavdefelem(av,elem,1)); } else { if (UNLIKELY(localizing)) { @@ -5215,7 +5221,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; @@ -5363,12 +5369,18 @@ PP(pp_aelem) if (!defer) DIE(aTHX_ PL_no_aelem, elem); len = av_tindex(av); - mPUSHs(newSVavdefelem(av, - /* Resolve a negative index now, unless it points before the - beginning of the array, in which case record it for error - reporting in magic_setdefelem. */ - elem < 0 && len + elem >= 0 ? len + elem : elem, - 1)); + /* Resolve a negative index that falls within the array. Leave + it negative it if falls outside the array. */ + if (elem < 0 && len + elem >= 0) + elem = len + elem; + if (elem >= 0 && elem <= len) + /* Falls within the array. */ + PUSHs(av_nonelem(av,elem)); + else + /* Falls outside the array. If it is negative, + magic_setdefelem will use the index for error reporting. + */ + mPUSHs(newSVavdefelem(av, elem, 1)); RETURN; } if (UNLIKELY(localizing)) { diff --git a/proto.h b/proto.h index 80b9e240b5..d6c36a08fa 100644 --- a/proto.h +++ b/proto.h @@ -220,6 +220,9 @@ PERL_CALLCONV AV* Perl_av_make(pTHX_ SSize_t size, SV **strp) #define PERL_ARGS_ASSERT_AV_MAKE \ assert(strp) +PERL_CALLCONV SV* Perl_av_nonelem(pTHX_ AV *av, SSize_t ix); +#define PERL_ARGS_ASSERT_AV_NONELEM \ + assert(av) PERL_CALLCONV SV* Perl_av_pop(pTHX_ AV *av); #define PERL_ARGS_ASSERT_AV_POP \ assert(av) @@ -1943,6 +1946,9 @@ PERL_CALLCONV int Perl_magic_setmglob(pTHX_ SV* sv, MAGIC* mg); PERL_CALLCONV int Perl_magic_setnkeys(pTHX_ SV* sv, MAGIC* mg); #define PERL_ARGS_ASSERT_MAGIC_SETNKEYS \ assert(sv); assert(mg) +PERL_CALLCONV int Perl_magic_setnonelem(pTHX_ SV* sv, MAGIC* mg); +#define PERL_ARGS_ASSERT_MAGIC_SETNONELEM \ + assert(sv); assert(mg) PERL_CALLCONV int Perl_magic_setpack(pTHX_ SV* sv, MAGIC* mg); #define PERL_ARGS_ASSERT_MAGIC_SETPACK \ assert(sv); assert(mg) diff --git a/regen/mg_vtable.pl b/regen/mg_vtable.pl index 342f5e04c4..f5213b2c21 100644 --- a/regen/mg_vtable.pl +++ b/regen/mg_vtable.pl @@ -92,6 +92,8 @@ my %mg = desc => 'substr() lvalue' }, defelem => { char => 'y', vtable => 'defelem', value_magic => 1, desc => "Shadow \"foreach\" iterator variable /\nsmart parameter vivification" }, + nonelem => { char => 'Y', vtable => 'nonelem', value_magic => 1, + desc => "Array element that does not exist" }, arylen => { char => '#', vtable => 'arylen', value_magic => 1, desc => 'Array length ($#ary)' }, pos => { char => '.', vtable => 'pos', value_magic => 1, @@ -137,6 +139,7 @@ my %sig = 'pos' => {get => 'getpos', set => 'setpos'}, 'uvar' => {get => 'getuvar', set => 'setuvar'}, 'defelem' => {get => 'getdefelem', set => 'setdefelem'}, + 'nonelem' => {set => 'setnonelem'}, 'regexp' => {set => 'setregexp', alias => [qw(bm fm)]}, 'regdata' => {len => 'regdata_cnt'}, 'regdatum' => {get => 'regdatum_get', set => 'regdatum_set'}, diff --git a/t/op/array.t b/t/op/array.t index aa595327bc..6370a9f072 100644 --- a/t/op/array.t +++ b/t/op/array.t @@ -6,7 +6,7 @@ BEGIN { set_up_inc('.', '../lib'); } -plan (188); +plan (194); # # @foo, @bar, and @ary are also used from tie-stdarray after tie-ing them @@ -642,4 +642,50 @@ $#a = -1; $#a++; is @a, 0, 'unwinding localization of elem past end of array shrinks it' } +# perl #132729, as it applies to flattening an array in lvalue context +{ + my @a; + $a[1] = 1; + map { unshift @a, 7; $_ = 3; goto aftermap; } @a; + aftermap: + is "[@a]", "[7 3 1]", + 'non-elems read from @a do not lose their position'; + @a = (); + $#a++; # make it magical + $a[1] = 1; + map { unshift @a, 7; $_ = 3; goto aftermath; } @a; + aftermath: + is "[@a]", "[7 3 1]", + 'non-elems read from magical @a do not lose their position'; +} +# perl #132729, as it applies to ‘holes’ in an array passed to a sub +# individually +{ + my @a; + $a[1] = 1; + sub { unshift @a, 7; $_[0] = 3; }->($a[0]); + is "[@a]", "[7 3 1]", + 'holes passed to sub do not lose their position (multideref)'; + @a = (); + $#a++; # make it magical + $a[1] = 1; + sub { unshift @a, 7; $_[0] = 3; }->($a[0]); + is "[@a]", "[7 3 1]", + 'holes passed to sub do not lose their position (multideref, mg)'; +} +{ + # Again, with aelem, not multideref + my @a; + $a[1] = 1; + sub { unshift @a, 7; $_[0] = 3; }->($a[${\0}]); + is "[@a]", "[7 3 1]", + 'holes passed to sub do not lose their position (aelem)'; + @a = (); + $#a++; # make it magical + $a[1] = 1; + sub { unshift @a, 7; $_[0] = 3; }->($a[${\0}]); + is "[@a]", "[7 3 1]", + 'holes passed to sub do not lose their position (aelem, mg)'; +} + "We're included by lib/Tie/Array/std.t so we need to return something true"; 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 5d99fddcbe..05ae01f792 100644 --- a/t/op/svleak.t +++ b/t/op/svleak.t @@ -15,7 +15,7 @@ BEGIN { use Config; -plan tests => 146; +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 @@ -214,6 +214,14 @@ leak_expr(5, 0, q{"YYYYYa" =~ /.+?(a(.+?)|b)/ }, "trie leak"); } +# Map plus sparse array +{ + my @a; + $a[10] = 10; + leak(3, 0, sub { my @b = map 1, @a }, + 'map reading from sparse array'); +} + SKIP: { # broken by 304474c3, fixed by cefd5c7c, but didn't seem to cause # any other test failures @@ -318,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'); -- Perl5 Master Repository