Skip to content

Commit

Permalink
[MERGE] handle /(?{})/ with overload::constant qr
Browse files Browse the repository at this point in the history
The reworking of the re_eval implementation for 5.17.1 made the assumption
that constant strings within literal patterns were, um, constant.

It turns out this this is an invalid assumption, because

    overload::constant qr => { sub return bless [], 'Foo' }

can cause the constant bits of a pattern, like foo, bar in

    /foo(?{...})bar/

to get replaced with (for example) blessed objects: so the 'constant' SV
attached to an OP_CONST is actually a blessed object, that could itself be
overloaded with string or concat methods say, or could be a qr// object
etc.

The commits in this merge (hopefully) fix the various problems this
assumption caused: chiefly with qr// objects containing compiled (?{})
code that were getting re-stringified and thus failing unless in the
presence of use re 'eval' (and sometimes failing even in its presence).
Also, runtime patterns could trigger a recursive call to the overload
method, and eventually stack overflow and SEGV.

See [perl #116823].
  • Loading branch information
iabyn committed Apr 12, 2013
2 parents 335e2ee + 4f3e251 commit e501306
Show file tree
Hide file tree
Showing 10 changed files with 359 additions and 231 deletions.
2 changes: 2 additions & 0 deletions cop.h
Expand Up @@ -1048,13 +1048,15 @@ L<perlcall>.
Perl_magic_methcall(). */
#define G_WRITING_TO_STDERR 1024 /* Perl_write_to_stderr() is calling
Perl_magic_methcall(). */
#define G_RE_REPARSING 0x800 /* compiling a run-time /(?{..})/ */

/* flag bits for PL_in_eval */
#define EVAL_NULL 0 /* not in an eval */
#define EVAL_INEVAL 1 /* some enclosing scope is an eval */
#define EVAL_WARNONLY 2 /* used by yywarn() when calling yyerror() */
#define EVAL_KEEPERR 4 /* set by Perl_call_sv if G_KEEPERR */
#define EVAL_INREQUIRE 8 /* The code is being required. */
#define EVAL_RE_REPARSING 0x10 /* eval_sv() called with G_RE_REPARSING */

/* Support for switching (stack and block) contexts.
* This ensures magic doesn't invalidate local stack and cx pointers.
Expand Down
1 change: 1 addition & 0 deletions op.h
Expand Up @@ -308,6 +308,7 @@ Deprecated. Use C<GIMME_V> instead.
#define OPpEVAL_UNICODE 4
#define OPpEVAL_BYTES 8
#define OPpEVAL_COPHH 16 /* Construct %^H from cop hints */
#define OPpEVAL_RE_REPARSING 32 /* eval_sv(..., G_RE_REPARSING) */

/* Private for OP_CALLER, OP_WANTARRAY and OP_RUNCV */
#define OPpOFFBYONE 128 /* Treat caller(1) as caller(2) */
Expand Down
2 changes: 1 addition & 1 deletion parser.h
Expand Up @@ -71,7 +71,7 @@ typedef struct yy_parser {
char multi_open; /* delimiter of said string */
char multi_close; /* delimiter of said string */
bool preambled;
/*** 8-bit hole ***/
bool lex_re_reparsing; /* we're doing G_RE_REPARSING */
I32 lex_allbrackets;/* (), [], {}, ?: bracket count */
SUBLEXINFO sublex_info;
LEXSHARED *lex_shared;
Expand Down
5 changes: 3 additions & 2 deletions perl.c
Expand Up @@ -2808,8 +2808,9 @@ Perl_eval_sv(pTHX_ SV *sv, I32 flags)
myop.op_flags |= OP_GIMME_REVERSE(flags);
if (flags & G_KEEPERR)
myop.op_flags |= OPf_SPECIAL;
if (PL_reg_state.re_reparsing)
myop.op_private = OPpEVAL_COPHH;

if (flags & G_RE_REPARSING)
myop.op_private = (OPpEVAL_COPHH | OPpEVAL_RE_REPARSING);

/* fail now; otherwise we could fail after the JMPENV_PUSH but
* before a PUSHEVAL, which corrupts the stack after a croak */
Expand Down
13 changes: 12 additions & 1 deletion pp_ctl.c
Expand Up @@ -3358,7 +3358,9 @@ S_doeval(pTHX_ int gimme, CV* outside, U32 seq, HV *hh)

PL_in_eval = (in_require
? (EVAL_INREQUIRE | (PL_in_eval & EVAL_INEVAL))
: EVAL_INEVAL);
: (EVAL_INEVAL |
((PL_op->op_private & OPpEVAL_RE_REPARSING)
? EVAL_RE_REPARSING : 0)));

PUSHMARK(SP);

Expand Down Expand Up @@ -3420,6 +3422,15 @@ S_doeval(pTHX_ int gimme, CV* outside, U32 seq, HV *hh)
else {
PL_hints = saveop->op_private & OPpEVAL_COPHH
? oldcurcop->cop_hints : saveop->op_targ;

/* making 'use re eval' not be in scope when compiling the
* qr/mabye_has_runtime_code_block/ ensures that we don't get
* infinite recursion when S_has_runtime_code() gives a false
* positive: the second time round, HINT_RE_EVAL isn't set so we
* don't bother calling S_has_runtime_code() */
if (PL_in_eval & EVAL_RE_REPARSING)
PL_hints &= ~HINT_RE_EVAL;

if (hh) {
/* SAVEHINTS created a new HV in PL_hintgv, which we need to GC */
SvREFCNT_dec(GvHV(PL_hintgv));
Expand Down

0 comments on commit e501306

Please sign in to comment.