summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2010-03-23 12:11:43 +0000
committerDavid Mitchell <davem@iabyn.com>2010-03-23 12:11:43 +0000
commitfd69380d5d5b95ef16e2521cf4251b34ee0ce151 (patch)
tree06f3bdf160300d7361e10d1ef591d0fb77801406 /pp_hot.c
parentd71e3dc326c2464ea298c6a68a3c5ab7f611e6c1 (diff)
downloadperl-fd69380d5d5b95ef16e2521cf4251b34ee0ce151.tar.gz
Fix assorted bugs related to magic (such as pos) not "sticking" to
magical array and hash elements; e.g. the following looped infinitely: $h{tainted_element} =~ /..../g There are two side-effects of this fix. First, MGf_GSKIP has been extended to work on tied array elements as well as hash elements. This is the mechanism that skips all but the first tied element magic gets until after the next set. Second, rvalue hash/array element access where the element has get magic, now directly returns the element rather than a mortal copy. The root cause of the bug was code similar to the following in pp_alem, pp_aelemfast, pp_helem and pp_rv2av: if (!lval && SvGMAGICAL(sv)) /* see note in pp_helem() */ sv = sv_mortalcopy(sv); According to the note, this was added in 1998 to make this work: local $tied{foo} = $tied{foo} Since it returns a copy rather than the element, this make //g fail. My first attempt, a few years ago, to fix this, took the approach that the LHS of the bind should be made an lvalue in the presence of //g, since it now modifies its LHS; i.e. expr =~ // expr is rvalue expr =~ s/// expr is lvalue expr =~ //g expr was rvalue, I proposed to change it to lvalue Unfortunately this fix broke too much stuff (stuff that was arguably already broken, but it upset people). For example, f() ~= s//// correctly gives the error Can't modify non-lvalue subroutine call My fix extended f() =~ //g to give the same error. Which is reasonable, because the g isn't doing what you want. But plenty of people had code that only needed to match once and the g had just been cargo-culted. So it broke their working code. So lets not do this. My new approach has been to remove the sv_mortalcopy(). It turns out that this is no longer needed to fix the local $tied{foo} issue. Presumably that went away as a side-effect of my container/value magic localisation rationalisation of a few years ago, although I haven't analysed it - just noted that the tests still pass (!). However, an issue with removing it is that mg_get() no longer gets called. So a plain $tied_hash{elem}; in void context no longer calls FETCH(). Which broke some tests and might break some code. Also, there's an issue with the delayed calling of magic in @+[n] and %+{foo}; by the time the get magic is called, the original pattern may have gone out of scope. The solution is to simply replace the original sv = sv_mortalcopy(sv); with mg_get(sv); This then caused problems with tied array FETCH() getting called too much. I fixed this by extending the MGf_GSKIP mechanism to tied arrays as well as hashes. I don't understand why tied arrays have always been treated differently than tied hashes, but unifying them didn't seem to break anything (except for a Storable test, whose comment indicated that the test's author thought FETCH() was being called to often anyway).
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 3371e889ea..8f8af53230 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -658,7 +658,7 @@ PP(pp_aelemfast)
SV *sv = (svp ? *svp : &PL_sv_undef);
EXTEND(SP, 1);
if (!lval && SvGMAGICAL(sv)) /* see note in pp_helem() */
- sv = sv_mortalcopy(sv);
+ mg_get(sv);
PUSHs(sv);
RETURN;
}
@@ -893,7 +893,7 @@ PP(pp_rv2av)
SV ** const svp = av_fetch(av, i, FALSE);
/* See note in pp_helem, and bug id #27839 */
SP[i+1] = svp
- ? SvGMAGICAL(*svp) ? sv_mortalcopy(*svp) : *svp
+ ? SvGMAGICAL(*svp) ? (mg_get(*svp), *svp) : *svp
: &PL_sv_undef;
}
}
@@ -1840,14 +1840,20 @@ PP(pp_helem)
vivify_ref(*svp, PL_op->op_private & OPpDEREF);
}
sv = (svp ? *svp : &PL_sv_undef);
- /* This makes C<local $tied{foo} = $tied{foo}> possible.
- * Pushing the magical RHS on to the stack is useless, since
- * that magic is soon destined to be misled by the local(),
- * and thus the later pp_sassign() will fail to mg_get() the
- * old value. This should also cure problems with delayed
- * mg_get()s. GSAR 98-07-03 */
+ /* Originally this did a conditional C<sv = sv_mortalcopy(sv)>; this
+ * was to make C<local $tied{foo} = $tied{foo}> possible.
+ * However, it seems no longer to be needed for that purpose, and
+ * introduced a new bug: stuff like C<while ($hash{taintedval} =~ /.../g>
+ * would loop endlessly since the pos magic is getting set on the
+ * mortal copy and lost. However, the copy has the effect of
+ * triggering the get magic, and losing it altogether made things like
+ * c<$tied{foo};> in void context no longer do get magic, which some
+ * code relied on. Also, delayed triggering of magic on @+ and friends
+ * meant the original regex may be out of scope by now. So as a
+ * compromise, do the get magic here. (The MGf_GSKIP flag will stop it
+ * being called too many times). */
if (!lval && SvGMAGICAL(sv))
- sv = sv_mortalcopy(sv);
+ mg_get(sv);
PUSHs(sv);
RETURN;
}
@@ -2983,7 +2989,7 @@ PP(pp_aelem)
}
sv = (svp ? *svp : &PL_sv_undef);
if (!lval && SvGMAGICAL(sv)) /* see note in pp_helem() */
- sv = sv_mortalcopy(sv);
+ mg_get(sv);
PUSHs(sv);
RETURN;
}