c1da88
From 900c00b2ae29aa10b5cf0b3b5c55aff7501fc382 Mon Sep 17 00:00:00 2001
c1da88
From: Tony Cook <tony@develop-help.com>
c1da88
Date: Wed, 12 Aug 2020 16:20:16 +1000
c1da88
Subject: [PATCH 3/3] Data::Dumper (XS): use mortals to prevent leaks if magic
c1da88
 throws
c1da88
MIME-Version: 1.0
c1da88
Content-Type: text/plain; charset=UTF-8
c1da88
Content-Transfer-Encoding: 8bit
c1da88
c1da88
For example:
c1da88
c1da88
  use Tie::Scalar;
c1da88
  use Data::Dumper;
c1da88
  sub T::TIESCALAR { bless {}, shift}
c1da88
  sub T::FETCH { die }
c1da88
  my $x;
c1da88
  tie $x, "T" or die;
c1da88
  while(1) {
c1da88
      eval { () = Dumper( [ \$x ] ) };
c1da88
  }
c1da88
c1da88
would leak various work SVs.
c1da88
c1da88
I start a new scope (ENTER/LEAVE) for most recursive DD_dump() calls
c1da88
so that the work SVs don't accumulate on the temps stack, for example
c1da88
if we're dumping a large array we'd end up with several SVs on the
c1da88
temp stack for each member of the array.
c1da88
c1da88
The exceptions are where I don't expect a large number of unreleased
c1da88
temps to accumulate, as with scalar or glob refs.
c1da88
c1da88
Petr Písař: Ported to Data-Dumper-2.173 from
c1da88
815b4be4ab7ae210f796fc9d29754e55fc0d1f0e perl commit.
c1da88
c1da88
Signed-off-by: Petr Písař <ppisar@redhat.com>
c1da88
---
c1da88
 Dumper.xs | 52 ++++++++++++++++++++++++++++------------------------
c1da88
 1 file changed, 28 insertions(+), 24 deletions(-)
c1da88
c1da88
diff --git a/Dumper.xs b/Dumper.xs
c1da88
index d4b34ad..65639ae 100644
c1da88
--- a/Dumper.xs
c1da88
+++ b/Dumper.xs
c1da88
@@ -808,12 +808,13 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 	    sv_catpvs(retval, "( ");
c1da88
             if (style->indent >= 2) {
c1da88
 		blesspad = apad;
c1da88
-		apad = newSVsv(apad);
c1da88
+		apad = sv_2mortal(newSVsv(apad));
c1da88
 		sv_x(aTHX_ apad, " ", 1, blesslen+2);
c1da88
 	    }
c1da88
 	}
c1da88
 
c1da88
         ipad = sv_x(aTHX_ Nullsv, SvPVX_const(style->xpad), SvCUR(style->xpad), level+1);
c1da88
+        sv_2mortal(ipad);
c1da88
 
c1da88
         if (is_regex) 
c1da88
         {
c1da88
@@ -878,7 +879,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 		realtype <= SVt_PVMG
c1da88
 #endif
c1da88
 	) {			     /* scalar ref */
c1da88
-	    SV * const namesv = newSVpvs("${");
c1da88
+	    SV * const namesv = sv_2mortal(newSVpvs("${"));
c1da88
 	    sv_catpvn(namesv, name, namelen);
c1da88
 	    sv_catpvs(namesv, "}");
c1da88
 	    if (realpack) {				     /* blessed */
c1da88
@@ -892,7 +893,6 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 		DD_dump(aTHX_ ival, SvPVX_const(namesv), SvCUR(namesv), retval, seenhv,
c1da88
 			postav, level+1, apad, style);
c1da88
 	    }
c1da88
-	    SvREFCNT_dec(namesv);
c1da88
 	}
c1da88
 	else if (realtype == SVt_PVGV) {		     /* glob ref */
c1da88
 	    SV * const namesv = newSVpvs("*{");
c1da88
@@ -908,9 +908,10 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 	    SSize_t ix = 0;
c1da88
 	    const SSize_t ixmax = av_len((AV *)ival);
c1da88
 	
c1da88
-	    SV * const ixsv = newSViv(0);
c1da88
+	    SV * const ixsv = sv_2mortal(newSViv(0));
c1da88
 	    /* allowing for a 24 char wide array index */
c1da88
 	    New(0, iname, namelen+28, char);
c1da88
+            SAVEFREEPV(iname);
c1da88
 	    (void) strlcpy(iname, name, namelen+28);
c1da88
 	    inamelen = namelen;
c1da88
 	    if (name[0] == '@') {
c1da88
@@ -940,7 +941,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 		iname[inamelen++] = '-'; iname[inamelen++] = '>';
c1da88
 	    }
c1da88
 	    iname[inamelen++] = '['; iname[inamelen] = '\0';
c1da88
-            totpad = newSVsv(style->sep);
c1da88
+            totpad = sv_2mortal(newSVsv(style->sep));
c1da88
             sv_catsv(totpad, style->pad);
c1da88
 	    sv_catsv(totpad, apad);
c1da88
 
c1da88
@@ -970,8 +971,12 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 		}
c1da88
 		sv_catsv(retval, totpad);
c1da88
 		sv_catsv(retval, ipad);
c1da88
+                ENTER;
c1da88
+                SAVETMPS;
c1da88
 		DD_dump(aTHX_ elem, iname, ilen, retval, seenhv, postav,
c1da88
 			level+1, apad, style);
c1da88
+                FREETMPS;
c1da88
+                LEAVE;
c1da88
 		if (ix < ixmax || (style->trailingcomma && style->indent >= 1))
c1da88
 		    sv_catpvs(retval, ",");
c1da88
 	    }
c1da88
@@ -985,9 +990,6 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 		sv_catpvs(retval, ")");
c1da88
 	    else
c1da88
 		sv_catpvs(retval, "]");
c1da88
-	    SvREFCNT_dec(ixsv);
c1da88
-	    SvREFCNT_dec(totpad);
c1da88
-	    Safefree(iname);
c1da88
 	}
c1da88
 	else if (realtype == SVt_PVHV) {
c1da88
 	    SV *totpad, *newapad;
c1da88
@@ -997,7 +999,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 	    SV *hval;
c1da88
 	    AV *keys = NULL;
c1da88
 	
c1da88
-	    SV * const iname = newSVpvn(name, namelen);
c1da88
+	    SV * const iname = newSVpvn_flags(name, namelen, SVs_TEMP);
c1da88
 	    if (name[0] == '%') {
c1da88
 		sv_catpvs(retval, "(");
c1da88
 		(SvPVX(iname))[0] = '$';
c1da88
@@ -1021,7 +1023,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 		sv_catpvs(iname, "->");
c1da88
 	    }
c1da88
 	    sv_catpvs(iname, "{");
c1da88
-            totpad = newSVsv(style->sep);
c1da88
+            totpad = sv_2mortal(newSVsv(style->sep));
c1da88
             sv_catsv(totpad, style->pad);
c1da88
 	    sv_catsv(totpad, apad);
c1da88
 	
c1da88
@@ -1117,6 +1119,10 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 
c1da88
                 sv_catsv(retval, totpad);
c1da88
                 sv_catsv(retval, ipad);
c1da88
+
c1da88
+                ENTER;
c1da88
+                SAVETMPS;
c1da88
+
c1da88
                 /* The (very)
c1da88
                    old logic was first to check utf8 flag, and if utf8 always
c1da88
                    call esc_q_utf8.  This caused test to break under -Mutf8,
c1da88
@@ -1143,6 +1149,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
                     else {
c1da88
 		        nticks = num_q(key, klen);
c1da88
 			New(0, nkey_buffer, klen+nticks+3, char);
c1da88
+                        SAVEFREEPV(nkey_buffer);
c1da88
                         nkey = nkey_buffer;
c1da88
 			nkey[0] = '\'';
c1da88
 			if (nticks)
c1da88
@@ -1160,7 +1167,8 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
                     nlen = klen;
c1da88
                     sv_catpvn(retval, nkey, klen);
c1da88
 		}
c1da88
-                sname = newSVsv(iname);
c1da88
+
c1da88
+                sname = sv_2mortal(newSVsv(iname));
c1da88
                 sv_catpvn(sname, nkey, nlen);
c1da88
                 sv_catpvs(sname, "}");
c1da88
 
c1da88
@@ -1168,7 +1176,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
                 if (style->indent >= 2) {
c1da88
 		    char *extra;
c1da88
                     STRLEN elen = 0;
c1da88
-		    newapad = newSVsv(apad);
c1da88
+		    newapad = sv_2mortal(newSVsv(apad));
c1da88
 		    New(0, extra, klen+4+1, char);
c1da88
 		    while (elen < (klen+4))
c1da88
 			extra[elen++] = ' ';
c1da88
@@ -1181,10 +1189,9 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 
c1da88
 		DD_dump(aTHX_ hval, SvPVX_const(sname), SvCUR(sname), retval, seenhv,
c1da88
 			postav, level+1, newapad, style);
c1da88
-		SvREFCNT_dec(sname);
c1da88
-		Safefree(nkey_buffer);
c1da88
-                if (style->indent >= 2)
c1da88
-		    SvREFCNT_dec(newapad);
c1da88
+
c1da88
+                FREETMPS;
c1da88
+                LEAVE;
c1da88
 	    }
c1da88
 	    if (i) {
c1da88
                 SV *opad = sv_x(aTHX_ Nullsv, SvPVX_const(style->xpad),
c1da88
@@ -1199,8 +1206,6 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 		sv_catpvs(retval, ")");
c1da88
 	    else
c1da88
 		sv_catpvs(retval, "}");
c1da88
-	    SvREFCNT_dec(iname);
c1da88
-	    SvREFCNT_dec(totpad);
c1da88
 	}
c1da88
 	else if (realtype == SVt_PVCV) {
c1da88
             if (style->deparse) {
c1da88
@@ -1247,7 +1252,6 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
             STRLEN plen, pticks;
c1da88
 
c1da88
             if (style->indent >= 2) {
c1da88
-		SvREFCNT_dec(apad);
c1da88
 		apad = blesspad;
c1da88
 	    }
c1da88
 	    sv_catpvs(retval, ", '");
c1da88
@@ -1276,7 +1280,6 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
c1da88
 		sv_catpvs(retval, "()");
c1da88
 	    }
c1da88
 	}
c1da88
-	SvREFCNT_dec(ipad);
c1da88
     }
c1da88
     else {
c1da88
 	STRLEN i;
c1da88
@@ -1671,20 +1674,21 @@ Data_Dumper_Dumpxs(href, ...)
c1da88
 		
c1da88
                     if (style.indent >= 2 && !terse) {
c1da88
 			SV * const tmpsv = sv_x(aTHX_ NULL, " ", 1, SvCUR(name)+3);
c1da88
-			newapad = newSVsv(apad);
c1da88
+			newapad = sv_2mortal(newSVsv(apad));
c1da88
 			sv_catsv(newapad, tmpsv);
c1da88
 			SvREFCNT_dec(tmpsv);
c1da88
 		    }
c1da88
 		    else
c1da88
 			newapad = apad;
c1da88
 		
c1da88
+                    ENTER;
c1da88
+                    SAVETMPS;
c1da88
 		    PUTBACK;
c1da88
 		    DD_dump(aTHX_ val, SvPVX_const(name), SvCUR(name), valstr, seenhv,
c1da88
                             postav, 0, newapad, &style);
c1da88
 		    SPAGAIN;
c1da88
-
c1da88
-                    if (style.indent >= 2 && !terse)
c1da88
-			SvREFCNT_dec(newapad);
c1da88
+                    FREETMPS;
c1da88
+                    LEAVE;
c1da88
 
c1da88
 		    postlen = av_len(postav);
c1da88
 		    if (postlen >= 0 || !terse) {
c1da88
-- 
c1da88
2.25.4
c1da88