Skip to content

Commit

Permalink
[perl #132854] Allow goto into first arg of bin op
Browse files Browse the repository at this point in the history
This particular case does not risk any stack corruption, and there is
a CPAN module depending on it working (PerlX::AsyncAwait).
  • Loading branch information
Father Chrysostomos committed Feb 24, 2018
1 parent d594884 commit b4dcd72
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 3 deletions.
7 changes: 6 additions & 1 deletion pod/perldelta.pod
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,12 @@ XXX Changes (i.e. rewording) of diagnostic messages go here

=item *

XXX Describe change here
The new (as of 5.27.8) restriction forbidding use of C<goto> to enter the
argument of a binary or list expression (see L<perldiag/"Can't
E<quot>gotoE<quot> into a binary or list expression">) has been relaxed to
allow entering the I<first> argument of an operator that takes a fixed
number of arguments, since this is a case that will not cause stack
corruption. [perl #132854]

=back

Expand Down
4 changes: 3 additions & 1 deletion pod/perlfunc.pod
Original file line number Diff line number Diff line change
Expand Up @@ -3458,7 +3458,9 @@ deprecated and will issue a warning. Even then, it may not be used to
go into any construct that requires initialization, such as a
subroutine, a C<foreach> loop, or a C<given>
block. In general, it may not be used to jump into the parameter
of a binary or list operator. It also can't be used to go into a
of a binary or list operator, but it may be used to jump into the
I<first> parameter of a binary operator or other operator that takes
a fixed number of arguments. It also can't be used to go into a
construct that is optimized away.

The C<goto &NAME> form is quite different from the other forms of
Expand Down
8 changes: 8 additions & 0 deletions pp_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2687,6 +2687,7 @@ S_dofindlabel(pTHX_ OP *o, const char *label, STRLEN len, U32 flags, OP **opstac
*ops = 0;
if (o->op_flags & OPf_KIDS) {
OP *kid;
OP * const kid1 = cUNOPo->op_first;
/* First try all the kids at this level, since that's likeliest. */
for (kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid)) {
if (kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) {
Expand All @@ -2709,6 +2710,7 @@ S_dofindlabel(pTHX_ OP *o, const char *label, STRLEN len, U32 flags, OP **opstac
}
}
for (kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid)) {
bool first_kid_of_binary = FALSE;
if (kid == PL_lastgotoprobe)
continue;
if (kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) {
Expand All @@ -2721,8 +2723,14 @@ S_dofindlabel(pTHX_ OP *o, const char *label, STRLEN len, U32 flags, OP **opstac
else
*ops++ = kid;
}
if (kid == kid1 && ops != opstack && ops[-1] == UNENTERABLE) {
first_kid_of_binary = TRUE;
ops--;
}
if ((o = dofindlabel(kid, label, len, flags, ops, oplimit)))
return o;
if (first_kid_of_binary)
*ops++ = UNENTERABLE;
}
}
*ops = 0;
Expand Down
12 changes: 11 additions & 1 deletion t/op/goto.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ BEGIN {

use warnings;
use strict;
plan tests => 122;
plan tests => 123;
our $TODO;

my $deprecated = 0;
Expand Down Expand Up @@ -870,3 +870,13 @@ sub _routine {
}
_routine();
pass("bug 132799");

# [perl #132854]
# Goto the *first* parameter of a binary expression, which is harmless.
eval {
goto __GEN_2;
my $sent = do {
__GEN_2:
};
};
is $@,'', 'goto the first parameter of a binary expression [perl #132854]';

0 comments on commit b4dcd72

Please sign in to comment.