summaryrefslogtreecommitdiff
path: root/doop.c
diff options
context:
space:
mode:
authorTony Cook <tony@develop-help.com>2016-11-07 11:22:55 +1100
committerTony Cook <tony@develop-help.com>2016-11-07 11:22:55 +1100
commitdc529e655355bff17b35ddec08d5bc5cbbdd206a (patch)
treeb1573b8277ac360bcce0ecc60a58f9a66daa3dfc /doop.c
parenta75f6a0b013c6142133284dab143f1ad0e581b10 (diff)
downloadperl-dc529e655355bff17b35ddec08d5bc5cbbdd206a.tar.gz
(perl #129995) avoid sv_catpvn() in do_vop() when unneeded
This could call sv_catpvn() with the source string being within the destination SV, which caused a freed memory access if do_vop() and sv_catpvn_flags() had different ideas about the ideal size of the target SV's buffer.
Diffstat (limited to 'doop.c')
-rw-r--r--doop.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/doop.c b/doop.c
index 5525c470e8..bc23c9e872 100644
--- a/doop.c
+++ b/doop.c
@@ -1218,8 +1218,17 @@ Perl_do_vop(pTHX_ I32 optype, SV *sv, SV *left, SV *right)
len = lensave;
if (rightlen > len)
sv_catpvn_nomg(sv, rsave + len, rightlen - len);
- else if (leftlen > (STRLEN)len)
- sv_catpvn_nomg(sv, lsave + len, leftlen - len);
+ else if (leftlen > (STRLEN)len) {
+ if (sv == left) {
+ /* sv_catpvn() might move the source from under us,
+ and the data is already in place, just adjust to
+ include it */
+ SvCUR_set(sv, leftlen);
+ *SvEND(sv) = '\0';
+ }
+ else
+ sv_catpvn_nomg(sv, lsave + len, leftlen - len);
+ }
else
*SvEND(sv) = '\0';
break;