diff --git a/run.c b/run.c index 7d11ae8b484b..8dd618ace034 100644 --- a/run.c +++ b/run.c @@ -127,9 +127,13 @@ Perl_runops_wrap(pTHX) * upwards; but this may prematurely free them, so * mortalise them instead */ EXTEND_MORTAL(n); - Copy(PL_stack_base + cut, PL_tmps_stack + PL_tmps_ix + 1, n, SV*); - PL_tmps_ix += n; + for (SSize_t i = 0; i < n; i ++) { + SV* sv = PL_stack_base[cut + i]; + if (sv) + PL_tmps_stack[++PL_tmps_ix] = sv; + } } + I32 sp1 = PL_stack_sp - PL_stack_base + 1; PL_curstackinfo->si_stack_nonrc_base = old_base > sp1 ? sp1 : old_base; diff --git a/t/op/grep.t b/t/op/grep.t index 8ab9a8aa4d87..42a8903717d2 100644 --- a/t/op/grep.t +++ b/t/op/grep.t @@ -10,7 +10,7 @@ BEGIN { set_up_inc( qw(. ../lib) ); } -plan( tests => 76 ); +plan( tests => 77 ); { my @lol = ([qw(a b c)], [], [qw(1 2 3)]); @@ -278,3 +278,19 @@ package FOO { bless[]; } 1,2,3; } + +# At one point during development, this code SEGVed on PERL_RC_STACK +# builds, as NULL filler pointers on the stack during a map were getting +# copied to the tmps stack, and the tmps stack can't handle NULL pointers. +# The bug only occurred in IO::Socket::SSL rather than core. It required +# perl doing a call_sv(.., G_EVAL) to call the sub containing the map. In +# the original bug this was triggered by a use/require, but here we use a +# BEGIN within an eval as simpler variant. + +{ + my @res; + eval q{ + BEGIN { @res = map { $_ => eval {die} || -1 } qw( ABC XYZ); } + }; + is("@res", "ABC -1 XYZ -1", "no NULL tmps"); +}