Skip to content

Commit

Permalink
when (re)creating @_, zero its elements
Browse files Browse the repository at this point in the history
When a sub's @_ gets abandoned (e.g. when 'goto &bar' "donates" the
current @_ to the new sub), a new AV is created at pad[0] for the old
sub. Perl alloc()'s the AvARRAY() buffer for the new AV, but didn't zero
it. This didn't used to be a problem, because @_ AVs are created
!AvREAL(), so the first thing perl did when someone tries to modify @_,
is to call av_reify() on it.  And it just so happens that av_reify()
zeros out all the unused slots on the array first. So code like

    $_[1] = 1;
    do_something_with($_[0])

was fine.

However, on PERL_RC_STACK builds, @_ is AvREAL() by default now, so
av_reify() doesn't get called, so AvARRAY() can sometimes contain random
wild pointers.

The fix is simple: zero AvARRAY() when creating it.

This was showing as a failure in Test::Trap
  • Loading branch information
iabyn committed Aug 4, 2023
1 parent 3f16b5f commit e96dd01
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pp_hot.c
Original file line number Diff line number Diff line change
Expand Up @@ -5493,7 +5493,7 @@ Perl_clear_defarray(pTHX_ AV* av, bool abandon)
/* abandon */
const SSize_t size = AvFILLp(av) + 1;
/* The ternary gives consistency with av_extend() */
AV *newav = newAV_alloc_x(size < PERL_ARRAY_NEW_MIN_KEY ?
AV *newav = newAV_alloc_xz(size < PERL_ARRAY_NEW_MIN_KEY ?
PERL_ARRAY_NEW_MIN_KEY : size);
#ifndef PERL_RC_STACK
AvREIFY_only(newav);
Expand Down
22 changes: 21 additions & 1 deletion t/op/goto.t
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ BEGIN {
use warnings;
use strict;
use Config;
plan tests => 133;
plan tests => 134;
our $TODO;

my $deprecated = 0;
Expand Down Expand Up @@ -952,3 +952,23 @@ SKIP:
my @a = bar_19936();
is($XS::APItest::GIMME_V, 3, "GH #19936 gimme XS call");
}

# goto &sub could leave AvARRAY() slots of @_ uninitialised.

{
my $i = 0;
my $f = sub {
goto &{ sub {} } unless $i++;
$_[1] = 1; # create a hole
# accessing $_[0] is more for valgrind/ASAN to chew on rather than
# we're too concerned about its value. Or it might give "bizarre
# copy" errors.
is($_[0], undef, "goto and AvARRAY");
};

# first call does goto, which gives &$f a fresh AV in pad[0],
# which formerly allocated an AvARRAY for it, but didn't zero it
$f->();
# second call creates hole in @_ which used to to be a wild SV pointer
$f->();
}

0 comments on commit e96dd01

Please sign in to comment.