b8876f
From 0c43d46cd570d2a19edfa54b9c637dea5c0a3514 Mon Sep 17 00:00:00 2001
b8876f
From: Tony Cook <tony@develop-help.com>
b8876f
Date: Thu, 19 Jan 2017 16:28:03 +1100
b8876f
Subject: [PATCH] (perl #129125) copy form data if it might be freed
b8876f
MIME-Version: 1.0
b8876f
Content-Type: text/plain; charset=UTF-8
b8876f
Content-Transfer-Encoding: 8bit
b8876f
b8876f
Ported to 5.24.1:
b8876f
b8876f
commit 86191aed6f092273950ebdd48f886d4ec0c5e85e
b8876f
Author: Tony Cook <tony@develop-help.com>
b8876f
Date:   Thu Jan 19 16:28:03 2017 +1100
b8876f
b8876f
    (perl #129125) copy form data if it might be freed
b8876f
b8876f
    If the format SV also appeared as an argument, and the FF_CHOP
b8876f
    operator modified that argument, the magic and hence the compiled
b8876f
    format would be freed, and the next iteration of the processing
b8876f
    the compiled format would read freed memory.
b8876f
b8876f
    Unlike my original patch this copies the formsv too, since
b8876f
    that is also stored in the magic, and is needed for presenting
b8876f
    literal text from the format.
b8876f
b8876f
Signed-off-by: Petr Písař <ppisar@redhat.com>
b8876f
---
b8876f
 pp_ctl.c     | 18 ++++++++++++++++++
b8876f
 t/op/write.t | 19 ++++++++++++++++++-
b8876f
 2 files changed, 36 insertions(+), 1 deletion(-)
b8876f
b8876f
diff --git a/pp_ctl.c b/pp_ctl.c
b8876f
index b94c09a..e859e01 100644
b8876f
--- a/pp_ctl.c
b8876f
+++ b/pp_ctl.c
b8876f
@@ -490,6 +490,7 @@ PP(pp_formline)
b8876f
     U8 *source;		    /* source of bytes to append */
b8876f
     STRLEN to_copy;	    /* how may bytes to append */
b8876f
     char trans;		    /* what chars to translate */
b8876f
+    bool copied_form = false; /* have we duplicated the form? */
b8876f
 
b8876f
     mg = doparseform(tmpForm);
b8876f
 
b8876f
@@ -687,6 +688,23 @@ PP(pp_formline)
b8876f
 	case FF_CHOP: /* (for ^*) chop the current item */
b8876f
 	    if (sv != &PL_sv_no) {
b8876f
 		const char *s = chophere;
b8876f
+                if (!copied_form &&
b8876f
+                    ((sv == tmpForm || SvSMAGICAL(sv))
b8876f
+                     || (SvGMAGICAL(tmpForm) && !sv_only_taint_gmagic(tmpForm))) ) {
b8876f
+                    /* sv and tmpForm are either the same SV, or magic might allow modification
b8876f
+                       of tmpForm when sv is modified, so copy */
b8876f
+                    SV *newformsv = sv_mortalcopy(formsv);
b8876f
+                    U32 *new_compiled;
b8876f
+
b8876f
+                    f = SvPV_nolen(newformsv) + (f - SvPV_nolen(formsv));
b8876f
+                    Newx(new_compiled, mg->mg_len / sizeof(U32), U32);
b8876f
+                    memcpy(new_compiled, mg->mg_ptr, mg->mg_len);
b8876f
+                    SAVEFREEPV(new_compiled);
b8876f
+                    fpc = new_compiled + (fpc - (U32*)mg->mg_ptr);
b8876f
+                    formsv = newformsv;
b8876f
+
b8876f
+                    copied_form = true;
b8876f
+                }
b8876f
 		if (chopspace) {
b8876f
 		    while (isSPACE(*s))
b8876f
 			s++;
b8876f
diff --git a/t/op/write.t b/t/op/write.t
b8876f
index 590d658..ab2733f 100644
b8876f
--- a/t/op/write.t
b8876f
+++ b/t/op/write.t
b8876f
@@ -98,7 +98,7 @@ for my $tref ( @NumTests ){
b8876f
 my $bas_tests = 21;
b8876f
 
b8876f
 # number of tests in section 3
b8876f
-my $bug_tests = 66 + 3 * 3 * 5 * 2 * 3 + 2 + 66 + 4 + 2 + 3 + 96 + 11 + 3;
b8876f
+my $bug_tests = 66 + 3 * 3 * 5 * 2 * 3 + 2 + 66 + 6 + 2 + 3 + 96 + 11 + 3;
b8876f
 
b8876f
 # number of tests in section 4
b8876f
 my $hmb_tests = 37;
b8876f
@@ -1637,6 +1637,23 @@ printf ">%s<\n", ref $zamm;
b8876f
 print "$zamm->[0]\n";
b8876f
 EOP
b8876f
 
b8876f
+# [perl #129125] - detected by -fsanitize=address or valgrind
b8876f
+# the compiled format would be freed when the format string was modified
b8876f
+# by the chop operator
b8876f
+fresh_perl_is(<<'EOP', "^", { stderr => 1 }, '#129125 - chop on format');
b8876f
+my $x = '^@';
b8876f
+formline$x=>$x;
b8876f
+print $^A;
b8876f
+EOP
b8876f
+
b8876f
+fresh_perl_is(<<'EOP', '<^< xx AA><xx ^<><>', { stderr => 1 }, '#129125 - chop on format, later values');
b8876f
+my $x = '^< xx ^<';
b8876f
+my $y = 'AA';
b8876f
+formline $x => $x, $y;
b8876f
+print "<$^A><$x><$y>";
b8876f
+EOP
b8876f
+
b8876f
+
b8876f
 # [perl #73690]
b8876f
 
b8876f
 select +(select(RT73690), do {
b8876f
-- 
b8876f
2.7.4
b8876f