Skip to content

Commit dec99a6

Browse files
committed
Perl_runops_wrap((): don't mortalise NULLs
This function was doing a delayed ref count decrement of all the SVs it had previously temporarily incremented, by mortalising each one. For efficiency it was just doing a Copy() of a block of SVs addresses from the argument stack to the TEMPs stack. However, the TEMPs stack can't cope with NULL pointers, while there are sometimes NULL pointers on the argument stack - in particular, while doing a map, any temporary holes in the stack are set to NULL on PERL_RC_STACK builds. The fix is simple - copy individual non-NULL addresses to the TEMPS stack rather than doing a block copy.
1 parent ae41033 commit dec99a6

File tree

2 files changed

+23
-3
lines changed

2 files changed

+23
-3
lines changed

run.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,13 @@ Perl_runops_wrap(pTHX)
127127
* upwards; but this may prematurely free them, so
128128
* mortalise them instead */
129129
EXTEND_MORTAL(n);
130-
Copy(PL_stack_base + cut, PL_tmps_stack + PL_tmps_ix + 1, n, SV*);
131-
PL_tmps_ix += n;
130+
for (SSize_t i = 0; i < n; i ++) {
131+
SV* sv = PL_stack_base[cut + i];
132+
if (sv)
133+
PL_tmps_stack[++PL_tmps_ix] = sv;
134+
}
132135
}
136+
133137
I32 sp1 = PL_stack_sp - PL_stack_base + 1;
134138
PL_curstackinfo->si_stack_nonrc_base =
135139
old_base > sp1 ? sp1 : old_base;

t/op/grep.t

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ BEGIN {
1010
set_up_inc( qw(. ../lib) );
1111
}
1212

13-
plan( tests => 76 );
13+
plan( tests => 77 );
1414

1515
{
1616
my @lol = ([qw(a b c)], [], [qw(1 2 3)]);
@@ -278,3 +278,19 @@ package FOO {
278278
bless[];
279279
} 1,2,3;
280280
}
281+
282+
# At one point during development, this code SEGVed on PERL_RC_STACK
283+
# builds, as NULL filler pointers on the stack during a map were getting
284+
# copied to the tmps stack, and the tmps stack can't handle NULL pointers.
285+
# The bug only occurred in IO::Socket::SSL rather than core. It required
286+
# perl doing a call_sv(.., G_EVAL) to call the sub containing the map. In
287+
# the original bug this was triggered by a use/require, but here we use a
288+
# BEGIN within an eval as simpler variant.
289+
290+
{
291+
my @res;
292+
eval q{
293+
BEGIN { @res = map { $_ => eval {die} || -1 } qw( ABC XYZ); }
294+
};
295+
is("@res", "ABC -1 XYZ -1", "no NULL tmps");
296+
}

0 commit comments

Comments
 (0)