From 503d7c815d88531fb05a65362d5236e943c15ef8 Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Mon, 19 Jun 2023 15:29:13 +1000 Subject: [PATCH] no bareword_filehandes: don't look up class barewords as handles 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 #19426 --- embed.fnc | 2 + embed.h | 1 + lib/B/Op_private.pm | 4 + op.c | 33 ++++- opcode.h | 205 +++++++++++++++-------------- pp_hot.c | 4 +- proto.h | 5 + regen/op_private | 3 +- t/lib/feature/bareword_filehandles | 28 ++++ 9 files changed, 175 insertions(+), 110 deletions(-) diff --git a/embed.fnc b/embed.fnc index f642bfa12f39..f279bbc5ccd8 100644 --- a/embed.fnc +++ b/embed.fnc @@ -4577,6 +4577,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 \ diff --git a/embed.h b/embed.h index f0f3a948a18c..219af6c7f18a 100644 --- a/embed.h +++ b/embed.h @@ -1378,6 +1378,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) diff --git a/lib/B/Op_private.pm b/lib/B/Op_private.pm index 9d754280c57e..a8e9649ab97b 100644 --- a/lib/B/Op_private.pm +++ b/lib/B/Op_private.pm @@ -139,6 +139,7 @@ $bits{$_}{2} = 'OPpLVREF_ELEM' for qw(lvref refassign); $bits{$_}{3} = 'OPpLVREF_ITER' for qw(lvref refassign); $bits{$_}{3} = 'OPpMAYBE_LVSUB' for qw(aassign aelem akeys aslice av2arylen avhvswitch helem hslice keys kvaslice kvhslice multideref padav padhv pos rv2av rv2gv rv2hv substr values vec); $bits{$_}{4} = 'OPpMAYBE_TRUEBOOL' for qw(blessed padhv ref rv2hv); +$bits{$_}{1} = 'OPpMETH_NO_BAREWORD_IO' for qw(method method_named method_redir method_redir_super method_super); $bits{$_}{7} = 'OPpOFFBYONE' for qw(caller runcv wantarray); $bits{$_}{5} = 'OPpOPEN_IN_CRLF' for qw(backtick open); $bits{$_}{4} = 'OPpOPEN_IN_RAW' for qw(backtick open); @@ -671,6 +672,7 @@ our %defines = ( OPpMAYBE_LVSUB => 8, OPpMAYBE_TRUEBOOL => 16, OPpMAY_RETURN_CONSTANT => 32, + OPpMETH_NO_BAREWORD_IO => 2, OPpMULTICONCAT_APPEND => 64, OPpMULTICONCAT_FAKE => 32, OPpMULTICONCAT_STRINGIFY => 8, @@ -785,6 +787,7 @@ our %labels = ( OPpMAYBE_LVSUB => 'LVSUB', OPpMAYBE_TRUEBOOL => 'BOOL?', OPpMAY_RETURN_CONSTANT => 'CONST', + OPpMETH_NO_BAREWORD_IO => 'NO_BAREWORD_IO', OPpMULTICONCAT_APPEND => 'APPEND', OPpMULTICONCAT_FAKE => 'FAKE', OPpMULTICONCAT_STRINGIFY => 'STRINGIFY', @@ -863,6 +866,7 @@ our %ops_using = ( OPpLVREF_ELEM => [qw(lvref refassign)], OPpMAYBE_LVSUB => [qw(aassign aelem akeys aslice av2arylen avhvswitch helem hslice keys kvaslice kvhslice multideref padav padhv pos rv2av rv2gv rv2hv substr values vec)], OPpMAYBE_TRUEBOOL => [qw(blessed padhv ref rv2hv)], + OPpMETH_NO_BAREWORD_IO => [qw(method method_named method_redir method_redir_super method_super)], OPpMULTICONCAT_APPEND => [qw(multiconcat)], OPpMULTIDEREF_DELETE => [qw(multideref)], OPpOFFBYONE => [qw(caller runcv wantarray)], diff --git a/op.c b/op.c index df43c2a02d10..8d63fcf248c3 100644 --- a/op.c +++ b/op.c @@ -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)); } } @@ -14601,6 +14611,7 @@ Perl_ck_subr(pTHX_ OP *o) CV *cv; GV *namegv; SV **const_class = NULL; + OP *const_op = NULL; PERL_ARGS_ASSERT_CK_SUBR; @@ -14630,12 +14641,14 @@ 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 */ @@ -14644,6 +14657,12 @@ Perl_ck_subr(pTHX_ OP *o) 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, diff --git a/opcode.h b/opcode.h index 9f5182219a45..610125d9bf4a 100644 --- a/opcode.h +++ b/opcode.h @@ -2293,6 +2293,7 @@ END_EXTERN_C #define OPpHINT_STRICT_REFS 0x02 #define OPpINITFIELD_AV 0x02 #define OPpITER_REVERSED 0x02 +#define OPpMETH_NO_BAREWORD_IO 0x02 #define OPpSORT_INTEGER 0x02 #define OPpTRANS_USE_SVOP 0x02 #define OPpARG2_MASK 0x03 @@ -2493,6 +2494,7 @@ EXTCONST char PL_op_private_labels[] = { 'N','O','(',')','\0', 'N','O','I','N','I','T','\0', 'N','O','V','E','R','\0', + 'N','O','_','B','A','R','E','W','O','R','D','_','I','O','\0', 'N','U','M','\0', 'O','U','R','I','N','T','R','\0', 'O','U','T','B','I','N','\0', @@ -2538,14 +2540,14 @@ EXTCONST char PL_op_private_labels[] = { EXTCONST I16 PL_op_private_bitfields[] = { 0, 8, -1, 0, 8, -1, - 0, 675, -1, + 0, 690, -1, 0, 8, -1, 0, 8, -1, - 0, 682, -1, - 0, 671, -1, - 1, -1, 0, 632, 1, 39, 2, 319, -1, + 0, 697, -1, + 0, 686, -1, + 1, -1, 0, 647, 1, 39, 2, 319, -1, 4, -1, 1, 185, 2, 192, 3, 199, -1, - 4, -1, 0, 632, 1, 39, 2, 319, 3, 131, -1, + 4, -1, 0, 647, 1, 39, 2, 319, 3, 131, -1, }; @@ -2769,18 +2771,18 @@ EXTCONST I16 PL_op_private_bitdef_ix[] = { 207, /* dump */ 207, /* goto */ 55, /* exit */ - 0, /* method */ - 0, /* method_named */ - 0, /* method_super */ - 0, /* method_redir */ - 0, /* method_redir_super */ + 209, /* method */ + 209, /* method_named */ + 209, /* method_super */ + 209, /* method_redir */ + 209, /* method_redir_super */ 0, /* entergiven */ 0, /* leavegiven */ 0, /* enterwhen */ 0, /* leavewhen */ -1, /* break */ -1, /* continue */ - 209, /* open */ + 211, /* open */ 55, /* close */ 55, /* pipe_op */ 55, /* fileno */ @@ -2826,33 +2828,33 @@ EXTCONST I16 PL_op_private_bitdef_ix[] = { 0, /* getpeername */ 0, /* lstat */ 0, /* stat */ - 214, /* ftrread */ - 214, /* ftrwrite */ - 214, /* ftrexec */ - 214, /* fteread */ - 214, /* ftewrite */ - 214, /* fteexec */ - 219, /* ftis */ - 219, /* ftsize */ - 219, /* ftmtime */ - 219, /* ftatime */ - 219, /* ftctime */ - 219, /* ftrowned */ - 219, /* fteowned */ - 219, /* ftzero */ - 219, /* ftsock */ - 219, /* ftchr */ - 219, /* ftblk */ - 219, /* ftfile */ - 219, /* ftdir */ - 219, /* ftpipe */ - 219, /* ftsuid */ - 219, /* ftsgid */ - 219, /* ftsvtx */ - 219, /* ftlink */ - 219, /* fttty */ - 219, /* fttext */ - 219, /* ftbinary */ + 216, /* ftrread */ + 216, /* ftrwrite */ + 216, /* ftrexec */ + 216, /* fteread */ + 216, /* ftewrite */ + 216, /* fteexec */ + 221, /* ftis */ + 221, /* ftsize */ + 221, /* ftmtime */ + 221, /* ftatime */ + 221, /* ftctime */ + 221, /* ftrowned */ + 221, /* fteowned */ + 221, /* ftzero */ + 221, /* ftsock */ + 221, /* ftchr */ + 221, /* ftblk */ + 221, /* ftfile */ + 221, /* ftdir */ + 221, /* ftpipe */ + 221, /* ftsuid */ + 221, /* ftsgid */ + 221, /* ftsvtx */ + 221, /* ftlink */ + 221, /* fttty */ + 221, /* fttext */ + 221, /* ftbinary */ 101, /* chdir */ 101, /* chown */ 78, /* chroot */ @@ -2872,17 +2874,17 @@ EXTCONST I16 PL_op_private_bitdef_ix[] = { 0, /* rewinddir */ 0, /* closedir */ -1, /* fork */ - 223, /* wait */ + 225, /* wait */ 101, /* waitpid */ 101, /* system */ 101, /* exec */ 101, /* kill */ - 223, /* getppid */ + 225, /* getppid */ 101, /* getpgrp */ 101, /* setpgrp */ 101, /* getpriority */ 101, /* setpriority */ - 223, /* time */ + 225, /* time */ -1, /* tms */ 0, /* localtime */ 55, /* gmtime */ @@ -2902,7 +2904,7 @@ EXTCONST I16 PL_op_private_bitdef_ix[] = { 0, /* require */ 0, /* dofile */ -1, /* hintseval */ - 224, /* entereval */ + 226, /* entereval */ 188, /* leaveeval */ 0, /* entertry */ -1, /* leavetry */ @@ -2941,17 +2943,17 @@ EXTCONST I16 PL_op_private_bitdef_ix[] = { 0, /* lock */ 0, /* once */ -1, /* custom */ - 231, /* coreargs */ - 235, /* avhvswitch */ + 233, /* coreargs */ + 237, /* avhvswitch */ 3, /* runcv */ 0, /* fc */ -1, /* padcv */ -1, /* introcv */ -1, /* clonecv */ - 237, /* padrange */ - 239, /* refassign */ - 245, /* lvref */ - 251, /* lvrefslice */ + 239, /* padrange */ + 241, /* refassign */ + 247, /* lvref */ + 253, /* lvrefslice */ 16, /* lvavref */ 0, /* anonconst */ 12, /* isa */ @@ -2961,7 +2963,7 @@ EXTCONST I16 PL_op_private_bitdef_ix[] = { -1, /* leavetrycatch */ -1, /* poptry */ 0, /* catch */ - 252, /* pushdefer */ + 254, /* pushdefer */ 0, /* is_bool */ 0, /* is_weak */ 0, /* weaken */ @@ -2972,9 +2974,9 @@ EXTCONST I16 PL_op_private_bitdef_ix[] = { 78, /* ceil */ 78, /* floor */ 0, /* is_tainted */ - 254, /* helemexistsor */ - 256, /* methstart */ - 258, /* initfield */ + 256, /* helemexistsor */ + 258, /* methstart */ + 260, /* initfield */ }; @@ -2993,80 +2995,81 @@ EXTCONST I16 PL_op_private_bitdef_ix[] = { */ EXTCONST U16 PL_op_private_bitdefs[] = { - 0x0003, /* scalar, prototype, refgen, srefgen, readline, regcmaybe, regcreset, regcomp, substcont, chop, schop, defined, study, preinc, i_preinc, predec, i_predec, postinc, i_postinc, postdec, i_postdec, negate, i_negate, not, ucfirst, lcfirst, uc, lc, quotemeta, aeach, avalues, each, pop, shift, grepstart, mapstart, mapwhile, range, and, or, dor, andassign, orassign, dorassign, argcheck, method, method_named, method_super, method_redir, method_redir_super, entergiven, leavegiven, enterwhen, leavewhen, untie, tied, dbmclose, getsockname, getpeername, lstat, stat, readlink, readdir, telldir, rewinddir, closedir, localtime, alarm, require, dofile, entertry, ghbyname, gnbyname, gpbyname, shostent, snetent, sprotoent, sservent, gpwnam, gpwuid, ggrnam, ggrgid, lock, once, fc, anonconst, cmpchain_and, cmpchain_dup, entertrycatch, catch, is_bool, is_weak, weaken, unweaken, is_tainted */ - 0x3abc, 0x4bb9, /* pushmark */ + 0x0003, /* scalar, prototype, refgen, srefgen, readline, regcmaybe, regcreset, regcomp, substcont, chop, schop, defined, study, preinc, i_preinc, predec, i_predec, postinc, i_postinc, postdec, i_postdec, negate, i_negate, not, ucfirst, lcfirst, uc, lc, quotemeta, aeach, avalues, each, pop, shift, grepstart, mapstart, mapwhile, range, and, or, dor, andassign, orassign, dorassign, argcheck, entergiven, leavegiven, enterwhen, leavewhen, untie, tied, dbmclose, getsockname, getpeername, lstat, stat, readlink, readdir, telldir, rewinddir, closedir, localtime, alarm, require, dofile, entertry, ghbyname, gnbyname, gpbyname, shostent, snetent, sprotoent, sservent, gpwnam, gpwuid, ggrnam, ggrgid, lock, once, fc, anonconst, cmpchain_and, cmpchain_dup, entertrycatch, catch, is_bool, is_weak, weaken, unweaken, is_tainted */ + 0x3abc, 0x4d99, /* pushmark */ 0x00bd, /* wantarray, runcv */ - 0x0558, 0x1b70, 0x4c6c, 0x4808, 0x3fe5, /* const */ - 0x3abc, 0x4139, /* gvsv */ + 0x0558, 0x1b70, 0x4e4c, 0x49e8, 0x3fe5, /* const */ + 0x3abc, 0x4319, /* gvsv */ 0x19d5, /* gv */ 0x0067, /* gelem, lt, i_lt, gt, i_gt, le, i_le, ge, i_ge, eq, i_eq, ne, i_ne, ncmp, i_ncmp, slt, sgt, sle, sge, seq, sne, scmp, smartmatch, lslice, xor, isa */ - 0x3abc, 0x4bb8, 0x03d7, /* padsv */ - 0x3abc, 0x4bb8, 0x0003, /* padsv_store, lvavref */ - 0x3abc, 0x4bb8, 0x06d4, 0x3bac, 0x4989, /* padav */ - 0x3abc, 0x4bb8, 0x06d4, 0x0770, 0x3bac, 0x4988, 0x3621, /* padhv */ - 0x3abc, 0x1e38, 0x03d6, 0x3bac, 0x3f08, 0x4c64, 0x0003, /* rv2gv */ - 0x3abc, 0x4138, 0x03d6, 0x4c64, 0x0003, /* rv2sv */ + 0x3abc, 0x4d98, 0x03d7, /* padsv */ + 0x3abc, 0x4d98, 0x0003, /* padsv_store, lvavref */ + 0x3abc, 0x4d98, 0x06d4, 0x3bac, 0x4b69, /* padav */ + 0x3abc, 0x4d98, 0x06d4, 0x0770, 0x3bac, 0x4b68, 0x3621, /* padhv */ + 0x3abc, 0x1e38, 0x03d6, 0x3bac, 0x3f08, 0x4e44, 0x0003, /* rv2gv */ + 0x3abc, 0x4318, 0x03d6, 0x4e44, 0x0003, /* rv2sv */ 0x3bac, 0x0003, /* av2arylen, akeys, values, keys */ - 0x3e7c, 0x1198, 0x0ef4, 0x014c, 0x4f68, 0x4c64, 0x0003, /* rv2cv */ + 0x3e7c, 0x1198, 0x0ef4, 0x014c, 0x5148, 0x4e44, 0x0003, /* rv2cv */ 0x06d4, 0x0770, 0x0003, /* ref, blessed */ 0x018f, /* bless, glob, sprintf, formline, unpack, pack, join, anonlist, anonhash, splice, warn, die, reset, exit, close, pipe_op, fileno, umask, binmode, tie, dbmopen, sselect, select, getc, read, enterwrite, sysopen, sysseek, sysread, syswrite, eof, tell, seek, truncate, fcntl, ioctl, send, recv, socket, sockpair, bind, connect, listen, accept, shutdown, gsockopt, ssockopt, open_dir, seekdir, gmtime, shmget, shmctl, shmread, shmwrite, msgget, msgctl, msgsnd, msgrcv, semop, semget, semctl, ghbyaddr, gnbyaddr, gpbynumber, gsbyname, gsbyport, syscall */ - 0x431c, 0x4238, 0x2dd4, 0x2d10, 0x0003, /* backtick */ + 0x44fc, 0x4418, 0x2dd4, 0x2d10, 0x0003, /* backtick */ 0x06d5, /* subst */ - 0x129c, 0x24b8, 0x0ad4, 0x4acc, 0x2848, 0x5244, 0x08e1, /* trans, transr */ + 0x129c, 0x24b8, 0x0ad4, 0x4cac, 0x2848, 0x5424, 0x08e1, /* trans, transr */ 0x10dc, 0x05f8, 0x0067, /* sassign */ 0x0d98, 0x0c94, 0x0b90, 0x3bac, 0x06c8, 0x0067, /* aassign */ - 0x5010, 0x0003, /* chomp, schomp, scomplement, sin, cos, exp, log, sqrt, int, hex, oct, abs, ord, chr, chroot, rmdir, refaddr, reftype, ceil, floor */ - 0x3abc, 0x4bb8, 0x3534, 0x5010, 0x0003, /* undef */ + 0x51f0, 0x0003, /* chomp, schomp, scomplement, sin, cos, exp, log, sqrt, int, hex, oct, abs, ord, chr, chroot, rmdir, refaddr, reftype, ceil, floor */ + 0x3abc, 0x4d98, 0x3534, 0x51f0, 0x0003, /* undef */ 0x06d4, 0x3bac, 0x0003, /* pos */ - 0x5010, 0x0067, /* pow, multiply, i_multiply, divide, i_divide, modulo, i_modulo, add, i_add, subtract, i_subtract */ + 0x51f0, 0x0067, /* pow, multiply, i_multiply, divide, i_divide, modulo, i_modulo, add, i_add, subtract, i_subtract */ 0x1658, 0x0067, /* repeat */ - 0x3d98, 0x5010, 0x0067, /* concat */ - 0x3abc, 0x0338, 0x1e34, 0x5010, 0x4d4c, 0x0003, /* multiconcat */ - 0x5010, 0x018f, /* stringify, atan2, rand, srand, crypt, push, unshift, flock, chdir, chown, unlink, chmod, utime, rename, link, symlink, mkdir, waitpid, system, exec, kill, getpgrp, setpgrp, getpriority, setpriority, sleep */ - 0x5010, 0x5169, /* left_shift, right_shift, nbit_and, nbit_xor, nbit_or, ncomplement */ - 0x5169, /* bit_and, bit_xor, bit_or, sbit_and, sbit_xor, sbit_or, complement */ - 0x06d4, 0x5010, 0x0003, /* length */ - 0x4570, 0x3bac, 0x012b, /* substr */ + 0x3d98, 0x51f0, 0x0067, /* concat */ + 0x3abc, 0x0338, 0x1e34, 0x51f0, 0x4f2c, 0x0003, /* multiconcat */ + 0x51f0, 0x018f, /* stringify, atan2, rand, srand, crypt, push, unshift, flock, chdir, chown, unlink, chmod, utime, rename, link, symlink, mkdir, waitpid, system, exec, kill, getpgrp, setpgrp, getpriority, setpriority, sleep */ + 0x51f0, 0x5349, /* left_shift, right_shift, nbit_and, nbit_xor, nbit_or, ncomplement */ + 0x5349, /* bit_and, bit_xor, bit_or, sbit_and, sbit_xor, sbit_or, complement */ + 0x06d4, 0x51f0, 0x0003, /* length */ + 0x4750, 0x3bac, 0x012b, /* substr */ 0x3bac, 0x0067, /* vec */ - 0x3d18, 0x06d4, 0x5010, 0x018f, /* index, rindex */ - 0x3abc, 0x4138, 0x06d4, 0x3bac, 0x4988, 0x4c64, 0x0003, /* rv2av */ + 0x3d18, 0x06d4, 0x51f0, 0x018f, /* index, rindex */ + 0x3abc, 0x4318, 0x06d4, 0x3bac, 0x4b68, 0x4e44, 0x0003, /* rv2av */ 0x025f, /* aelemfast, aelemfast_lex, aelemfastlex_store */ 0x3abc, 0x39b8, 0x03d6, 0x3bac, 0x0067, /* aelem, helem */ - 0x3abc, 0x3bac, 0x4989, /* aslice, hslice */ + 0x3abc, 0x3bac, 0x4b69, /* aslice, hslice */ 0x3bad, /* kvaslice, kvhslice */ - 0x3abc, 0x48d8, 0x36d4, 0x0003, /* delete */ - 0x4e98, 0x0003, /* exists */ - 0x3abc, 0x4138, 0x06d4, 0x0770, 0x3bac, 0x4988, 0x4c64, 0x3621, /* rv2hv */ - 0x3abc, 0x39b8, 0x1314, 0x1d50, 0x3bac, 0x4c64, 0x0003, /* multideref */ - 0x3abc, 0x4138, 0x0410, 0x37cc, 0x2b49, /* split */ + 0x3abc, 0x4ab8, 0x36d4, 0x0003, /* delete */ + 0x5078, 0x0003, /* exists */ + 0x3abc, 0x4318, 0x06d4, 0x0770, 0x3bac, 0x4b68, 0x4e44, 0x3621, /* rv2hv */ + 0x3abc, 0x39b8, 0x1314, 0x1d50, 0x3bac, 0x4e44, 0x0003, /* multideref */ + 0x3abc, 0x4318, 0x0410, 0x37cc, 0x2b49, /* split */ 0x3abc, 0x2579, /* list */ - 0x3abc, 0x4bb8, 0x0214, 0x5010, 0x018f, /* emptyavhv */ - 0x15b0, 0x330c, 0x4668, 0x3404, 0x40a1, /* sort */ + 0x3abc, 0x4d98, 0x0214, 0x51f0, 0x018f, /* emptyavhv */ + 0x15b0, 0x330c, 0x4848, 0x3404, 0x4281, /* sort */ 0x330c, 0x0003, /* reverse */ 0x06d4, 0x0003, /* grepwhile */ 0x3858, 0x0003, /* flip, flop */ 0x3abc, 0x0003, /* cond_expr */ - 0x3abc, 0x1198, 0x03d6, 0x014c, 0x4f68, 0x4c64, 0x2c21, /* entersub */ - 0x43d8, 0x0003, /* leavesub, leavesublv, leavewrite, leaveeval */ + 0x3abc, 0x1198, 0x03d6, 0x014c, 0x5148, 0x4e44, 0x2c21, /* entersub */ + 0x45b8, 0x0003, /* leavesub, leavesublv, leavewrite, leaveeval */ 0x02aa, 0x0003, /* argelem */ 0x2a3c, 0x2918, 0x0003, /* argdefelem */ 0x00bc, 0x018f, /* caller */ 0x2755, /* nextstate, dbstate */ - 0x395c, 0x43d9, /* leave */ - 0x3abc, 0x4138, 0x120c, 0x46e5, /* enteriter */ - 0x46e5, /* iter */ + 0x395c, 0x45b9, /* leave */ + 0x3abc, 0x4318, 0x120c, 0x48c5, /* enteriter */ + 0x48c5, /* iter */ 0x395c, 0x0067, /* leaveloop */ - 0x537c, 0x0003, /* last, next, redo, dump, goto */ - 0x431c, 0x4238, 0x2dd4, 0x2d10, 0x018f, /* open */ + 0x555c, 0x0003, /* last, next, redo, dump, goto */ + 0x40a4, 0x0003, /* method, method_named, method_super, method_redir, method_redir_super */ + 0x44fc, 0x4418, 0x2dd4, 0x2d10, 0x018f, /* open */ 0x20f0, 0x234c, 0x2208, 0x1fc4, 0x0003, /* ftrread, ftrwrite, ftrexec, fteread, ftewrite, fteexec */ 0x20f0, 0x234c, 0x2208, 0x0003, /* ftis, ftsize, ftmtime, ftatime, ftctime, ftrowned, fteowned, ftzero, ftsock, ftchr, ftblk, ftfile, ftdir, ftpipe, ftsuid, ftsgid, ftsvtx, ftlink, fttty, fttext, ftbinary */ - 0x5011, /* wait, getppid, time */ - 0x1c78, 0x4474, 0x0fb0, 0x082c, 0x50e8, 0x2664, 0x0003, /* entereval */ + 0x51f1, /* wait, getppid, time */ + 0x1c78, 0x4654, 0x0fb0, 0x082c, 0x52c8, 0x2664, 0x0003, /* entereval */ 0x3c7c, 0x0018, 0x14c4, 0x13e1, /* coreargs */ 0x3bac, 0x00c7, /* avhvswitch */ 0x3abc, 0x01fb, /* padrange */ - 0x3abc, 0x4bb8, 0x04f6, 0x348c, 0x1ac8, 0x0067, /* refassign */ - 0x3abc, 0x4bb8, 0x04f6, 0x348c, 0x1ac8, 0x0003, /* lvref */ + 0x3abc, 0x4d98, 0x04f6, 0x348c, 0x1ac8, 0x0067, /* refassign */ + 0x3abc, 0x4d98, 0x04f6, 0x348c, 0x1ac8, 0x0003, /* lvref */ 0x3abd, /* lvrefslice */ 0x1edc, 0x0003, /* pushdefer */ 0x131c, 0x0003, /* helemexistsor */ @@ -3295,11 +3298,11 @@ EXTCONST U8 PL_op_private_valid[] = { /* DUMP */ (OPpARG1_MASK|OPpPV_IS_UTF8), /* GOTO */ (OPpARG1_MASK|OPpPV_IS_UTF8), /* EXIT */ (OPpARG4_MASK), - /* METHOD */ (OPpARG1_MASK), - /* METHOD_NAMED */ (OPpARG1_MASK), - /* METHOD_SUPER */ (OPpARG1_MASK), - /* METHOD_REDIR */ (OPpARG1_MASK), - /* METHOD_REDIR_SUPER */ (OPpARG1_MASK), + /* METHOD */ (OPpARG1_MASK|OPpMETH_NO_BAREWORD_IO), + /* METHOD_NAMED */ (OPpARG1_MASK|OPpMETH_NO_BAREWORD_IO), + /* METHOD_SUPER */ (OPpARG1_MASK|OPpMETH_NO_BAREWORD_IO), + /* METHOD_REDIR */ (OPpARG1_MASK|OPpMETH_NO_BAREWORD_IO), + /* METHOD_REDIR_SUPER */ (OPpARG1_MASK|OPpMETH_NO_BAREWORD_IO), /* ENTERGIVEN */ (OPpARG1_MASK), /* LEAVEGIVEN */ (OPpARG1_MASK), /* ENTERWHEN */ (OPpARG1_MASK), diff --git a/pp_hot.c b/pp_hot.c index 3ec24a0e232a..32e2e2ebf648 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -35,6 +35,7 @@ #define PERL_IN_PP_HOT_C #include "perl.h" #include "regcomp.h" +#include "feature.h" /* Hot code. */ @@ -5783,7 +5784,8 @@ S_opmethod_stash(pTHX_ SV* meth) stash = gv_stashpvn(packname, packlen, packname_utf8 | GV_CACHE_ONLY); if (stash) return stash; - if (!(iogv = gv_fetchpvn_flags( + if ((PL_op->op_private & OPpMETH_NO_BAREWORD_IO) || + !(iogv = gv_fetchpvn_flags( packname, packlen, packname_utf8, SVt_PVIO )) || !(ob=MUTABLE_SV(GvIO(iogv)))) diff --git a/proto.h b/proto.h index 74c373655474..706c48d7f6e8 100644 --- a/proto.h +++ b/proto.h @@ -7397,6 +7397,11 @@ S_voidnonfinal(pTHX_ OP *o); # define PERL_ARGS_ASSERT_VOIDNONFINAL # if !defined(PERL_NO_INLINE_FUNCTIONS) +PERL_STATIC_INLINE bool +S_is_standard_filehandle_name(const char *fhname); +# define PERL_ARGS_ASSERT_IS_STANDARD_FILEHANDLE_NAME \ + assert(fhname) + PERL_STATIC_INLINE OP * S_newMETHOP_internal(pTHX_ I32 type, I32 flags, OP *dynamic_meth, SV * const_meth); # define PERL_ARGS_ASSERT_NEWMETHOP_INTERNAL diff --git a/regen/op_private b/regen/op_private index 547879b62615..518d48ff026b 100644 --- a/regen/op_private +++ b/regen/op_private @@ -482,7 +482,8 @@ addbits($_, 7 => qw(OPpOFFBYONE +1)) for qw(caller wantarray runcv); # label is in UTF8 */ addbits($_, 7 => qw(OPpPV_IS_UTF8 UTF)) for qw(last redo next goto dump); - +# suppress looking up a class name as an IO handle in a method call +addbits($_, 1 => qw(OPpMETH_NO_BAREWORD_IO NO_BAREWORD_IO)) for ops_with_flag('.'); # ==================================================================== # diff --git a/t/lib/feature/bareword_filehandles b/t/lib/feature/bareword_filehandles index 3ac4d560de6d..d8c5742d343a 100644 --- a/t/lib/feature/bareword_filehandles +++ b/t/lib/feature/bareword_filehandles @@ -528,3 +528,31 @@ say main->foo; -x main->foo(); -x main->foo; EXPECT +######## +# NAME bareword method calls resolving to bareword filehandles +# https://github.com/Perl/perl5/issues/19426 +use feature "say"; +my $x = "Foo"; +*Foo = *STDOUT; # make Foo an IO +sub Foo::say { + say ">", @_[1..$#_]; +} +Foo->say("Hello"); # calls IO::File->say() +no feature "bareword_filehandles"; +"Foo"->say("Alpha"); # calls IO::File::say(); +$x->say("Beta"); # calls IO::File::say() +Foo->say("Goodbye"); # calls Foo->say(), Foo now in stash cache +"Foo"->say("Gamma"); # calls Foo->say() +STDOUT->say("stdout"); # calls IO::File->say +use feature "bareword_filehandles"; +Foo->say("Delta"); # calls Foo->say() +$x->say("Epsilon"); # calls Foo->say() +EXPECT +Hello +Alpha +Beta +>Goodbye +>Gamma +stdout +>Delta +>Epsilon