summaryrefslogtreecommitdiff
path: root/pp.c
diff options
context:
space:
mode:
authorDave Mitchell <davem@fdisolutions.com>2004-03-27 01:54:09 +0000
committerDave Mitchell <davem@fdisolutions.com>2004-03-27 01:54:09 +0000
commit781e754729fc501417aaa89f25dc83f904a17c5c (patch)
treeacd18394b24e1dee6d0d3d8d64564808b9a1195c /pp.c
parent314d47789e6f2fb6e6cb6d9aa287d0766ea79b45 (diff)
downloadperl-781e754729fc501417aaa89f25dc83f904a17c5c.tar.gz
[perl #24200] string corruption with lvalue sub
Depending on the context, the same substr OP may want to return a PVLV or an LV on subsequent invcations. If TARG is the wrong type, use a mortal instead. p4raw-id: //depot/perl@22599
Diffstat (limited to 'pp.c')
-rw-r--r--pp.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/pp.c b/pp.c
index 4c3e377ec4..0bf02fa41d 100644
--- a/pp.c
+++ b/pp.c
@@ -3038,6 +3038,19 @@ PP(pp_substr)
if (utf8_curlen)
sv_pos_u2b(sv, &pos, &rem);
tmps += pos;
+ /* we either return a PV or an LV. If the TARG hasn't been used
+ * before, or is of that type, reuse it; otherwise use a mortal
+ * instead. Note that LVs can have an extended lifetime, so also
+ * dont reuse if refcount > 1 (bug #20933) */
+ if (SvTYPE(TARG) > SVt_NULL) {
+ if ( (SvTYPE(TARG) == SVt_PVLV)
+ ? (!lvalue || SvREFCNT(TARG) > 1)
+ : lvalue)
+ {
+ TARG = sv_newmortal();
+ }
+ }
+
sv_setpvn(TARG, tmps, rem);
#ifdef USE_LOCALE_COLLATE
sv_unmagic(TARG, PERL_MAGIC_collxfrm);
@@ -3074,8 +3087,6 @@ PP(pp_substr)
sv_setpvn(sv,"",0); /* avoid lexical reincarnation */
}
- if (SvREFCNT(TARG) > 1) /* don't share the TARG (#20933) */
- TARG = sv_newmortal();
if (SvTYPE(TARG) < SVt_PVLV) {
sv_upgrade(TARG, SVt_PVLV);
sv_magic(TARG, Nullsv, PERL_MAGIC_substr, Nullch, 0);