Skip to content

Commit

Permalink
no bareword_filehandes: don't look up class barewords as handles
Browse files Browse the repository at this point in the history
This prevents SomeBareword from being looked up as a filehandle:

  no feature "bareword_filehandles";
  SomeBareword->method();

Since "bareword_filehandles" is explicitly about bareword handles,
it does not prevent other string to object/class look ups from
resolving the class as a filehandle, eg for the following:

  "SomeLiteral"->method();
  my $x = "SomeVariable";
  $x->method();

both are looked up as file handles per normal.

Note that in any of these cases, with or without the
bareword_filehandles feature, if the name is a bareword that
has been resolved as a class name since the last time the
stash cache was cleared, it will be resolved as a class name,
not a filehandle.

Fixes Perl#19426

# Conflicts:
#	opcode.h

# Conflicts:
#	opcode.h
  • Loading branch information
tonycoz committed Feb 21, 2024
1 parent 391c8c3 commit f2d6099
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 110 deletions.
2 changes: 2 additions & 0 deletions embed.fnc
Original file line number Diff line number Diff line change
Expand Up @@ -4714,6 +4714,8 @@ S |void |inplace_aassign|NN OP *o
RST |bool |is_handle_constructor \
|NN const OP *o \
|I32 numargs
Ti |bool |is_standard_filehandle_name \
|NN const char *fhname
S |OP * |listkids |NULLOK OP *o
S |bool |looks_like_bool|NN const OP *o
S |OP * |modkids |NULLOK OP *o \
Expand Down
1 change: 1 addition & 0 deletions embed.h
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,7 @@
# define gen_constant_list(a) S_gen_constant_list(aTHX_ a)
# define inplace_aassign(a) S_inplace_aassign(aTHX_ a)
# define is_handle_constructor S_is_handle_constructor
# define is_standard_filehandle_name S_is_standard_filehandle_name
# define listkids(a) S_listkids(aTHX_ a)
# define looks_like_bool(a) S_looks_like_bool(aTHX_ a)
# define modkids(a,b) S_modkids(aTHX_ a,b)
Expand Down
4 changes: 4 additions & 0 deletions lib/B/Op_private.pm

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 27 additions & 7 deletions op.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,17 +712,27 @@ Perl_no_bareword_allowed(pTHX_ OP *o)
o->op_private &= ~OPpCONST_STRICT; /* prevent warning twice about the same OP */
}

/*
Return true if the supplied string is the name of one of the built-in
filehandles.
*/

PERL_STATIC_INLINE bool
S_is_standard_filehandle_name(const char *fhname) {
return strEQ(fhname, "STDERR")
|| strEQ(fhname, "STDOUT")
|| strEQ(fhname, "STDIN")
|| strEQ(fhname, "_")
|| strEQ(fhname, "ARGV")
|| strEQ(fhname, "ARGVOUT")
|| strEQ(fhname, "DATA");
}

void
Perl_no_bareword_filehandle(pTHX_ const char *fhname) {
PERL_ARGS_ASSERT_NO_BAREWORD_FILEHANDLE;

if (strNE(fhname, "STDERR")
&& strNE(fhname, "STDOUT")
&& strNE(fhname, "STDIN")
&& strNE(fhname, "_")
&& strNE(fhname, "ARGV")
&& strNE(fhname, "ARGVOUT")
&& strNE(fhname, "DATA")) {
if (!is_standard_filehandle_name(fhname)) {
qerror(Perl_mess(aTHX_ "Bareword filehandle \"%s\" not allowed under 'no feature \"bareword_filehandles\"'", fhname));
}
}
Expand Down Expand Up @@ -14845,6 +14855,7 @@ Perl_ck_subr(pTHX_ OP *o)
CV *cv;
GV *namegv;
SV **const_class = NULL;
OP *const_op = NULL;

PERL_ARGS_ASSERT_CK_SUBR;

Expand Down Expand Up @@ -14874,20 +14885,29 @@ Perl_ck_subr(pTHX_ OP *o)
if (aop->op_type == OP_CONST) {
aop->op_private &= ~OPpCONST_STRICT;
const_class = &cSVOPx(aop)->op_sv;
const_op = aop;
}
else if (aop->op_type == OP_LIST) {
OP * const sib = OpSIBLING(cUNOPx(aop)->op_first);
if (sib && sib->op_type == OP_CONST) {
sib->op_private &= ~OPpCONST_STRICT;
const_class = &cSVOPx(sib)->op_sv;
const_op = sib;
}
}
/* make class name a shared cow string to speedup method calls */
/* constant string might be replaced with object, f.e. bigint */
if (const_class && SvPOK(*const_class)) {
assert(const_op);
STRLEN len;
const char* str = SvPV(*const_class, len);
if (len) {
if (!FEATURE_BAREWORD_FILEHANDLES_IS_ENABLED
&& !is_standard_filehandle_name(str)
&& (const_op->op_private & OPpCONST_BARE)) {
cvop->op_private |= OPpMETH_NO_BAREWORD_IO;
}

SV* const shared = newSVpvn_share(
str, SvUTF8(*const_class)
? -(SSize_t)len : (SSize_t)len,
Expand Down
Loading

0 comments on commit f2d6099

Please sign in to comment.