Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PATCH] Started work on "Remove the use of SVs as temporaries in dump.c" #14001

Closed
p5pRT opened this issue Jul 25, 2014 · 26 comments
Closed

[PATCH] Started work on "Remove the use of SVs as temporaries in dump.c" #14001

p5pRT opened this issue Jul 25, 2014 · 26 comments
Labels

Comments

@p5pRT
Copy link

p5pRT commented Jul 25, 2014

Migrated from rt.perl.org#122405 (status was 'rejected')

Searchable as RT122405$

@p5pRT
Copy link
Author

p5pRT commented Jul 25, 2014

From creaktive@gmail.com

Picked this yak from Porting/todo.pod :)
This is a work in progress, some functions still use newSV*.
Also, a cleanup is planned (_sv_catpv/_sv_cpypv macros will be removed).


AUTHORS | 1 +
dump.c | 599
+++++++++++++++++++++++++++++++++++---------------------------
embed.fnc | 1 +
embed.h | 1 +
proto.h | 6 +
utf8.c | 118 ++++++++-----
6 files changed, 421 insertions(+), 305 deletions(-)

Inline Patch
diff --git a/AUTHORS b/AUTHORS
index 9db941e..80c4cf1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1088,6 +1088,7 @@ Solar Designer <solar@openwall.com>
 Spider Boardman <spider@orb.nashua.nh.us>
 Spiros Denaxas <s.denaxas@gmail.com>
 Sreeji K Das <sreeji_k@yahoo.com>
+Stanislaw Pusep <creaktive@gmail.com>
 Stas Bekman <stas@stason.org>
 Steffen Müller <smueller@cpan.org>
 Steffen Schwigon <ss5@renormalist.net>
diff --git a/dump.c b/dump.c
index d15aee6..c368794 100644
--- a/dump.c
+++ b/dump.c
@@ -73,20 +73,24 @@ struct flag_to_name {
     const char *name;
 };

+#define DO_SV_DUMP_BUFSIZE 5120
+#define _sv_catpv(d, s)     (my_strlcat(d, s, DO_SV_DUMP_BUFSIZE))
+#define _sv_setpv(d, s)     (my_strlcpy(d, s, DO_SV_DUMP_BUFSIZE))
+
 static void
-S_append_flags(pTHX_ SV *sv, U32 flags, const struct flag_to_name *start,
-       const struct flag_to_name *const end)
+S_append_flags(char *s, U32 flags, const struct flag_to_name *start,
+        const struct flag_to_name *const end)
 {
     do {
- if (flags & start->flag)
-    sv_catpv(sv, start->name);
+        if (flags & start->flag)
+            _sv_catpv(s, start->name);
     } while (++start < end);
 }

-#define append_flags(sv, f, flags) \
-    S_append_flags(aTHX_ (sv), (f), (flags), C_ARRAY_END(flags))
+#define append_flags(s, f, flags) \
+    S_append_flags((s), (f), (flags), C_ARRAY_END(flags))

-#define generic_pv_escape(sv,s,len,utf8) pv_escape( (sv), (s), (len), \
+#define generic_pv_escape(sv,s,len,utf8) _pv_escape( aTHX_ (sv), (s),
(len), \   \(len\) \* \(4\+UTF8\_MAXBYTES\) \+ 1\, NULL\, \\   PERL\_PV\_ESCAPE\_NONASCII | PERL\_PV\_ESCAPE\_DWIM \\   | \(\(utf8\) ? PERL\_PV\_ESCAPE\_UNI : 0\) \) @​@​ \-134\,10 \+138\,11 @​@​ Returns a pointer to the escaped text as held by dsv\. \#define PV\_ESCAPE\_OCTBUFSIZE 32

char *
-Perl_pv_escape( pTHX_ SV *dsv, char const * const str,
- const STRLEN count, const STRLEN max,
- STRLEN * const escaped, const U32 flags )
+_pv_escape( pTHX_ char *dsv, char const * const str,
+ const STRLEN count, const STRLEN max,
+ STRLEN * const escaped, const U32 flags )
{
+ char buf[PV_ESCAPE_OCTBUFSIZE];
  const char esc = (flags & PERL_PV_ESCAPE_RE) ? '%' : '\\';
  const char dq = (flags & PERL_PV_ESCAPE_QUOTE) ? '"' : esc;
  char octbuf[PV_ESCAPE_OCTBUFSIZE] = "%123456789ABCDF";
@​@​ -149,95 +154,111 @​@​ Perl_pv_escape( pTHX_ SV *dsv, char const * const
str,
  const char * const end = pv + count; /* end of string */
  octbuf[0] = esc;

- PERL_ARGS_ASSERT_PV_ESCAPE;
-
- if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) {
- /* This won't alter the UTF-8 flag */
- sv_setpvs(dsv, "");
- }
-
  if ((flags & PERL_PV_ESCAPE_UNI_DETECT) && is_utf8_string((U8*)pv,
count))
  isuni = 1;
-
+
  for ( ; (pv < end && (!max || (wrote < max))) ; pv += readsize ) {
  const UV u= (isuni) ? utf8_to_uvchr_buf((U8*)pv, (U8*) end,
&readsize) : (U8)*pv;
  const U8 c = (U8)u & 0xFF;
-
+
  if ( ( u > 255 )
- || (flags & PERL_PV_ESCAPE_ALL)
- || (( ! isASCII(u) ) && (flags &
(PERL_PV_ESCAPE_NONASCII|PERL_PV_ESCAPE_DWIM))))
- {
- if (flags & PERL_PV_ESCAPE_FIRSTCHAR)
- chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
- "%"UVxf, u);
+ || (flags & PERL_PV_ESCAPE_ALL)
+ || (( ! isASCII(u) ) && (flags &
(PERL_PV_ESCAPE_NONASCII|PERL_PV_ESCAPE_DWIM))))
+ {
+ if (flags & PERL_PV_ESCAPE_FIRSTCHAR)
+ chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
+ "%"UVxf, u);
  else
- chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
- ((flags & PERL_PV_ESCAPE_DWIM) &&
!isuni)
- ? "%cx%02"UVxf
- : "%cx{%02"UVxf"}", esc, u);
+ chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
+ ((flags & PERL_PV_ESCAPE_DWIM) && !isuni)
+ ? "%cx%02"UVxf
+ : "%cx{%02"UVxf"}", esc, u);

  } else if (flags & PERL_PV_ESCAPE_NOBACKSLASH) {
- chsize = 1;
- } else {
+ chsize = 1;
+ } else {
  if ( (c == dq) || (c == esc) || !isPRINT(c) ) {
- chsize = 2;
+ chsize = 2;
  switch (c) {
-
- case '\\' : /* FALLTHROUGH */
- case '%' : if ( c == esc ) {
- octbuf[1] = esc;
- } else {
- chsize = 1;
- }
- break;
- case '\v' : octbuf[1] = 'v'; break;
- case '\t' : octbuf[1] = 't'; break;
- case '\r' : octbuf[1] = 'r'; break;
- case '\n' : octbuf[1] = 'n'; break;
- case '\f' : octbuf[1] = 'f'; break;
- case '"' :
- if ( dq == '"' )
- octbuf[1] = '"';
- else
- chsize = 1;
- break;
- default​:
- if ( (flags & PERL_PV_ESCAPE_DWIM) && c != '\0' ) {
- chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
- isuni ? "%cx{%02"UVxf"}" :
"%cx%02"UVxf,
- esc, u);
- }
- else if ( (pv+readsize < end) &&
isDIGIT((U8)*(pv+readsize)) )
- chsize = my_snprintf( octbuf,
PV_ESCAPE_OCTBUFSIZE,
- "%c%03o", esc, c);
- else
- chsize = my_snprintf( octbuf,
PV_ESCAPE_OCTBUFSIZE,
- "%c%o", esc, c);
+
+ case '\\' : /* FALLTHROUGH */
+ case '%' : if ( c == esc ) {
+ octbuf[1] = esc;
+ } else {
+ chsize = 1;
+ }
+ break;
+ case '\v' : octbuf[1] = 'v'; break;
+ case '\t' : octbuf[1] = 't'; break;
+ case '\r' : octbuf[1] = 'r'; break;
+ case '\n' : octbuf[1] = 'n'; break;
+ case '\f' : octbuf[1] = 'f'; break;
+ case '"' :
+ if ( dq == '"' )
+ octbuf[1] = '"';
+ else
+ chsize = 1;
+ break;
+ default​:
+ if ( (flags & PERL_PV_ESCAPE_DWIM) && c !=
'\0' ) {
+ chsize = my_snprintf( octbuf,
PV_ESCAPE_OCTBUFSIZE,
+ isuni ? "%cx{%02"UVxf"}" :
"%cx%02"UVxf,
+ esc, u);
+ }
+ else if ( (pv+readsize < end) &&
isDIGIT((U8)*(pv+readsize)) )
+ chsize = my_snprintf( octbuf,
PV_ESCAPE_OCTBUFSIZE,
+ "%c%03o", esc, c);
+ else
+ chsize = my_snprintf( octbuf,
PV_ESCAPE_OCTBUFSIZE,
+ "%c%o", esc, c);
  }
  } else {
  chsize = 1;
  }
- }
- if ( max && (wrote + chsize > max) ) {
- break;
+ }
+ if ( max && (wrote + chsize > max) ) {
+ break;
  } else if (chsize > 1) {
- sv_catpvn(dsv, octbuf, chsize);
+ my_strlcpy(buf, "", 1);
+ my_strlcpy(buf, octbuf, chsize + 1);
+ _sv_catpv(dsv, buf);
  wrote += chsize;
- } else {
- /* If PERL_PV_ESCAPE_NOBACKSLASH is set then non-ASCII bytes
- can be appended raw to the dsv. If dsv happens to be
- UTF-8 then we need catpvf to upgrade them for us.
- Or add a new API call sv_catpvc(). Think about that name, and
- how to keep it clear that it's unlike the s of catpvs, which is
- really an array of octets, not a string. */
- Perl_sv_catpvf( aTHX_ dsv, "%c", c);
- wrote++;
- }
- if ( flags & PERL_PV_ESCAPE_FIRSTCHAR )
+ } else {
+ /* If PERL_PV_ESCAPE_NOBACKSLASH is set then non-ASCII bytes
+ can be appended raw to the dsv. If dsv happens to be
+ UTF-8 then we need catpvf to upgrade them for us.
+ Or add a new API call sv_catpvc(). Think about that name,
and
+ how to keep it clear that it's unlike the s of catpvs,
which is
+ really an array of octets, not a string. */
+ my_snprintf(buf, sizeof(buf), "%c", c);
+ _sv_catpv(dsv, buf);
+ wrote++;
+ }
+ if ( flags & PERL_PV_ESCAPE_FIRSTCHAR )
  break;
  }
  if (escaped != NULL)
  *escaped= pv - str;
+ return dsv;
+}
+
+char *
+Perl_pv_escape( pTHX_ SV *dsv, char const * const str,
+ const STRLEN count, const STRLEN max,
+ STRLEN * const escaped, const U32 flags )
+{
+ char *buf;
+ PERL_ARGS_ASSERT_PV_ESCAPE;
+
+ if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) {
+ /* This won't alter the UTF-8 flag */
+ sv_setpvs(dsv, "");
+ }
+
+ Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
+ sv_catpv(dsv, _pv_escape(aTHX_ buf, str, count, max, escaped, flags));
+ Safefree(buf);
+
  return SvPVX(dsv);
}
/*
@​@​ -266,44 +287,56 @​@​ Returns a pointer to the prettified text as held by
dsv.
*/

char *
-Perl_pv_pretty( pTHX_ SV *dsv, char const * const str, const STRLEN count,
- const STRLEN max, char const * const start_color, char const * const
end_color,
- const U32 flags )
+_pv_pretty( pTHX_ char *dsv, char const * const str, const STRLEN count,
+ const STRLEN max, char const * const start_color, char const *
const end_color,
+ const U32 flags )
{
  const U8 dq = (flags & PERL_PV_PRETTY_QUOTE) ? '"' : '%';
  STRLEN escaped;
-
- PERL_ARGS_ASSERT_PV_PRETTY;
-
- if (!(flags & PERL_PV_PRETTY_NOCLEAR)) {
- /* This won't alter the UTF-8 flag */
- sv_setpvs(dsv, "");
- }

  if ( dq == '"' )
- sv_catpvs(dsv, "\"");
+ _sv_catpv(dsv, "\"");
  else if ( flags & PERL_PV_PRETTY_LTGT )
- sv_catpvs(dsv, "<");
-
- if ( start_color != NULL )
- sv_catpv(dsv, start_color);
-
- pv_escape( dsv, str, count, max, &escaped, flags |
PERL_PV_ESCAPE_NOCLEAR );
-
- if ( end_color != NULL )
- sv_catpv(dsv, end_color);
-
- if ( dq == '"' )
- sv_catpvs( dsv, "\"");
+ _sv_catpv(dsv, "<");
+
+ if ( start_color != NULL )
+ _sv_catpv(dsv, start_color);
+
+ _pv_escape( aTHX_ dsv, str, count, max, &escaped, flags );
+
+ if ( end_color != NULL )
+ _sv_catpv(dsv, end_color);
+
+ if ( dq == '"' )
+ _sv_catpv( dsv, "\"");
  else if ( flags & PERL_PV_PRETTY_LTGT )
- sv_catpvs(dsv, ">");
-
+ _sv_catpv(dsv, ">");
+
  if ( (flags & PERL_PV_PRETTY_ELLIPSES) && ( escaped < count ) )
- sv_catpvs(dsv, "...");
-
- return SvPVX(dsv);
+ _sv_catpv(dsv, "...");
+
+ return dsv;
}

+char *
+Perl_pv_pretty( pTHX_ SV *dsv, char const * const str, const STRLEN count,
+ const STRLEN max, char const * const start_color, char const * const
end_color,
+ const U32 flags )
+{
+ char *buf;
+ PERL_ARGS_ASSERT_PV_PRETTY;
+
+ if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) {
+ /* This won't alter the UTF-8 flag */
+ sv_setpvs(dsv, "");
+ }
+
+ Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
+ sv_catpv(dsv, _pv_pretty(aTHX_ buf, str, count, max, start_color,
end_color, flags));
+ Safefree(buf);
+
+ return SvPVX(dsv);
+}
/*
=for apidoc pv_display

@​@​ -320,17 +353,39 @​@​ Note that the final string may be up to 7 chars
longer than pvlim.
*/

char *
+_pv_display( pTHX_ char *dsv, const char *pv, STRLEN cur, STRLEN len,
STRLEN pvlim)
+{
+ _sv_setpv(dsv, "");
+ _pv_pretty( aTHX_ dsv, pv, cur, pvlim, NULL, NULL,
PERL_PV_PRETTY_DUMP);
+ if (len > cur && pv[cur] == '\0')
+ _sv_catpv( dsv, "\\0");
+ return dsv;
+}
+
+char *
Perl_pv_display(pTHX_ SV *dsv, const char *pv, STRLEN cur, STRLEN len,
STRLEN pvlim)
{
+ char *buf;
  PERL_ARGS_ASSERT_PV_DISPLAY;

- pv_pretty( dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP);
- if (len > cur && pv[cur] == '\0')
- sv_catpvs( dsv, "\\0");
+ Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
+ sv_setpv(dsv, _pv_display(aTHX_ buf, pv, cur, len, pvlim));
+ Safefree(buf);
+
  return SvPVX(dsv);
}

char *
+_sv_uni_display( pTHX_ char *dest, SV *ssv, STRLEN pvlim, UV flags)
+{
+ STRLEN len = SvCUR(ssv);
+ U8 *spv = (U8 *)
+ (isREGEXP(ssv) ? RX_WRAPPED((REGEXP*)ssv) : SvPVX_const(ssv));
+
+ return str_uni_display(dest, DO_SV_DUMP_BUFSIZE, spv, len, pvlim,
flags);
+}
+
+char *
Perl_sv_peek(pTHX_ SV *sv)
{
  dVAR;
@​@​ -421,11 +476,12 @​@​ Perl_sv_peek(pTHX_ SV *sv)
  }
  type = SvTYPE(sv);
  if (type == SVt_PVCV) {
- SV * const tmp = newSVpvs_flags("", SVs_TEMP);
  GV* gvcv = CvGV(sv);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_sv_catpvf(aTHX_ t, "CV(%s)", gvcv
  ? generic_pv_escape( tmp, GvNAME(gvcv),
GvNAMELEN(gvcv), GvNAMEUTF8(gvcv))
  : "");
+ Safefree(tmp);
  goto finish;
  } else if (type < SVt_LAST) {
  sv_catpv(t, svshorttypenames[type]);
@​@​ -580,19 +636,19 @​@​ Perl_dump_sub_perl(pTHX_ const GV *gv, bool justperl)
{
  STRLEN len;
  SV * const sv = newSVpvs_flags("", SVs_TEMP);
- SV *tmpsv;
  const char * name;
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);

  PERL_ARGS_ASSERT_DUMP_SUB_PERL;

  if (justperl && (CvISXSUB(GvCV(gv)) || !CvROOT(GvCV(gv))))
  return;

- tmpsv = newSVpvs_flags("", SVs_TEMP);
  gv_fullname3(sv, gv, NULL);
  name = SvPV_const(sv, len);
  Perl_dump_indent(aTHX_ 0, Perl_debug_log, "\nSUB %s = ",
- generic_pv_escape(tmpsv, name, len, SvUTF8(sv)));
+ generic_pv_escape(tmp, name, len, SvUTF8(sv)));
+ Safefree(tmp);
  if (CvISXSUB(GvCV(gv)))
  Perl_dump_indent(aTHX_ 0, Perl_debug_log, "(xsub 0x%"UVxf" %d)\n",
  PTR2UV(CvXSUB(GvCV(gv))),
@​@​ -685,37 +741,42 @​@​ const struct flag_to_name pmflags_flags_names[] = {
static SV *
S_pm_description(pTHX_ const PMOP *pm)
{
- SV * const desc = newSVpvs("");
+ char *desc;
+ SV *sv;
  const REGEXP * const regex = PM_GETRE(pm);
  const U32 pmflags = pm->op_pmflags;

  PERL_ARGS_ASSERT_PM_DESCRIPTION;

+ Newxz(desc, DO_SV_DUMP_BUFSIZE, char);
+
  if (pmflags & PMf_ONCE)
- sv_catpv(desc, ",ONCE");
+ _sv_catpv(desc, ",ONCE");
#ifdef USE_ITHREADS
  if (SvREADONLY(PL_regex_pad[pm->op_pmoffset]))
- sv_catpv(desc, "​:USED");
+ _sv_catpv(desc, "​:USED");
#else
  if (pmflags & PMf_USED)
- sv_catpv(desc, "​:USED");
+ _sv_catpv(desc, "​:USED");
#endif

  if (regex) {
  if (RX_ISTAINTED(regex))
- sv_catpv(desc, ",TAINTED");
+ _sv_catpv(desc, ",TAINTED");
  if (RX_CHECK_SUBSTR(regex)) {
  if (!(RX_INTFLAGS(regex) & PREGf_NOSCAN))
- sv_catpv(desc, ",SCANFIRST");
+ _sv_catpv(desc, ",SCANFIRST");
  if (RX_EXTFLAGS(regex) & RXf_CHECK_ALL)
- sv_catpv(desc, ",ALL");
+ _sv_catpv(desc, ",ALL");
  }
  if (RX_EXTFLAGS(regex) & RXf_SKIPWHITE)
- sv_catpv(desc, ",SKIPWHITE");
+ _sv_catpv(desc, ",SKIPWHITE");
  }

  append_flags(desc, pmflags, pmflags_flags_names);
- return desc;
+ sv = newSVpv(desc, 0);
+ Safefree(desc);
+ return sv;
}

void
@​@​ -863,57 +924,58 @​@​ const struct op_private_by_op op_private_names[] = {
};

static bool
-S_op_private_to_names(pTHX_ SV *tmpsv, U32 optype, U32 op_private) {
+S_op_private_to_names(char *tmp, U32 optype, U32 op_private) {
  const struct op_private_by_op *start = op_private_names;
  const struct op_private_by_op *const end =
C_ARRAY_END(op_private_names);

  /* This is a linear search, but no worse than the code that it
replaced.
  It's debugging code - size is more important than speed. */
  do {
- if (optype == start->op_type) {
- S_append_flags(aTHX_ tmpsv, op_private, start->start,
- start->start + start->len);
- return TRUE;
- }
+ if (optype == start->op_type) {
+ S_append_flags(tmp, op_private, start->start,
+ start->start + start->len);
+ return TRUE;
+ }
  } while (++start < end);
  return FALSE;
}

#define DUMP_OP_FLAGS(o,level,file) \
  if (o->op_flags || o->op_slabbed || o->op_savefree || o->op_static) { \
- SV * const tmpsv = newSVpvs(""); \
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char); \
  switch (o->op_flags & OPf_WANT) { \
  case OPf_WANT_VOID​: \
- sv_catpv(tmpsv, ",VOID"); \
+ _sv_catpv(tmp, ",VOID"); \
  break; \
  case OPf_WANT_SCALAR​: \
- sv_catpv(tmpsv, ",SCALAR"); \
+ _sv_catpv(tmp, ",SCALAR"); \
  break; \
  case OPf_WANT_LIST​: \
- sv_catpv(tmpsv, ",LIST"); \
+ _sv_catpv(tmp, ",LIST"); \
  break; \
  default​: \
- sv_catpv(tmpsv, ",UNKNOWN"); \
+ _sv_catpv(tmp, ",UNKNOWN"); \
  break; \
  } \
- append_flags(tmpsv, o->op_flags, op_flags_names); \
- if (o->op_slabbed) sv_catpvs(tmpsv, ",SLABBED"); \
- if (o->op_savefree) sv_catpvs(tmpsv, ",SAVEFREE"); \
- if (o->op_static) sv_catpvs(tmpsv, ",STATIC"); \
- if (o->op_folded) sv_catpvs(tmpsv, ",FOLDED"); \
- if (o->op_lastsib) sv_catpvs(tmpsv, ",LASTSIB"); \
+ append_flags(tmp, o->op_flags, op_flags_names); \
+ if (o->op_slabbed) _sv_catpv(tmp, ",SLABBED"); \
+ if (o->op_savefree) _sv_catpv(tmp, ",SAVEFREE"); \
+ if (o->op_static) _sv_catpv(tmp, ",STATIC"); \
+ if (o->op_folded) _sv_catpv(tmp, ",FOLDED"); \
+ if (o->op_lastsib) _sv_catpv(tmp, ",LASTSIB"); \
  Perl_dump_indent(aTHX_ level, file, "FLAGS = (%s)\n", \
- SvCUR(tmpsv) ? SvPVX_const(tmpsv) + 1 : ""); \
+ strlen(tmp) ? tmp + 1 : ""); \
  }

#define DUMP_OP_PRIVATE(o,level,file) \
  if (o->op_private) { \
  U32 optype = o->op_type; \
  U32 oppriv = o->op_private; \
- SV * const tmpsv = newSVpvs(""); \
+ char *tmp, tmp2[PV_ESCAPE_OCTBUFSIZE]; \
+ Newxz(tmp, DO_SV_DUMP_BUFSIZE, char); \
  if (PL_opargs[optype] & OA_TARGLEX) { \
  if (oppriv & OPpTARGET_MY) \
- sv_catpv(tmpsv, ",TARGET_MY"); \
+ _sv_catpv(tmp, ",TARGET_MY"); \
  } \
  else if (optype == OP_ENTERSUB || \
  optype == OP_RV2SV || \
@​@​ -925,70 +987,72 @​@​ S_op_private_to_names(pTHX_ SV *tmpsv, U32 optype,
U32 op_private) {
  optype == OP_HELEM ) \
  { \
  if (optype == OP_ENTERSUB) { \
- append_flags(tmpsv, oppriv, op_entersub_names); \
+ append_flags(tmp, oppriv, op_entersub_names); \
  } \
  else { \
  switch (oppriv & OPpDEREF) { \
  case OPpDEREF_SV​: \
- sv_catpv(tmpsv, ",SV"); \
+ _sv_catpv(tmp, ",SV"); \
  break; \
  case OPpDEREF_AV​: \
- sv_catpv(tmpsv, ",AV"); \
+ _sv_catpv(tmp, ",AV"); \
  break; \
  case OPpDEREF_HV​: \
- sv_catpv(tmpsv, ",HV"); \
+ _sv_catpv(tmp, ",HV"); \
  break; \
  } \
  if (oppriv & OPpMAYBE_LVSUB) \
- sv_catpv(tmpsv, ",MAYBE_LVSUB"); \
+ _sv_catpv(tmp, ",MAYBE_LVSUB"); \
  } \
  if (optype == OP_AELEM || optype == OP_HELEM) { \
  if (oppriv & OPpLVAL_DEFER) \
- sv_catpv(tmpsv, ",LVAL_DEFER"); \
+ _sv_catpv(tmp, ",LVAL_DEFER"); \
  } \
  else if (optype == OP_RV2HV || optype == OP_PADHV) { \
  if (oppriv & OPpMAYBE_TRUEBOOL) \
- sv_catpvs(tmpsv, ",OPpMAYBE_TRUEBOOL"); \
+ _sv_catpv(tmp, ",OPpMAYBE_TRUEBOOL"); \
  if (oppriv & OPpTRUEBOOL) \
- sv_catpvs(tmpsv, ",OPpTRUEBOOL"); \
+ _sv_catpv(tmp, ",OPpTRUEBOOL"); \
  } \
  else { \
  if (oppriv & HINT_STRICT_REFS) \
- sv_catpv(tmpsv, ",STRICT_REFS"); \
+ _sv_catpv(tmp, ",STRICT_REFS"); \
  if (oppriv & OPpOUR_INTRO) \
- sv_catpv(tmpsv, ",OUR_INTRO"); \
+ _sv_catpv(tmp, ",OUR_INTRO"); \
  } \
  } \
- else if (S_op_private_to_names(aTHX_ tmpsv, optype, oppriv)) { \
+ else if (S_op_private_to_names(tmp, optype, oppriv)) { \
  } \
  else if (OP_IS_FILETEST(o->op_type)) { \
  if (oppriv & OPpFT_ACCESS) \
- sv_catpv(tmpsv, ",FT_ACCESS"); \
+ _sv_catpv(tmp, ",FT_ACCESS"); \
  if (oppriv & OPpFT_STACKED) \
- sv_catpv(tmpsv, ",FT_STACKED"); \
+ _sv_catpv(tmp, ",FT_STACKED"); \
  if (oppriv & OPpFT_STACKING) \
- sv_catpv(tmpsv, ",FT_STACKING"); \
+ _sv_catpv(tmp, ",FT_STACKING"); \
  if (oppriv & OPpFT_AFTER_t) \
- sv_catpv(tmpsv, ",AFTER_t"); \
+ _sv_catpv(tmp, ",AFTER_t"); \
  } \
  else if (o->op_type == OP_AASSIGN) { \
  if (oppriv & OPpASSIGN_COMMON) \
- sv_catpvs(tmpsv, ",COMMON"); \
+ _sv_catpv(tmp, ",COMMON"); \
  if (oppriv & OPpMAYBE_LVSUB) \
- sv_catpvs(tmpsv, ",MAYBE_LVSUB"); \
+ _sv_catpv(tmp, ",MAYBE_LVSUB"); \
  } \
  if (o->op_flags & OPf_MOD && oppriv & OPpLVAL_INTRO) \
- sv_catpv(tmpsv, ",INTRO"); \
- if (o->op_type == OP_PADRANGE) \
- Perl_sv_catpvf(aTHX_ tmpsv, ",COUNT=%"UVuf, \
+ _sv_catpv(tmp, ",INTRO"); \
+ if (o->op_type == OP_PADRANGE) { \
+ my_snprintf(tmp2, sizeof(tmp2), ",COUNT=%"UVuf, \
  (UV)(oppriv & OPpPADRANGE_COUNTMASK)); \
+ _sv_catpv(tmp, tmp2); \
+ } \
  if ( (o->op_type == OP_RV2HV || o->op_type == OP_RV2AV || \
  o->op_type == OP_PADAV || o->op_type == OP_PADHV || \
  o->op_type == OP_ASLICE || o->op_type == OP_HSLICE) \
  && oppriv & OPpSLICEWARNING ) \
- sv_catpvs(tmpsv, ",SLICEWARNING"); \
- if (SvCUR(tmpsv)) { \
- Perl_dump_indent(aTHX_ level, file, "PRIVATE = (%s)\n",
SvPVX_const(tmpsv) + 1); \
+ _sv_catpv(tmp, ",SLICEWARNING"); \
+ if (strlen(tmp)) { \
+ Perl_dump_indent(aTHX_ level, file, "PRIVATE = (%s)\n", tmp +
1); \
  } else \
  Perl_dump_indent(aTHX_ level, file, "PRIVATE = (0x%"UVxf")\n",
\
  (UV)oppriv); \
@​@​ -1027,22 +1091,24 @​@​ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file,
const OP *o)
  Perl_dump_indent(aTHX_ level, file, "LINE = %"UVuf"\n",
  (UV)CopLINE(cCOPo));
  if (CopSTASHPV(cCOPo)) {
- SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
  HV *stash = CopSTASH(cCOPo);
  const char * const hvname = HvNAME_get(stash);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);

  Perl_dump_indent(aTHX_ level, file, "PACKAGE = \"%s\"\n",
- generic_pv_escape( tmpsv, hvname,
HvNAMELEN(stash), HvNAMEUTF8(stash)));
+ generic_pv_escape( tmp, hvname,
HvNAMELEN(stash), HvNAMEUTF8(stash)));
+ Safefree(tmp);
  }
  if (CopLABEL(cCOPo)) {
- SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
  STRLEN label_len;
  U32 label_flags;
  const char *label = CopLABEL_len_flags(cCOPo,
  &label_len,
  &label_flags);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_dump_indent(aTHX_ level, file, "LABEL = \"%s\"\n",
- generic_pv_escape( tmpsv, label,
label_len,(label_flags & SVf_UTF8)));
+ generic_pv_escape( tmp, label,
label_len,(label_flags & SVf_UTF8)));
+ Safefree(tmp);
  }

  }
@​@​ -1070,11 +1136,11 @​@​ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file,
const OP *o)
  STRLEN len;
  const char * name;
  SV * const tmpsv = newSVpvs_flags("", SVs_TEMP);
- SV * const tmpsv2 = newSVpvs_flags("", SVs_TEMP);
+ char *tmp2; Newxz(tmp2, DO_SV_DUMP_BUFSIZE, char);
  gv_fullname3(tmpsv, MUTABLE_GV(cSVOPo->op_sv), NULL);
  name = SvPV_const(tmpsv, len);
  Perl_dump_indent(aTHX_ level, file, "GV = %s\n",
- generic_pv_escape( tmpsv2, name, len,
SvUTF8(tmpsv)));
+ generic_pv_escape( tmp2, name, len, SvUTF8(tmpsv)));
  }
  else
  Perl_dump_indent(aTHX_ level, file, "GV = NULL\n");
@​@​ -1096,23 +1162,25 @​@​ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file,
const OP *o)
  Perl_dump_indent(aTHX_ level, file, "LINE = %"UVuf"\n",
  (UV)CopLINE(cCOPo));
  if (CopSTASHPV(cCOPo)) {
- SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
  HV *stash = CopSTASH(cCOPo);
  const char * const hvname = HvNAME_get(stash);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);

  Perl_dump_indent(aTHX_ level, file, "PACKAGE = \"%s\"\n",
- generic_pv_escape(tmpsv, hvname,
+ generic_pv_escape(tmp, hvname,
  HvNAMELEN(stash), HvNAMEUTF8(stash)));
+ Safefree(tmp);
  }
  if (CopLABEL(cCOPo)) {
- SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
  STRLEN label_len;
  U32 label_flags;
  const char *label = CopLABEL_len_flags(cCOPo,
  &label_len, &label_flags);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_dump_indent(aTHX_ level, file, "LABEL = \"%s\"\n",
- generic_pv_escape( tmpsv, label, label_len,
+ generic_pv_escape( tmp, label, label_len,
  (label_flags & SVf_UTF8)));
+ Safefree(tmp);
  }
  break;
  case OP_ENTERLOOP​:
@​@​ -1190,7 +1258,8 @​@​ Perl_gv_dump(pTHX_ GV *gv)
{
  STRLEN len;
  const char* name;
- SV *sv, *tmp = newSVpvs_flags("", SVs_TEMP);
+ SV *sv;
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);

  PERL_ARGS_ASSERT_GV_DUMP;
@​@​ -1205,12 +1274,14 @​@​ Perl_gv_dump(pTHX_ GV *gv)
  name = SvPV_const(sv, len);
  Perl_dump_indent(aTHX_ 1, Perl_debug_log, "GV_NAME = %s",
  generic_pv_escape( tmp, name, len, SvUTF8(sv) ));
+ _sv_setpv(tmp, "");
  if (gv != GvEGV(gv)) {
  gv_efullname3(sv, GvEGV(gv), NULL);
  name = SvPV_const(sv, len);
  Perl_dump_indent(aTHX_ 1, Perl_debug_log, "-> %s",
  generic_pv_escape( tmp, name, len, SvUTF8(sv) ));
  }
+ Safefree(tmp);
  PerlIO_putc(Perl_debug_log, '\n');
  Perl_dump_indent(aTHX_ 0, Perl_debug_log, "}\n");
}
@​@​ -1369,10 +1440,11 @​@​ Perl_do_hv_dump(pTHX_ I32 level, PerlIO *file,
const char *name, HV *sv)
  name which quite legally could contain insane things like tabs,
newlines, nulls or
  other scary crap - this should produce sane results - except
maybe for unicode package
  names - but we will wait for someone to file a bug on that -
demerphq */
- SV * const tmpsv = newSVpvs_flags("", SVs_TEMP);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  PerlIO_printf(file, "\t\"%s\"\n",
- generic_pv_escape( tmpsv, hvname,
+ generic_pv_escape( tmp, hvname,
  HvNAMELEN(sv), HvNAMEUTF8(sv)));
+ Safefree(tmp);
  }
  else
  PerlIO_putc(file, '\n');
@​@​ -1385,9 +1457,10 @​@​ Perl_do_gv_dump(pTHX_ I32 level, PerlIO *file, const
char *name, GV *sv)

  Perl_dump_indent(aTHX_ level, file, "%s = 0x%"UVxf, name, PTR2UV(sv));
  if (sv && GvNAME(sv)) {
- SV * const tmpsv = newSVpvs("");
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  PerlIO_printf(file, "\t\"%s\"\n",
- generic_pv_escape( tmpsv, GvNAME(sv),
GvNAMELEN(sv), GvNAMEUTF8(sv) ));
+ generic_pv_escape( tmp, GvNAME(sv),
GvNAMELEN(sv), GvNAMEUTF8(sv) ));
+ Safefree(tmp);
  }
  else
  PerlIO_putc(file, '\n');
@​@​ -1400,18 +1473,20 @​@​ Perl_do_gvgv_dump(pTHX_ I32 level, PerlIO *file,
const char *name, GV *sv)

  Perl_dump_indent(aTHX_ level, file, "%s = 0x%"UVxf, name, PTR2UV(sv));
  if (sv && GvNAME(sv)) {
- SV *tmp = newSVpvs_flags("", SVs_TEMP);
  const char *hvname;
  HV * const stash = GvSTASH(sv);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  PerlIO_printf(file, "\t");
  /* TODO might have an extra \" here */
  if (stash && (hvname = HvNAME_get(stash))) {
  PerlIO_printf(file, "\"%s\" :​: \"",
  generic_pv_escape(tmp, hvname,
  HvNAMELEN(stash),
HvNAMEUTF8(stash)));
+ _sv_setpv(tmp, "");
  }
  PerlIO_printf(file, "%s\"\n",
  generic_pv_escape( tmp, GvNAME(sv),
GvNAMELEN(sv), GvNAMEUTF8(sv)));
+ Safefree(tmp);
  }
  else
  PerlIO_putc(file, '\n');
@​@​ -1529,8 +1604,8 @​@​ const struct flag_to_name
regexp_core_intflags_names[] = {
void
Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32
maxnest, bool dumpops, STRLEN pvlim)
{
- SV *d;
- const char *s;
+ char *d;
+ STRLEN len;
  U32 flags;
  U32 type;

@​@​ -1546,34 +1621,35 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo

  /* process general SV flags */

- d = Perl_newSVpvf(aTHX_
- "(0x%"UVxf") at 0x%"UVxf"\n%*s REFCNT = %"IVdf"\n%*s FLAGS = (",
- PTR2UV(SvANY(sv)), PTR2UV(sv),
- (int)(PL_dumpindent*level), "", (IV)SvREFCNT(sv),
- (int)(PL_dumpindent*level), "");
+ Newx(d, DO_SV_DUMP_BUFSIZE, char);
+ my_snprintf(d, DO_SV_DUMP_BUFSIZE,
+ "(0x%"UVxf") at 0x%"UVxf"\n%*s REFCNT = %"IVdf"\n%*s
FLAGS = (",
+ PTR2UV(SvANY(sv)), PTR2UV(sv),
+ (int)(PL_dumpindent*level), "", (IV)SvREFCNT(sv),
+ (int)(PL_dumpindent*level), "");

  if (!((flags & SVpad_NAME) == SVpad_NAME
  && (type == SVt_PVMG || type == SVt_PVNV))) {
  if ((flags & SVs_PADMY) && (flags & SVs_PADSTALE))
- sv_catpv(d, "PADSTALE,");
+ _sv_catpv(d, "PADSTALE,");
  }
  if (!((flags & SVpad_NAME) == SVpad_NAME && type == SVt_PVMG)) {
  if (!(flags & SVs_PADMY) && (flags & SVs_PADTMP))
- sv_catpv(d, "PADTMP,");
- if (flags & SVs_PADMY) sv_catpv(d, "PADMY,");
+ _sv_catpv(d, "PADTMP,");
+ if (flags & SVs_PADMY) _sv_catpv(d, "PADMY,");
  }
  append_flags(d, flags, first_sv_flags_names);
  if (flags & SVf_ROK) {
- sv_catpv(d, "ROK,");
- if (SvWEAKREF(sv)) sv_catpv(d, "WEAKREF,");
+ _sv_catpv(d, "ROK,");
+ if (SvWEAKREF(sv)) _sv_catpv(d, "WEAKREF,");
  }
  append_flags(d, flags, second_sv_flags_names);
  if (flags & SVp_SCREAM && type != SVt_PVHV && !isGV_with_GP(sv)
  && type != SVt_PVAV) {
  if (SvPCS_IMPORTED(sv))
- sv_catpv(d, "PCS_IMPORTED,");
+ _sv_catpv(d, "PCS_IMPORTED,");
  else
- sv_catpv(d, "SCREAM,");
+ _sv_catpv(d, "SCREAM,");
  }

  /* process type-specific SV flags */
@​@​ -1592,44 +1668,42 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  append_flags(d, GvFLAGS(sv), gp_flags_names);
  }
  if (isGV_with_GP(sv) && GvIMPORTED(sv)) {
- sv_catpv(d, "IMPORT");
+ _sv_catpv(d, "IMPORT");
  if (GvIMPORTED(sv) == GVf_IMPORTED)
- sv_catpv(d, "ALL,");
+ _sv_catpv(d, "ALL,");
  else {
- sv_catpv(d, "(");
+ _sv_catpv(d, "(");
  append_flags(d, GvFLAGS(sv), gp_flags_imported_names);
- sv_catpv(d, " ),");
+ _sv_catpv(d, " ),");
  }
  }
  /* FALLTHROUGH */
  default​:
  evaled_or_uv​:
- if (SvEVALED(sv)) sv_catpv(d, "EVALED,");
- if (SvIsUV(sv) && !(flags & SVf_ROK)) sv_catpv(d, "IsUV,");
+ if (SvEVALED(sv)) _sv_catpv(d, "EVALED,");
+ if (SvIsUV(sv) && !(flags & SVf_ROK)) _sv_catpv(d, "IsUV,");
  break;
  case SVt_PVMG​:
- if (SvTAIL(sv)) sv_catpv(d, "TAIL,");
- if (SvVALID(sv)) sv_catpv(d, "VALID,");
- if (SvPAD_TYPED(sv)) sv_catpv(d, "TYPED,");
- if (SvPAD_OUR(sv)) sv_catpv(d, "OUR,");
+ if (SvTAIL(sv)) _sv_catpv(d, "TAIL,");
+ if (SvVALID(sv)) _sv_catpv(d, "VALID,");
+ if (SvPAD_TYPED(sv)) _sv_catpv(d, "TYPED,");
+ if (SvPAD_OUR(sv)) _sv_catpv(d, "OUR,");
  /* FALLTHROUGH */
  case SVt_PVNV​:
- if (SvPAD_STATE(sv)) sv_catpv(d, "STATE,");
+ if (SvPAD_STATE(sv)) _sv_catpv(d, "STATE,");
  goto evaled_or_uv;
  case SVt_PVAV​:
- if (AvPAD_NAMELIST(sv)) sv_catpvs(d, "NAMELIST,");
+ if (AvPAD_NAMELIST(sv)) _sv_catpv(d, "NAMELIST,");
  break;
  }
  /* SVphv_SHAREKEYS is also 0x20000000 */
  if ((type != SVt_PVHV) && SvUTF8(sv))
- sv_catpv(d, "UTF8");
+ _sv_catpv(d, "UTF8");

- if (*(SvEND(d) - 1) == ',') {
- SvCUR_set(d, SvCUR(d) - 1);
- SvPVX(d)[SvCUR(d)] = '\0';
- }
- sv_catpv(d, ")");
- s = SvPVX_const(d);
+ len = strlen(d);
+ if (d[len - 1] == ',')
+ d[len - 1] = '\0';
+ _sv_catpv(d, ")");

  /* dump initial SV details */

@​@​ -1649,15 +1723,15 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  /* Dump SV type */

  if (type < SVt_LAST) {
- PerlIO_printf(file, "%s%s\n", svtypenames[type], s);
+ PerlIO_printf(file, "%s%s\n", svtypenames[type], d);

  if (type == SVt_NULL) {
- SvREFCNT_dec_NN(d);
+ Safefree(d);
  return;
  }
  } else {
- PerlIO_printf(file, "UNKNOWN(0x%"UVxf") %s\n", (UV)type, s);
- SvREFCNT_dec_NN(d);
+ PerlIO_printf(file, "UNKNOWN(0x%"UVxf") %s\n", (UV)type, d);
+ Safefree(d);
  return;
  }

@​@​ -1711,7 +1785,7 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  }

  if (type < SVt_PV) {
- SvREFCNT_dec_NN(d);
+ Safefree(d);
  return;
  }

@​@​ -1732,7 +1806,7 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  Perl_dump_indent(aTHX_ level, file," PV = 0x%"UVxf" ", PTR2UV(ptr));
  if (SvOOK(sv)) {
  PerlIO_printf(file, "( %s . ) ",
- pv_display(d, ptr - delta, delta, 0,
+ _pv_display(aTHX_ d, ptr - delta, delta, 0,
  pvlim));
  }
  if (type == SVt_INVLIST) {
@​@​ -1741,12 +1815,12 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  _invlist_dump(file, level, " ", sv);
  }
  else {
- PerlIO_printf(file, "%s", pv_display(d, ptr, SvCUR(sv),
+ PerlIO_printf(file, "%s", _pv_display(aTHX_ d, ptr,
SvCUR(sv),
  re ? 0 : SvLEN(sv),
  pvlim));
  if (SvUTF8(sv)) /* the 6? \x{....} */
  PerlIO_printf(file, " [UTF8 \"%s\"]",
- sv_uni_display(d, sv, 6 *
SvCUR(sv),
+ _sv_uni_display(aTHX_ d, sv, 6 *
SvCUR(sv),
  UNI_DISPLAY_QQ));
  PerlIO_printf(file, "\n");
  }
@​@​ -1802,11 +1876,11 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  if (!AvPAD_NAMELIST(sv))
  Perl_dump_indent(aTHX_ level, file, " ARYLEN = 0x%"UVxf"\n",
  SvMAGIC(sv) ? PTR2UV(AvARYLEN(sv)) : 0);
- sv_setpvs(d, "");
- if (AvREAL(sv)) sv_catpv(d, ",REAL");
- if (AvREIFY(sv)) sv_catpv(d, ",REIFY");
+ _sv_setpv(d, "");
+ if (AvREAL(sv)) _sv_catpv(d, ",REAL");
+ if (AvREIFY(sv)) _sv_catpv(d, ",REIFY");
  Perl_dump_indent(aTHX_ level, file, " FLAGS = (%s)\n",
- SvCUR(d) ? SvPVX_const(d) + 1 : "");
+ strlen(d) ? d + 1 : "");
  if (nest < maxnest && av_tindex(MUTABLE_AV(sv)) >= 0) {
  SSize_t count;
  for (count = 0; count <= av_tindex(MUTABLE_AV(sv)) && count <
maxnest; count++) {
@​@​ -1927,10 +2001,11 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  {
  const char * const hvname = HvNAME_get(sv);
  if (hvname) {
- SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_dump_indent(aTHX_ level, file, " NAME = \"%s\"\n",
- generic_pv_escape( tmpsv, hvname,
+ generic_pv_escape( tmp, hvname,
  HvNAMELEN(sv), HvNAMEUTF8(sv)));
+ Safefree(tmp);
  }
  }
  if (SvOOK(sv)) {
@​@​ -1945,35 +2020,42 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  if (HvAUX(sv)->xhv_name_u.xhvnameu_name && HvENAME_HEK_NN(sv)) {
  const I32 count = HvAUX(sv)->xhv_name_count;
  if (count) {
- SV * const names = newSVpvs_flags("", SVs_TEMP);
  /* The starting point is the first element if count is
  positive and the second element if count is negative. */
  HEK *const *hekp = HvAUX(sv)->xhv_name_u.xhvnameu_names
  + (count < 0 ? 1 : 0);
  HEK *const *const endp = HvAUX(sv)->xhv_name_u.xhvnameu_names
  + (count < 0 ? -count : count);
+ char *names; Newxz(names, DO_SV_DUMP_BUFSIZE, char);
  while (hekp < endp) {
  if (HEK_LEN(*hekp)) {
- SV *tmp = newSVpvs_flags("", SVs_TEMP);
- Perl_sv_catpvf(aTHX_ names, ", \"%s\"",
+ char *tmp, *tmp2;
+ Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
+ Newx(tmp2, DO_SV_DUMP_BUFSIZE, char);
+ my_snprintf(tmp2, DO_SV_DUMP_BUFSIZE, ",
\"%s\"",
  generic_pv_escape(tmp, HEK_KEY(*hekp),
HEK_LEN(*hekp), HEK_UTF8(*hekp)));
+ _sv_catpv(names, tmp2);
+ Safefree(tmp);
+ Safefree(tmp2);
  } else {
  /* This should never happen. */
- sv_catpvs(names, ", (null)");
+ _sv_catpv(names, ", (null)");
  }
  ++hekp;
  }
  Perl_dump_indent(aTHX_
- level, file, " ENAME = %s\n", SvPV_nolen(names)+2
+ level, file, " ENAME = %s\n", names+2
  );
+ Safefree(names);
  }
  else {
- SV * const tmp = newSVpvs_flags("", SVs_TEMP);
  const char *const hvename = HvENAME_get(sv);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_dump_indent(aTHX_
  level, file, " ENAME = \"%s\"\n",
  generic_pv_escape(tmp, hvename,
  HvENAMELEN_get(sv),
HvENAMEUTF8(sv)));
+ Safefree(tmp);
  }
  }
  if (backrefs) {
@​@​ -1983,12 +2065,13 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  dumpops, pvlim);
  }
  if (meta) {
- SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_dump_indent(aTHX_ level, file, " MRO_WHICH = \"%s\" (0x%"UVxf")\n",
- generic_pv_escape( tmpsv, meta->mro_which->name,
+ generic_pv_escape( tmp, meta->mro_which->name,
  meta->mro_which->length,
  (meta->mro_which->kflags & HVhek_UTF8)),
  PTR2UV(meta->mro_which));
+ Safefree(tmp);
  Perl_dump_indent(aTHX_ level, file, " CACHE_GEN = 0x%"UVxf"\n",
  (UV)meta->cache_gen);
  Perl_dump_indent(aTHX_ level, file, " PKG_GEN = 0x%"UVxf"\n",
@​@​ -2041,9 +2124,9 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  keypv = SvPV_const(keysv, len);
  elt = HeVAL(he);

- Perl_dump_indent(aTHX_ level+1, file, "Elt %s ",
pv_display(d, keypv, len, 0, pvlim));
+ Perl_dump_indent(aTHX_ level+1, file, "Elt %s ",
_pv_display(aTHX_ d, keypv, len, 0, pvlim));
  if (SvUTF8(keysv))
- PerlIO_printf(file, "[UTF8 \"%s\"] ",
sv_uni_display(d, keysv, 6 * SvCUR(keysv), UNI_DISPLAY_QQ));
+ PerlIO_printf(file, "[UTF8 \"%s\"] ",
_sv_uni_display(aTHX_ d, keysv, 6 * SvCUR(keysv), UNI_DISPLAY_QQ));
  if (HvEITER_get(hv) == he)
  PerlIO_printf(file, "[CURRENT] ");
  PerlIO_printf(file, "HASH = 0x%"UVxf"\n", (UV)
hash);
@​@​ -2058,18 +2141,20 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo

  case SVt_PVCV​:
  if (CvAUTOLOAD(sv)) {
- SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
  STRLEN len;
  const char *const name = SvPV_const(sv, len);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_dump_indent(aTHX_ level, file, " AUTOLOAD = \"%s\"\n",
- generic_pv_escape(tmpsv, name, len, SvUTF8(sv)));
+ generic_pv_escape(tmp, name, len, SvUTF8(sv)));
+ Safefree(tmp);
  }
  if (SvPOK(sv)) {
- SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
  const char *const proto = CvPROTO(sv);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_dump_indent(aTHX_ level, file, " PROTOTYPE = \"%s\"\n",
- generic_pv_escape(tmpsv, proto, CvPROTOLEN(sv),
+ generic_pv_escape(tmp, proto, CvPROTOLEN(sv),
  SvUTF8(sv)));
+ Safefree(tmp);
  }
  /* FALLTHROUGH */
  case SVt_PVFM​:
@​@​ -2116,6 +2201,7 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  }
  {
  const CV * const outside = CvOUTSIDE(sv);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_dump_indent(aTHX_ level, file, " OUTSIDE = 0x%"UVxf" (%s)\n",
  PTR2UV(outside),
  (!outside ? "null"
@​@​ -2124,11 +2210,12 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  : CvUNIQUE(outside) ? "UNIQUE"
  : CvGV(outside) ?
  generic_pv_escape(
- newSVpvs_flags("", SVs_TEMP),
+ tmp,
  GvNAME(CvGV(outside)),
  GvNAMELEN(CvGV(outside)),
  GvNAMEUTF8(CvGV(outside)))
  : "UNDEFINED"));
+ Safefree(tmp);
  }
  if (nest < maxnest && (CvCLONE(sv) || CvCLONED(sv)))
  do_sv_dump(level+1, file, MUTABLE_SV(CvOUTSIDE(sv)), nest+1, maxnest,
dumpops, pvlim);
@​@​ -2150,11 +2237,12 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  if (!isGV_with_GP(sv))
  break;
  {
- SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
+ char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
  Perl_dump_indent(aTHX_ level, file, " NAME = \"%s\"\n",
- generic_pv_escape(tmpsv, GvNAME(sv),
+ generic_pv_escape(tmp, GvNAME(sv),
  GvNAMELEN(sv),
  GvNAMEUTF8(sv)));
+ Safefree(tmp);
  }
  Perl_dump_indent(aTHX_ level, file, " NAMELEN = %"IVdf"\n",
(IV)GvNAMELEN(sv));
  do_hv_dump (level, file, " GvSTASH", GvSTASH(sv));
@​@​ -2226,27 +2314,26 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  struct regexp * const r = ReANY((REGEXP*)sv);

#define SV_SET_STRINGIFY_REGEXP_FLAGS(d,flags,names) STMT_START { \
- sv_setpv(d,""); \
- append_flags(d, flags, names); \
- if (SvCUR(d) > 0 && *(SvEND(d) - 1) == ',') { \
- SvCUR_set(d, SvCUR(d) - 1); \
- SvPVX(d)[SvCUR(d)] = '\0'; \
- } \
+ _sv_setpv(d,""); \
+ append_flags(d, flags, names); \
+ len = strlen(d); \
+ if (len > 0 && d[len - 1] == ',') \
+ d[len - 1] = '\0'; \
} STMT_END

SV_SET_STRINGIFY_REGEXP_FLAGS(d,r->compflags,regexp_extflags_names);
  Perl_dump_indent(aTHX_ level, file, " COMPFLAGS = 0x%"UVxf"
(%s)\n",
- (UV)(r->compflags), SvPVX_const(d));
+ (UV)(r->compflags), d);

SV_SET_STRINGIFY_REGEXP_FLAGS(d,r->extflags,regexp_extflags_names);
  Perl_dump_indent(aTHX_ level, file, " EXTFLAGS = 0x%"UVxf" (%s)\n",
- (UV)(r->extflags), SvPVX_const(d));
+ (UV)(r->extflags), d);

  Perl_dump_indent(aTHX_ level, file, " ENGINE = 0x%"UVxf"
(%s)\n",
  PTR2UV(r->engine), (r->engine ==
&PL_core_reg_engine) ? "STANDARD" : "PLUG-IN" );
  if (r->engine == &PL_core_reg_engine) {

SV_SET_STRINGIFY_REGEXP_FLAGS(d,r->intflags,regexp_core_intflags_names);
  Perl_dump_indent(aTHX_ level, file, " INTFLAGS =
0x%"UVxf" (%s)\n",
- (UV)(r->intflags), SvPVX_const(d));
+ (UV)(r->intflags), d);
  } else {
  Perl_dump_indent(aTHX_ level, file, " INTFLAGS =
0x%"UVxf"\n",
  (UV)(r->intflags));
@​@​ -2275,7 +2362,7 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  if (r->subbeg)
  Perl_dump_indent(aTHX_ level, file, " SUBBEG = 0x%"UVxf" %s\n",
  PTR2UV(r->subbeg),
- pv_display(d, r->subbeg, r->sublen, 50, pvlim));
+ _pv_display(aTHX_ d, r->subbeg, r->sublen, 50, pvlim));
  else
  Perl_dump_indent(aTHX_ level, file, " SUBBEG = 0x0\n");
  Perl_dump_indent(aTHX_ level, file, " MOTHER_RE = 0x%"UVxf"\n",
@​@​ -2300,7 +2387,7 @​@​ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV
*sv, I32 nest, I32 maxnest, bo
  }
  break;
  }
- SvREFCNT_dec_NN(d);
+ Safefree(d);
}

/*

Inline Patch
diff --git a/embed.fnc b/embed.fnc
index d02e555..45989dd 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -1618,6 +1618,7 @@ Ap |U8* |uvuni_to_utf8 |NN U8 *d|UV uv
 Adm |U8* |uvchr_to_utf8_flags |NN U8 *d|UV uv|UV flags
 Apd |U8* |uvoffuni_to_utf8_flags |NN U8 *d|UV uv|UV flags
 Ap |U8* |uvuni_to_utf8_flags |NN U8 *d|UV uv|UV flags
+Ap |char* |str_uni_display |NN char *dest|STRLEN maxlen|NN const U8
*spv|STRLEN len|STRLEN pvlim|UV flags Apd |char\* |pv\_uni\_display |NN SV \*dsv|NN const U8 \*spv|STRLEN len|STRLEN pvlim|UV flags ApdR |char\* |sv\_uni\_display |NN SV \*dsv|NN SV \*ssv|STRLEN pvlim|UV flags : Used by Data​::Alias
Inline Patch
diff --git a/embed.h b/embed.h
index 7ca719d..9278180 100644
--- a/embed.h
+++ b/embed.h
@@ -557,6 +557,7 @@
 #define stack_grow(a,b,c) Perl_stack_grow(aTHX_ a,b,c)
 #define start_subparse(a,b) Perl_start_subparse(aTHX_ a,b)
 #define str_to_version(a) Perl_str_to_version(aTHX_ a)
+#define str_uni_display(a,b,c,d,e,f) Perl_str_uni_display(aTHX_
a,b,c,d,e,f) \#define sv\_2bool\_flags\(a\,b\) Perl\_sv\_2bool\_flags\(aTHX\_ a\,b\) \#define sv\_2cv\(a\,b\,c\,d\) Perl\_sv\_2cv\(aTHX\_ a\,b\,c\,d\) \#define sv\_2io\(a\) Perl\_sv\_2io\(aTHX\_ a\)
Inline Patch
diff --git a/proto.h b/proto.h
index 1eccc46..9b104a8 100644
--- a/proto.h
+++ b/proto.h
@@ -3922,6 +3922,12 @@ PERL_CALLCONV NV Perl_str_to_version(pTHX_ SV *sv)
 #define PERL_ARGS_ASSERT_STR_TO_VERSION \
  assert(sv)

+PERL_CALLCONV char* Perl_str_uni_display(pTHX_ char *dest, STRLEN maxlen,
const U8 *spv, STRLEN len, STRLEN pvlim, UV flags) \+ \_\_attribute\_\_nonnull\_\_\(pTHX\_1\) \+ \_\_attribute\_\_nonnull\_\_\(pTHX\_3\); \+\#define PERL\_ARGS\_ASSERT\_STR\_UNI\_DISPLAY \\ \+ assert\(dest\); assert\(spv\) \+ PERL\_CALLCONV void Perl\_sub\_crush\_depth\(pTHX\_ CV\* cv\)   \_\_attribute\_\_nonnull\_\_\(pTHX\_1\); \#define PERL\_ARGS\_ASSERT\_SUB\_CRUSH\_DEPTH \\
Inline Patch
diff --git a/utf8.c b/utf8.c
index aa63504..db1eaf8 100644
--- a/utf8.c
+++ b/utf8.c
@@ -3729,63 +3729,83 @@ The pointer to the PV of the C<dsv> is returned.

 =cut */
 char *
-Perl_pv_uni_display(pTHX_ SV *dsv, const U8 *spv, STRLEN len, STRLEN
pvlim, UV flags) \+Perl\_str\_uni\_display\(pTHX\_ char \*dest\, STRLEN maxlen\, const U8 \*spv\, STRLEN len\, STRLEN pvlim\, UV flags\) \{   int truncated = 0;   const char \*s\, \*e; \+ char buf\[32\];

- PERL_ARGS_ASSERT_PV_UNI_DISPLAY;
+ PERL_ARGS_ASSERT_STR_UNI_DISPLAY;

- sv_setpvs(dsv, "");
- SvUTF8_off(dsv);
+ dest[0] = '\0';
  for (s = (const char *)spv, e = s + len; s < e; s += UTF8SKIP(s)) {
- UV u;
- /* This serves double duty as a flag and a character to print after
- a \ when flags & UNI_DISPLAY_BACKSLASH is true.
- */
- char ok = 0;
-
- if (pvlim && SvCUR(dsv) >= pvlim) {
- truncated++;
- break;
- }
- u = utf8_to_uvchr_buf((U8*)s, (U8*)e, 0);
- if (u < 256) {
- const unsigned char c = (unsigned char)u & 0xFF;
- if (flags & UNI_DISPLAY_BACKSLASH) {
- switch (c) {
- case '\n'​:
- ok = 'n'; break;
- case '\r'​:
- ok = 'r'; break;
- case '\t'​:
- ok = 't'; break;
- case '\f'​:
- ok = 'f'; break;
- case '\a'​:
- ok = 'a'; break;
- case '\\'​:
- ok = '\\'; break;
- default​: break;
- }
- if (ok) {
- const char string = ok;
- sv_catpvs(dsv, "\\");
- sv_catpvn(dsv, &string, 1);
- }
- }
- /* isPRINT() is the locale-blind version. */
- if (!ok && (flags & UNI_DISPLAY_ISPRINT) && isPRINT(c)) {
- const char string = c;
- sv_catpvn(dsv, &string, 1);
- ok = 1;
- }
- }
- if (!ok)
- Perl_sv_catpvf(aTHX_ dsv, "\\x{%"UVxf"}", u);
+ UV u;
+ /* This serves double duty as a flag and a character to print after
+ a \ when flags & UNI_DISPLAY_BACKSLASH is true.
+ */
+ char ok = 0;
+
+ if (pvlim && strlen(dest) >= pvlim) {
+ truncated++;
+ break;
+ }
+ u = utf8_to_uvchr_buf((U8*)s, (U8*)e, 0);
+ if (u < 256) {
+ const unsigned char c = (unsigned char)u & 0xFF;
+ if (flags & UNI_DISPLAY_BACKSLASH) {
+ switch (c) {
+ case '\n'​:
+ ok = 'n'; break;
+ case '\r'​:
+ ok = 'r'; break;
+ case '\t'​:
+ ok = 't'; break;
+ case '\f'​:
+ ok = 'f'; break;
+ case '\a'​:
+ ok = 'a'; break;
+ case '\\'​:
+ ok = '\\'; break;
+ default​: break;
+ }
+ if (ok) {
+ buf[0] = '\\';
+ buf[1] = ok;
+ buf[2] = '\0';
+ my_strlcat(dest, buf, maxlen);
+ }
+ }
+ /* isPRINT() is the locale-blind version. */
+ if (!ok && (flags & UNI_DISPLAY_ISPRINT) && isPRINT(c)) {
+ buf[0] = c;
+ buf[1] = '\0';
+ my_strlcat(dest, buf, maxlen);
+ ok = 1;
+ }
+ }
+ if (!ok) {
+ my_snprintf(buf, sizeof(buf), "\\x{%"UVxf"}", u);
+ my_strlcat(dest, buf, maxlen);
+ }
  }
  if (truncated)
- sv_catpvs(dsv, "...");
+ my_strlcat(dest, "...", maxlen);
+
+ return dest;
+}
+
+char *
+Perl_pv_uni_display(pTHX_ SV *dsv, const U8 *spv, STRLEN len, STRLEN
pvlim, UV flags)
+{
+ char *buf;
+ STRLEN maxlen = 6 * (len + 1);
+
+ PERL_ARGS_ASSERT_PV_UNI_DISPLAY;
+
+ Newxz(buf, maxlen, char);
+ sv_setpv(dsv, str_uni_display(buf, maxlen, spv, len, pvlim, flags));
+ SvUTF8_off(dsv);
+ Safefree(buf);

  return SvPVX(dsv);
}
--
2.0.1

@p5pRT
Copy link
Author

p5pRT commented Jul 25, 2014

From creaktive@gmail.com

Sorry about the GMail noise. Patch also available here​:
https://gist.github.com/creaktive/14081a74a13728bab7dc

@p5pRT
Copy link
Author

p5pRT commented Jul 26, 2014

From @jkeenan

On Fri Jul 25 09​:11​:04 2014, creaktive@​gmail.com wrote​:

Picked this yak from Porting/todo.pod :)
This is a work in progress, some functions still use newSV*.
Also, a cleanup is planned (_sv_catpv/_sv_cpypv macros will be removed).
---
AUTHORS | 1 +
dump.c | 599
+++++++++++++++++++++++++++++++++++---------------------------
embed.fnc | 1 +
embed.h | 1 +
proto.h | 6 +
utf8.c | 118 ++++++++-----
6 files changed, 421 insertions(+), 305 deletions(-)

Thank you for taking this task on. I have created a smoke-testing branch for it in our git repository​:

smoke-me/jkeenan/122405-dump-c-cleanup

You indicate that this is a work-in-progress. I would encourage you to send future patches as attachments to this ticket at rt.perl.org or as attachments to posts to the p5p list. I.e., avoid inlines.

Porters​:

Because this patch is (a) large, (b) presumably the first of several, and (c) touches the internals, we should develop a plan for its review. That means we have to call upon people who understand what dump.c does and why this cleanup is recommended in Porting/todo.pod.

When applied in a branch (with one whitespace correction), the patch passes all tests for me on Linux/x86_64. But I don't know whether we currently have any tests that directly exercise dump.c, so I can't say that that PASS is a green light to proceed. Bugs due to changes in the internals sometimes do not materialize for a year or more.

How, then, shall we proceed?

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Jul 26, 2014

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jul 26, 2014

From @iabyn

On Fri, Jul 25, 2014 at 09​:11​:05AM -0700, Stanislaw Pusep wrote​:

I had a cursory glance at this diff, and noticed that you've added several
functions with names beginning with an underscore, e.g.

+_pv_escape( pTHX_ char *dsv, char const * const str,
+ const STRLEN count, const STRLEN max,
+ STRLEN * const escaped, const U32 flags )

This isn't a generally done practise within the perl core. Are these
supposed to be private helper functions local to dump.c?

In which case, they should be declared static, and have names starting
with S_; but not with a name that clashes with Perl_ - i.e. you shouldn't
have both S_foo() and Perl_foo().

--
"But Sidley Park is already a picture, and a most amiable picture too.
The slopes are green and gentle. The trees are companionably grouped at
intervals that show them to advantage. The rill is a serpentine ribbon
unwound from the lake peaceably contained by meadows on which the right
amount of sheep are tastefully arranged." -- Lady Croom, "Arcadia"

@p5pRT
Copy link
Author

p5pRT commented Jul 28, 2014

From creaktive@gmail.com

@​James​:
Sorry about the inlining, will send the patches as attachments from now on
:)
The test that more-or-less directly exercises dump.c is
ext/Devel-Peek/t/Peek.t
Also, my initial changes to utf8.c managed to break these tests​:
t/uni/gv.t
t/uni/variables.t
lib/warnings.t
So, if any of these reports as failing, that was probably caused by my
changes. BTW, I've tested under Darwin/x86_64, for threaded/non-threaded &
debug/non-debug builds.

@​Dave​:
Thanks for pointing this out, I was quite confused with the naming for
these private helpers. Will rename in the upcoming patch.

@p5pRT
Copy link
Author

p5pRT commented Jul 28, 2014

From creaktive@gmail.com

OK, here's the second part.
Also, I am confused about Perl_sv_peek(). In a nutshell, this is how it looks like​:

char *Perl_sv_peek(pTHX_ SV *sv) {
  dVAR;
  SV * const t = sv_newmortal();
  /* do all kind of stuff with "t" */
  return SvPV_nolen(t);
}

What happens to "t", then? Isn't the reference to it lost, since we only return the pointer to it's payload?
From what I see, the pattern of usage of Perl_sv_peek (AKA SvPEEK) is​:

newSVpv(Perl_sv_peek(aTHX_ sv), 0);

Would it be an acceptable idea to make Perl_sv_peek store the data in a static buffer?
(sort of​: what's worse, leaking memory or being dangerously thread-unsafe?)

@p5pRT
Copy link
Author

p5pRT commented Jul 28, 2014

From creaktive@gmail.com

0001-Proper-naming-for-the-new-helper-functions-more-newS.patch
From 2cda05049b8b42e037a3f13f00ea9e81603b5eff Mon Sep 17 00:00:00 2001
From: Stanislaw Pusep <creaktive@gmail.com>
Date: Mon, 28 Jul 2014 12:21:00 +0200
Subject: [PATCH] Proper naming for the new helper functions; more newSVpv()
 references removed.

Perl_sv_peek() now operates internally without allocating new SVs. But then,
a single SV is allocated for the result so we can return SvPV_nolen().
Does that configure a memory leak? Perl_sv_peek() already works that way.
---
 dump.c | 151 ++++++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 83 insertions(+), 68 deletions(-)

diff --git a/dump.c b/dump.c
index 5f81704..9b80afa 100644
--- a/dump.c
+++ b/dump.c
@@ -90,7 +90,7 @@ S_append_flags(char *s, U32 flags, const struct flag_to_name *start,
 #define append_flags(s, f, flags) \
     S_append_flags((s), (f), (flags), C_ARRAY_END(flags))
 
-#define generic_pv_escape(sv,s,len,utf8) _pv_escape( aTHX_ (sv), (s), (len), \
+#define generic_pv_escape(sv,s,len,utf8) S_pv_escape( aTHX_ (sv), (s), (len), \
                               (len) * (4+UTF8_MAXBYTES) + 1, NULL, \
                               PERL_PV_ESCAPE_NONASCII | PERL_PV_ESCAPE_DWIM \
                               | ((utf8) ? PERL_PV_ESCAPE_UNI : 0) )
@@ -137,8 +137,8 @@ Returns a pointer to the escaped text as held by dsv.
 */
 #define PV_ESCAPE_OCTBUFSIZE 32
 
-char *
-_pv_escape( pTHX_ char *dsv, char const * const str,
+static char *
+S_pv_escape( pTHX_ char *dsv, char const * const str,
             const STRLEN count, const STRLEN max,
             STRLEN * const escaped, const U32 flags )
 {
@@ -256,7 +256,7 @@ Perl_pv_escape( pTHX_ SV *dsv, char const * const str,
     }
 
     Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
-    sv_catpv(dsv, _pv_escape(aTHX_ buf, str, count, max, escaped, flags));
+    sv_catpv(dsv, S_pv_escape(aTHX_ buf, str, count, max, escaped, flags));
     Safefree(buf);
 
     return SvPVX(dsv);
@@ -286,8 +286,8 @@ Returns a pointer to the prettified text as held by dsv.
 =cut           
 */
 
-char *
-_pv_pretty( pTHX_ char *dsv, char const * const str, const STRLEN count,
+static char *
+S_pv_pretty( pTHX_ char *dsv, char const * const str, const STRLEN count,
             const STRLEN max, char const * const start_color, char const * const end_color,
             const U32 flags )
 {
@@ -302,7 +302,7 @@ _pv_pretty( pTHX_ char *dsv, char const * const str, const STRLEN count,
     if ( start_color != NULL )
         _sv_catpv(dsv, start_color);
 
-    _pv_escape( aTHX_ dsv, str, count, max, &escaped, flags );
+    S_pv_escape( aTHX_ dsv, str, count, max, &escaped, flags );
 
     if ( end_color != NULL )
         _sv_catpv(dsv, end_color);
@@ -332,7 +332,7 @@ Perl_pv_pretty( pTHX_ SV *dsv, char const * const str, const STRLEN count,
     }
 
     Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
-    sv_catpv(dsv, _pv_pretty(aTHX_ buf, str, count, max, start_color, end_color, flags));
+    sv_catpv(dsv, S_pv_pretty(aTHX_ buf, str, count, max, start_color, end_color, flags));
     Safefree(buf);
 
     return SvPVX(dsv);
@@ -352,11 +352,11 @@ Note that the final string may be up to 7 chars longer than pvlim.
 =cut
 */
 
-char *
-_pv_display( pTHX_ char *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim)
+static char *
+S_pv_display( pTHX_ char *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim)
 {
     _sv_setpv(dsv, "");
-    _pv_pretty( aTHX_ dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP);
+    S_pv_pretty( aTHX_ dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP);
     if (len > cur && pv[cur] == '\0')
         _sv_catpv( dsv, "\\0");
     return dsv;
@@ -369,14 +369,14 @@ Perl_pv_display(pTHX_ SV *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pv
     PERL_ARGS_ASSERT_PV_DISPLAY;
 
     Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
-    sv_setpv(dsv, _pv_display(aTHX_ buf, pv, cur, len, pvlim));
+    sv_setpv(dsv, S_pv_display(aTHX_ buf, pv, cur, len, pvlim));
     Safefree(buf);
 
     return SvPVX(dsv);
 }
 
-char *
-_sv_uni_display( pTHX_ char *dest, SV *ssv, STRLEN pvlim, UV flags)
+static char *
+S_sv_uni_display( pTHX_ char *dest, SV *ssv, STRLEN pvlim, UV flags)
 {
     STRLEN len = SvCUR(ssv);
     U8 *spv = (U8 *)
@@ -389,31 +389,34 @@ char *
 Perl_sv_peek(pTHX_ SV *sv)
 {
     dVAR;
-    SV * const t = sv_newmortal();
+    SV * const out = sv_newmortal();
     int unref = 0;
     U32 type;
+    char *s, *t;
+    Newx(s, DO_SV_DUMP_BUFSIZE, char);
+    Newx(t, DO_SV_DUMP_BUFSIZE, char);
 
-    sv_setpvs(t, "");
+    _sv_setpv(t, "");
   retry:
     if (!sv) {
-	sv_catpv(t, "VOID");
+	_sv_catpv(t, "VOID");
 	goto finish;
     }
     else if (sv == (const SV *)0x55555555 || ((char)SvTYPE(sv)) == 'U') {
         /* detect data corruption under memory poisoning */
-	sv_catpv(t, "WILD");
+	_sv_catpv(t, "WILD");
 	goto finish;
     }
     else if (sv == &PL_sv_undef || sv == &PL_sv_no || sv == &PL_sv_yes || sv == &PL_sv_placeholder) {
 	if (sv == &PL_sv_undef) {
-	    sv_catpv(t, "SV_UNDEF");
+	    _sv_catpv(t, "SV_UNDEF");
 	    if (!(SvFLAGS(sv) & (SVf_OK|SVf_OOK|SVs_OBJECT|
 				 SVs_GMG|SVs_SMG|SVs_RMG)) &&
 		SvREADONLY(sv))
 		goto finish;
 	}
 	else if (sv == &PL_sv_no) {
-	    sv_catpv(t, "SV_NO");
+	    _sv_catpv(t, "SV_NO");
 	    if (!(SvFLAGS(sv) & (SVf_ROK|SVf_OOK|SVs_OBJECT|
 				 SVs_GMG|SVs_SMG|SVs_RMG)) &&
 		!(~SvFLAGS(sv) & (SVf_POK|SVf_NOK|SVf_READONLY|
@@ -423,7 +426,7 @@ Perl_sv_peek(pTHX_ SV *sv)
 		goto finish;
 	}
 	else if (sv == &PL_sv_yes) {
-	    sv_catpv(t, "SV_YES");
+	    _sv_catpv(t, "SV_YES");
 	    if (!(SvFLAGS(sv) & (SVf_ROK|SVf_OOK|SVs_OBJECT|
 				 SVs_GMG|SVs_SMG|SVs_RMG)) &&
 		!(~SvFLAGS(sv) & (SVf_POK|SVf_NOK|SVf_READONLY|
@@ -434,16 +437,16 @@ Perl_sv_peek(pTHX_ SV *sv)
 		goto finish;
 	}
 	else {
-	    sv_catpv(t, "SV_PLACEHOLDER");
+	    _sv_catpv(t, "SV_PLACEHOLDER");
 	    if (!(SvFLAGS(sv) & (SVf_OK|SVf_OOK|SVs_OBJECT|
 				 SVs_GMG|SVs_SMG|SVs_RMG)) &&
 		SvREADONLY(sv))
 		goto finish;
 	}
-	sv_catpv(t, ":");
+	_sv_catpv(t, ":");
     }
     else if (SvREFCNT(sv) == 0) {
-	sv_catpv(t, "(");
+	_sv_catpv(t, "(");
 	unref++;
     }
     else if (DEBUG_R_TEST_) {
@@ -456,19 +459,19 @@ Perl_sv_peek(pTHX_ SV *sv)
 		break;
 	    }
 	}
-	if (SvREFCNT(sv) > 1)
-	    Perl_sv_catpvf(aTHX_ t, "<%"UVuf"%s>", (UV)SvREFCNT(sv),
-		    is_tmp ? "T" : "");
-	else if (is_tmp)
-	    sv_catpv(t, "<T>");
+	if (SvREFCNT(sv) > 1) {
+            my_snprintf(s, DO_SV_DUMP_BUFSIZE, "<%"UVuf"%s>", (UV)SvREFCNT(sv),
+                is_tmp ? "T" : "");
+            _sv_catpv(t, s);
+        } else if (is_tmp)
+            _sv_catpv(t, "<T>");
     }
 
     if (SvROK(sv)) {
-	sv_catpv(t, "\\");
-	if (SvCUR(t) + unref > 10) {
-	    SvCUR_set(t, unref + 3);
-	    *SvEND(t) = '\0';
-	    sv_catpv(t, "...");
+	_sv_catpv(t, "\\");
+	if (strlen(t) + unref > 10) {
+            t[unref + 4] = '\0';
+	    _sv_catpv(t, "...");
 	    goto finish;
 	}
 	sv = SvRV(sv);
@@ -478,60 +481,71 @@ Perl_sv_peek(pTHX_ SV *sv)
     if (type == SVt_PVCV) {
         GV* gvcv = CvGV(sv);
         char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
-        Perl_sv_catpvf(aTHX_ t, "CV(%s)", gvcv
+        my_snprintf(s, DO_SV_DUMP_BUFSIZE, "CV(%s)", gvcv
                        ? generic_pv_escape( tmp, GvNAME(gvcv), GvNAMELEN(gvcv), GvNAMEUTF8(gvcv))
                        : "");
+        _sv_catpv(t, s);
         Safefree(tmp);
 	goto finish;
     } else if (type < SVt_LAST) {
-	sv_catpv(t, svshorttypenames[type]);
+	_sv_catpv(t, svshorttypenames[type]);
 
 	if (type == SVt_NULL)
 	    goto finish;
     } else {
-	sv_catpv(t, "FREED");
+	_sv_catpv(t, "FREED");
 	goto finish;
     }
 
     if (SvPOKp(sv)) {
 	if (!SvPVX_const(sv))
-	    sv_catpv(t, "(null)");
+	    _sv_catpv(t, "(null)");
 	else {
-	    SV * const tmp = newSVpvs("");
-	    sv_catpv(t, "(");
+            char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
+	    _sv_catpv(t, "(");
 	    if (SvOOK(sv)) {
 		STRLEN delta;
 		SvOOK_offset(sv, delta);
-		Perl_sv_catpvf(aTHX_ t, "[%s]", pv_display(tmp, SvPVX_const(sv)-delta, delta, 0, 127));
+                my_snprintf(s, DO_SV_DUMP_BUFSIZE, "[%s]", S_pv_display(tmp, SvPVX_const(sv)-delta, delta, 0, 127));
+                _sv_catpv(t, s);
 	    }
-	    Perl_sv_catpvf(aTHX_ t, "%s)", pv_display(tmp, SvPVX_const(sv), SvCUR(sv), SvLEN(sv), 127));
-	    if (SvUTF8(sv))
-		Perl_sv_catpvf(aTHX_ t, " [UTF8 \"%s\"]",
-			       sv_uni_display(tmp, sv, 6 * SvCUR(sv),
-					      UNI_DISPLAY_QQ));
-	    SvREFCNT_dec_NN(tmp);
+            my_snprintf(s, DO_SV_DUMP_BUFSIZE, "%s)", S_pv_display(tmp, SvPVX_const(sv), SvCUR(sv), SvLEN(sv), 127));
+            _sv_catpv(t, s);
+            if (SvUTF8(sv)) {
+                my_snprintf(s, DO_SV_DUMP_BUFSIZE, " [UTF8 \"%s\"]",
+                            S_sv_uni_display(tmp, sv, 6 * SvCUR(sv),
+                            UNI_DISPLAY_QQ));
+                _sv_catpv(t, s);
+            }
+            Safefree(tmp);
 	}
     }
     else if (SvNOKp(sv)) {
 	STORE_NUMERIC_LOCAL_SET_STANDARD();
-	Perl_sv_catpvf(aTHX_ t, "(%"NVgf")",SvNVX(sv));
+        my_snprintf(s, DO_SV_DUMP_BUFSIZE, "(%"NVgf")",SvNVX(sv));
+        _sv_catpv(t, s);
 	RESTORE_NUMERIC_LOCAL();
     }
     else if (SvIOKp(sv)) {
-	if (SvIsUV(sv))
-	    Perl_sv_catpvf(aTHX_ t, "(%"UVuf")", (UV)SvUVX(sv));
-	else
-            Perl_sv_catpvf(aTHX_ t, "(%"IVdf")", (IV)SvIVX(sv));
+        if (SvIsUV(sv))
+            my_snprintf(s, DO_SV_DUMP_BUFSIZE, "(%"UVuf")", (UV)SvUVX(sv));
+        else
+            my_snprintf(s, DO_SV_DUMP_BUFSIZE, "(%"IVdf")", (IV)SvIVX(sv));
+        _sv_catpv(t, s);
     }
     else
-	sv_catpv(t, "()");
+	_sv_catpv(t, "()");
 
   finish:
     while (unref--)
-	sv_catpv(t, ")");
+	_sv_catpv(t, ")");
     if (TAINTING_get && sv && SvTAINTED(sv))
-	sv_catpv(t, " [tainted]");
-    return SvPV_nolen(t);
+	_sv_catpv(t, " [tainted]");
+
+    sv_setpv(out, t);
+    Safefree(s);
+    Safefree(t);
+    return SvPV_nolen(out);
 }
 
 /*
@@ -1365,13 +1379,14 @@ Perl_do_magic_dump(pTHX_ I32 level, PerlIO *file, const MAGIC *mg, I32 nest, I32
 	        PTR2UV(mg->mg_obj));
             if (mg->mg_type == PERL_MAGIC_qr) {
 		REGEXP* const re = (REGEXP *)mg->mg_obj;
-		SV * const dsv = sv_newmortal();
-                const char * const s
-		    = pv_pretty(dsv, RX_WRAPPED(re), RX_WRAPLEN(re),
+                char *s;
+                char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
+                s = S_pv_pretty(tmp, RX_WRAPPED(re), RX_WRAPLEN(re),
                     60, NULL, NULL,
                     ( PERL_PV_PRETTY_QUOTE | PERL_PV_ESCAPE_RE | PERL_PV_PRETTY_ELLIPSES |
                     (RX_UTF8(re) ? PERL_PV_ESCAPE_UNI : 0))
                 );
+                Safefree(tmp);
 		Perl_dump_indent(aTHX_ level+1, file, "    PAT = %s\n", s);
 		Perl_dump_indent(aTHX_ level+1, file, "    REFCNT = %"IVdf"\n",
 			(IV)RX_REFCNT(re));
@@ -1385,9 +1400,9 @@ Perl_do_magic_dump(pTHX_ I32 level, PerlIO *file, const MAGIC *mg, I32 nest, I32
 	    Perl_dump_indent(aTHX_ level, file, "    MG_PTR = 0x%"UVxf, PTR2UV(mg->mg_ptr));
 	    if (mg->mg_len >= 0) {
 		if (mg->mg_type != PERL_MAGIC_utf8) {
-		    SV * const sv = newSVpvs("");
-		    PerlIO_printf(file, " %s", pv_display(sv, mg->mg_ptr, mg->mg_len, 0, pvlim));
-		    SvREFCNT_dec_NN(sv);
+                    char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
+                    PerlIO_printf(file, " %s", S_pv_display(tmp, mg->mg_ptr, mg->mg_len, 0, pvlim));
+                    Safefree(tmp);
 		}
             }
 	    else if (mg->mg_len == HEf_SVKEY) {
@@ -1806,7 +1821,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	    Perl_dump_indent(aTHX_ level, file,"  PV = 0x%"UVxf" ", PTR2UV(ptr));
 	    if (SvOOK(sv)) {
 		PerlIO_printf(file, "( %s . ) ",
-			      _pv_display(aTHX_ d, ptr - delta, delta, 0,
+			      S_pv_display(aTHX_ d, ptr - delta, delta, 0,
 					 pvlim));
 	    }
             if (type == SVt_INVLIST) {
@@ -1815,12 +1830,12 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
                 _invlist_dump(file, level, "    ", sv);
             }
             else {
-                PerlIO_printf(file, "%s", _pv_display(aTHX_ d, ptr, SvCUR(sv),
+                PerlIO_printf(file, "%s", S_pv_display(aTHX_ d, ptr, SvCUR(sv),
                                                      re ? 0 : SvLEN(sv),
                                                      pvlim));
                 if (SvUTF8(sv)) /* the 6?  \x{....} */
                     PerlIO_printf(file, " [UTF8 \"%s\"]",
-                                         _sv_uni_display(aTHX_ d, sv, 6 * SvCUR(sv),
+                                         S_sv_uni_display(aTHX_ d, sv, 6 * SvCUR(sv),
                                                         UNI_DISPLAY_QQ));
                 PerlIO_printf(file, "\n");
             }
@@ -2124,9 +2139,9 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 			keypv = SvPV_const(keysv, len);
 			elt = HeVAL(he);
 
-                        Perl_dump_indent(aTHX_ level+1, file, "Elt %s ", _pv_display(aTHX_ d, keypv, len, 0, pvlim));
+                        Perl_dump_indent(aTHX_ level+1, file, "Elt %s ", S_pv_display(aTHX_ d, keypv, len, 0, pvlim));
                         if (SvUTF8(keysv))
-                            PerlIO_printf(file, "[UTF8 \"%s\"] ", _sv_uni_display(aTHX_ d, keysv, 6 * SvCUR(keysv), UNI_DISPLAY_QQ));
+                            PerlIO_printf(file, "[UTF8 \"%s\"] ", S_sv_uni_display(aTHX_ d, keysv, 6 * SvCUR(keysv), UNI_DISPLAY_QQ));
 			if (HvEITER_get(hv) == he)
 			    PerlIO_printf(file, "[CURRENT] ");
                         PerlIO_printf(file, "HASH = 0x%"UVxf"\n", (UV) hash);
@@ -2362,7 +2377,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	    if (r->subbeg)
 		Perl_dump_indent(aTHX_ level, file, "  SUBBEG = 0x%"UVxf" %s\n",
 			    PTR2UV(r->subbeg),
-			    _pv_display(aTHX_ d, r->subbeg, r->sublen, 50, pvlim));
+			    S_pv_display(aTHX_ d, r->subbeg, r->sublen, 50, pvlim));
 	    else
 		Perl_dump_indent(aTHX_ level, file, "  SUBBEG = 0x0\n");
 	    Perl_dump_indent(aTHX_ level, file, "  MOTHER_RE = 0x%"UVxf"\n",
-- 
2.0.1

@p5pRT
Copy link
Author

p5pRT commented Aug 4, 2014

From @jkeenan

On Mon Jul 28 06​:08​:52 2014, creaktive@​gmail.com wrote​:

OK, here's the second part.
Also, I am confused about Perl_sv_peek(). In a nutshell, this is how
it looks like​:

char *Perl_sv_peek(pTHX_ SV *sv) {
dVAR;
SV * const t = sv_newmortal();
/* do all kind of stuff with "t" */
return SvPV_nolen(t);
}

What happens to "t", then? Isn't the reference to it lost, since we
only return the pointer to it's payload?
From what I see, the pattern of usage of Perl_sv_peek (AKA SvPEEK) is​:

newSVpv(Perl_sv_peek(aTHX_ sv), 0);

Would it be an acceptable idea to make Perl_sv_peek store the data in
a static buffer?
(sort of​: what's worse, leaking memory or being dangerously thread-
unsafe?)

Although I was able to apply the second locally, I got conflicts when I attempted to push it to the smoke-me branch.

#####
[perl] 69 $ git push -f origin 122405-dump-c-cleanup​:smoke-me/jkeenan/122405-dump-c-cleanup
Counting objects​: 22, done.
Delta compression using up to 4 threads.
Compressing objects​: 100% (4/4), done.
Writing objects​: 100% (4/4), 4.44 KiB | 0 bytes/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote​: error​: denying non-fast-forward refs/heads/smoke-me/jkeenan/122405-dump-c-cleanup (you should pull first)
To jkeenan@​perl5.git.perl.org​:/gitroot/perl.git
! [remote rejected] 122405-dump-c-cleanup -> smoke-me/jkeenan/122405-dump-c-cleanup (non-fast-forward)
error​: failed to push some refs to 'jkeenan@​perl5.git.perl.org​:/gitroot/perl.git'
[perl] 70 $ vi .git/config
[perl] 71 $ git pull origin smoke-me/jkeenan/122405-dump-c-cleanup
From perl5.git.perl.org​:/gitroot/perl
* branch smoke-me/jkeenan/122405-dump-c-cleanup -> FETCH_HEAD
Auto-merging dump.c
CONFLICT (content)​: Merge conflict in dump.c
Automatic merge failed; fix conflicts and then commit the result.
#####

@p5pRT
Copy link
Author

p5pRT commented Aug 4, 2014

From creaktive@gmail.com

Sorry about my clumsiness, I've literally discovered "git am" 10 days ago.
May I use GitHub mirror? I am more familiar with that tool.
This is the same patch applied to my fork​:
https://github.com/creaktive/perl5/commit/5b2957bef84fa5a0bfc07433cfcdda355e046661

On Mon, Aug 4, 2014 at 1​:53 PM, James E Keenan via RT <
perlbug-followup@​perl.org> wrote​:

On Mon Jul 28 06​:08​:52 2014, creaktive@​gmail.com wrote​:

OK, here's the second part.
Also, I am confused about Perl_sv_peek(). In a nutshell, this is how
it looks like​:

char *Perl_sv_peek(pTHX_ SV *sv) {
dVAR;
SV * const t = sv_newmortal();
/* do all kind of stuff with "t" */
return SvPV_nolen(t);
}

What happens to "t", then? Isn't the reference to it lost, since we
only return the pointer to it's payload?
From what I see, the pattern of usage of Perl_sv_peek (AKA SvPEEK) is​:

newSVpv(Perl_sv_peek(aTHX_ sv), 0);

Would it be an acceptable idea to make Perl_sv_peek store the data in
a static buffer?
(sort of​: what's worse, leaking memory or being dangerously thread-
unsafe?)

Although I was able to apply the second locally, I got conflicts when I
attempted to push it to the smoke-me branch.

#####
[perl] 69 $ git push -f origin
122405-dump-c-cleanup​:smoke-me/jkeenan/122405-dump-c-cleanup
Counting objects​: 22, done.
Delta compression using up to 4 threads.
Compressing objects​: 100% (4/4), done.
Writing objects​: 100% (4/4), 4.44 KiB | 0 bytes/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote​: error​: denying non-fast-forward
refs/heads/smoke-me/jkeenan/122405-dump-c-cleanup (you should pull first)
To jkeenan@​perl5.git.perl.org​:/gitroot/perl.git
! [remote rejected] 122405-dump-c-cleanup ->
smoke-me/jkeenan/122405-dump-c-cleanup (non-fast-forward)
error​: failed to push some refs to 'jkeenan@​perl5.git.perl.org​:
/gitroot/perl.git'
[perl] 70 $ vi .git/config
[perl] 71 $ git pull origin smoke-me/jkeenan/122405-dump-c-cleanup
From perl5.git.perl.org​:/gitroot/perl
* branch smoke-me/jkeenan/122405-dump-c-cleanup -> FETCH_HEAD
Auto-merging dump.c
CONFLICT (content)​: Merge conflict in dump.c
Automatic merge failed; fix conflicts and then commit the result.
#####

@p5pRT
Copy link
Author

p5pRT commented Aug 4, 2014

From @jkeenan

On 08/04/2014 08​:24 AM, Stanislaw Pusep wrote​:

Sorry about my clumsiness, I've literally discovered "git am" 10 days
ago. May I use GitHub mirror? I am more familiar with that tool.

'git am' is what we would use to apply your patch.

What you probably want is 'git format-patch'. It creates one diff file
-- in a format well suited for 'git am' on the committer side -- for
each commit since a designated one.

So let's suppose that your starting point was commit
0bfc07433cfcdda355e0. To create a patch(es) and place them in /home/
spusep/uploads, you would say​:

git format-patch -o /home/spusep/uploads 0bfc07433cfcdda355e0

The patches would be named by prepending '0001-', '0002-', etc. to a
munged version of the top line of the commit message. You would then
attach them to your email or to your post via the GUI at rt.perl.org.

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Aug 5, 2014

From @tonycoz

On Mon Jul 28 06​:08​:52 2014, creaktive@​gmail.com wrote​:

OK, here's the second part.
Also, I am confused about Perl_sv_peek(). In a nutshell, this is how
it looks like​:

char *Perl_sv_peek(pTHX_ SV *sv) {
dVAR;
SV * const t = sv_newmortal();
/* do all kind of stuff with "t" */
return SvPV_nolen(t);
}

What happens to "t", then? Isn't the reference to it lost, since we
only return the pointer to it's payload?

sv_newmortal() creates an SV and registers it to be freed on the next (nested) FREETMPS, eg​:

  SAVETMPS;
  s = sv_newmortal();
  ...
  SAVETMPS;
  ...
  FREETMPS;
  ...
  FREETMPS; /* s released here */

From what I see, the pattern of usage of Perl_sv_peek (AKA SvPEEK) is​:

newSVpv(Perl_sv_peek(aTHX_ sv), 0);

Would it be an acceptable idea to make Perl_sv_peek store the data in
a static buffer?
(sort of​: what's worse, leaking memory or being dangerously thread-
unsafe?)

SAVEFREEPV() might be what you want here.

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 5, 2014

From creaktive@gmail.com

Thanks for the explanation. But the .patch file generated that way is almost the same, the only thing that did changed were the first and the last line (not the diff body).
Just to make sure, I've rebased all the changes on my local copy of 'smoke-me/jkeenan/122405-dump-c-cleanup' and made the .patch files that do apply to the current 'blead'. So, in the worst case, 'smoke-me/jkeenan/122405-dump-c-cleanup' could be dropped and regenerated from the latest codebase.

On Mon Aug 04 15​:37​:54 2014, jkeen@​verizon.net wrote​:

On 08/04/2014 08​:24 AM, Stanislaw Pusep wrote​:

Sorry about my clumsiness, I've literally discovered "git am" 10 days
ago. May I use GitHub mirror? I am more familiar with that tool.

'git am' is what we would use to apply your patch.

What you probably want is 'git format-patch'. It creates one diff file
-- in a format well suited for 'git am' on the committer side -- for
each commit since a designated one.

So let's suppose that your starting point was commit
0bfc07433cfcdda355e0. To create a patch(es) and place them in /home/
spusep/uploads, you would say​:

git format-patch -o /home/spusep/uploads 0bfc07433cfcdda355e0

The patches would be named by prepending '0001-', '0002-', etc. to a
munged version of the top line of the commit message. You would then
attach them to your email or to your post via the GUI at rt.perl.org.

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Aug 5, 2014

From creaktive@gmail.com

0001-Started-work-on-Remove-the-use-of-SVs-as-temporaries.patch
From 08e529251f904ee44b6a67d89c48f0287a761fc1 Mon Sep 17 00:00:00 2001
From: Stanislaw Pusep <creaktive@gmail.com>
Date: Thu, 24 Jul 2014 14:38:27 +0200
Subject: [PATCH 1/3] Started work on "Remove the use of SVs as temporaries in
 dump.c"

Picked this yak from Porting/todo.pod :)
This is a work in progress, some functions still use newSV*.
Also, a cleanup is planned (_sv_catpv/_sv_cpypv macros will be removed).
---
 AUTHORS   |   1 +
 dump.c    | 599 +++++++++++++++++++++++++++++++++++---------------------------
 embed.fnc |   1 +
 embed.h   |   1 +
 proto.h   |   6 +
 utf8.c    | 118 ++++++++-----
 6 files changed, 421 insertions(+), 305 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 934c50c..60fdd59 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1088,6 +1088,7 @@ Solar Designer			<solar@openwall.com>
 Spider Boardman			<spider@orb.nashua.nh.us>
 Spiros Denaxas			<s.denaxas@gmail.com>
 Sreeji K Das			<sreeji_k@yahoo.com>
+Stanislaw Pusep			<creaktive@gmail.com>
 Stas Bekman			<stas@stason.org>
 Steffen M��ller			<smueller@cpan.org>
 Steffen Schwigon		<ss5@renormalist.net>
diff --git a/dump.c b/dump.c
index d15aee6..c368794 100644
--- a/dump.c
+++ b/dump.c
@@ -73,20 +73,24 @@ struct flag_to_name {
     const char *name;
 };
 
+#define DO_SV_DUMP_BUFSIZE 5120
+#define _sv_catpv(d, s)     (my_strlcat(d, s, DO_SV_DUMP_BUFSIZE))
+#define _sv_setpv(d, s)     (my_strlcpy(d, s, DO_SV_DUMP_BUFSIZE))
+
 static void
-S_append_flags(pTHX_ SV *sv, U32 flags, const struct flag_to_name *start,
-	       const struct flag_to_name *const end)
+S_append_flags(char *s, U32 flags, const struct flag_to_name *start,
+        const struct flag_to_name *const end)
 {
     do {
-	if (flags & start->flag)
-	    sv_catpv(sv, start->name);
+        if (flags & start->flag)
+            _sv_catpv(s, start->name);
     } while (++start < end);
 }
 
-#define append_flags(sv, f, flags) \
-    S_append_flags(aTHX_ (sv), (f), (flags), C_ARRAY_END(flags))
+#define append_flags(s, f, flags) \
+    S_append_flags((s), (f), (flags), C_ARRAY_END(flags))
 
-#define generic_pv_escape(sv,s,len,utf8) pv_escape( (sv), (s), (len), \
+#define generic_pv_escape(sv,s,len,utf8) _pv_escape( aTHX_ (sv), (s), (len), \
                               (len) * (4+UTF8_MAXBYTES) + 1, NULL, \
                               PERL_PV_ESCAPE_NONASCII | PERL_PV_ESCAPE_DWIM \
                               | ((utf8) ? PERL_PV_ESCAPE_UNI : 0) )
@@ -134,10 +138,11 @@ Returns a pointer to the escaped text as held by dsv.
 #define PV_ESCAPE_OCTBUFSIZE 32
 
 char *
-Perl_pv_escape( pTHX_ SV *dsv, char const * const str, 
-                const STRLEN count, const STRLEN max, 
-                STRLEN * const escaped, const U32 flags ) 
+_pv_escape( pTHX_ char *dsv, char const * const str,
+            const STRLEN count, const STRLEN max,
+            STRLEN * const escaped, const U32 flags )
 {
+    char buf[PV_ESCAPE_OCTBUFSIZE];
     const char esc = (flags & PERL_PV_ESCAPE_RE) ? '%' : '\\';
     const char dq = (flags & PERL_PV_ESCAPE_QUOTE) ? '"' : esc;
     char octbuf[PV_ESCAPE_OCTBUFSIZE] = "%123456789ABCDF";
@@ -149,95 +154,111 @@ Perl_pv_escape( pTHX_ SV *dsv, char const * const str,
     const char * const end = pv + count; /* end of string */
     octbuf[0] = esc;
 
-    PERL_ARGS_ASSERT_PV_ESCAPE;
-
-    if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) {
-	    /* This won't alter the UTF-8 flag */
-	    sv_setpvs(dsv, "");
-    }
-    
     if ((flags & PERL_PV_ESCAPE_UNI_DETECT) && is_utf8_string((U8*)pv, count))
         isuni = 1;
-    
+
     for ( ; (pv < end && (!max || (wrote < max))) ; pv += readsize ) {
         const UV u= (isuni) ? utf8_to_uvchr_buf((U8*)pv, (U8*) end, &readsize) : (U8)*pv;
         const U8 c = (U8)u & 0xFF;
-        
+
         if ( ( u > 255 )
-	  || (flags & PERL_PV_ESCAPE_ALL)
-	  || (( ! isASCII(u) ) && (flags & (PERL_PV_ESCAPE_NONASCII|PERL_PV_ESCAPE_DWIM))))
-	{
-            if (flags & PERL_PV_ESCAPE_FIRSTCHAR) 
-                chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE, 
-                                      "%"UVxf, u);
+                || (flags & PERL_PV_ESCAPE_ALL)
+                || (( ! isASCII(u) ) && (flags & (PERL_PV_ESCAPE_NONASCII|PERL_PV_ESCAPE_DWIM))))
+        {
+            if (flags & PERL_PV_ESCAPE_FIRSTCHAR)
+                chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
+                        "%"UVxf, u);
             else
-                chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE, 
-                                      ((flags & PERL_PV_ESCAPE_DWIM) && !isuni)
-                                      ? "%cx%02"UVxf
-                                      : "%cx{%02"UVxf"}", esc, u);
+                chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
+                        ((flags & PERL_PV_ESCAPE_DWIM) && !isuni)
+                        ? "%cx%02"UVxf
+                        : "%cx{%02"UVxf"}", esc, u);
 
         } else if (flags & PERL_PV_ESCAPE_NOBACKSLASH) {
-            chsize = 1;            
-        } else {         
+            chsize = 1;
+        } else {
             if ( (c == dq) || (c == esc) || !isPRINT(c) ) {
-	        chsize = 2;
+                chsize = 2;
                 switch (c) {
-                
-		case '\\' : /* FALLTHROUGH */
-		case '%'  : if ( c == esc )  {
-		                octbuf[1] = esc;  
-		            } else {
-		                chsize = 1;
-		            }
-		            break;
-		case '\v' : octbuf[1] = 'v';  break;
-		case '\t' : octbuf[1] = 't';  break;
-		case '\r' : octbuf[1] = 'r';  break;
-		case '\n' : octbuf[1] = 'n';  break;
-		case '\f' : octbuf[1] = 'f';  break;
-                case '"'  : 
-                        if ( dq == '"' ) 
-				octbuf[1] = '"';
-                        else 
-                            chsize = 1;
-                        break;
-		default:
-                     if ( (flags & PERL_PV_ESCAPE_DWIM) && c != '\0' ) {
-                        chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
-                                      isuni ? "%cx{%02"UVxf"}" : "%cx%02"UVxf,
-                                      esc, u);
-                     }
-                     else if ( (pv+readsize < end) && isDIGIT((U8)*(pv+readsize)) )
-                            chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE, 
-                                                  "%c%03o", esc, c);
-			else
-                            chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE, 
-                                                  "%c%o", esc, c);
+
+                    case '\\' : /* FALLTHROUGH */
+                    case '%'  : if ( c == esc )  {
+                                    octbuf[1] = esc;
+                                } else {
+                                    chsize = 1;
+                                }
+                                break;
+                    case '\v' : octbuf[1] = 'v';  break;
+                    case '\t' : octbuf[1] = 't';  break;
+                    case '\r' : octbuf[1] = 'r';  break;
+                    case '\n' : octbuf[1] = 'n';  break;
+                    case '\f' : octbuf[1] = 'f';  break;
+                    case '"'  :
+                                if ( dq == '"' )
+                                    octbuf[1] = '"';
+                                else
+                                    chsize = 1;
+                                break;
+                    default:
+                                if ( (flags & PERL_PV_ESCAPE_DWIM) && c != '\0' ) {
+                                    chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
+                                            isuni ? "%cx{%02"UVxf"}" : "%cx%02"UVxf,
+                                            esc, u);
+                                }
+                                else if ( (pv+readsize < end) && isDIGIT((U8)*(pv+readsize)) )
+                                    chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
+                                            "%c%03o", esc, c);
+                                else
+                                    chsize = my_snprintf( octbuf, PV_ESCAPE_OCTBUFSIZE,
+                                            "%c%o", esc, c);
                 }
             } else {
                 chsize = 1;
             }
-	}
-	if ( max && (wrote + chsize > max) ) {
-	    break;
+        }
+        if ( max && (wrote + chsize > max) ) {
+            break;
         } else if (chsize > 1) {
-            sv_catpvn(dsv, octbuf, chsize);
+            my_strlcpy(buf, "", 1);
+            my_strlcpy(buf, octbuf, chsize + 1);
+            _sv_catpv(dsv, buf);
             wrote += chsize;
-	} else {
-	    /* If PERL_PV_ESCAPE_NOBACKSLASH is set then non-ASCII bytes
-	       can be appended raw to the dsv. If dsv happens to be
-	       UTF-8 then we need catpvf to upgrade them for us.
-	       Or add a new API call sv_catpvc(). Think about that name, and
-	       how to keep it clear that it's unlike the s of catpvs, which is
-	       really an array of octets, not a string.  */
-            Perl_sv_catpvf( aTHX_ dsv, "%c", c);
-	    wrote++;
-	}
-        if ( flags & PERL_PV_ESCAPE_FIRSTCHAR ) 
+        } else {
+            /* If PERL_PV_ESCAPE_NOBACKSLASH is set then non-ASCII bytes
+               can be appended raw to the dsv. If dsv happens to be
+               UTF-8 then we need catpvf to upgrade them for us.
+               Or add a new API call sv_catpvc(). Think about that name, and
+               how to keep it clear that it's unlike the s of catpvs, which is
+               really an array of octets, not a string.  */
+            my_snprintf(buf, sizeof(buf), "%c", c);
+            _sv_catpv(dsv, buf);
+            wrote++;
+        }
+        if ( flags & PERL_PV_ESCAPE_FIRSTCHAR )
             break;
     }
     if (escaped != NULL)
         *escaped= pv - str;
+    return dsv;
+}
+
+char *
+Perl_pv_escape( pTHX_ SV *dsv, char const * const str,
+                const STRLEN count, const STRLEN max,
+                STRLEN * const escaped, const U32 flags )
+{
+    char *buf;
+    PERL_ARGS_ASSERT_PV_ESCAPE;
+
+    if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) {
+        /* This won't alter the UTF-8 flag */
+        sv_setpvs(dsv, "");
+    }
+
+    Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
+    sv_catpv(dsv, _pv_escape(aTHX_ buf, str, count, max, escaped, flags));
+    Safefree(buf);
+
     return SvPVX(dsv);
 }
 /*
@@ -266,44 +287,56 @@ Returns a pointer to the prettified text as held by dsv.
 */
 
 char *
-Perl_pv_pretty( pTHX_ SV *dsv, char const * const str, const STRLEN count, 
-  const STRLEN max, char const * const start_color, char const * const end_color, 
-  const U32 flags ) 
+_pv_pretty( pTHX_ char *dsv, char const * const str, const STRLEN count,
+            const STRLEN max, char const * const start_color, char const * const end_color,
+            const U32 flags )
 {
     const U8 dq = (flags & PERL_PV_PRETTY_QUOTE) ? '"' : '%';
     STRLEN escaped;
- 
-    PERL_ARGS_ASSERT_PV_PRETTY;
-   
-    if (!(flags & PERL_PV_PRETTY_NOCLEAR)) {
-	    /* This won't alter the UTF-8 flag */
-	    sv_setpvs(dsv, "");
-    }
 
     if ( dq == '"' )
-        sv_catpvs(dsv, "\"");
+        _sv_catpv(dsv, "\"");
     else if ( flags & PERL_PV_PRETTY_LTGT )
-        sv_catpvs(dsv, "<");
-        
-    if ( start_color != NULL ) 
-        sv_catpv(dsv, start_color);
-    
-    pv_escape( dsv, str, count, max, &escaped, flags | PERL_PV_ESCAPE_NOCLEAR );    
-    
-    if ( end_color != NULL ) 
-        sv_catpv(dsv, end_color);
-
-    if ( dq == '"' ) 
-	sv_catpvs( dsv, "\"");
+        _sv_catpv(dsv, "<");
+
+    if ( start_color != NULL )
+        _sv_catpv(dsv, start_color);
+
+    _pv_escape( aTHX_ dsv, str, count, max, &escaped, flags );
+
+    if ( end_color != NULL )
+        _sv_catpv(dsv, end_color);
+
+    if ( dq == '"' )
+        _sv_catpv( dsv, "\"");
     else if ( flags & PERL_PV_PRETTY_LTGT )
-        sv_catpvs(dsv, ">");         
-    
+        _sv_catpv(dsv, ">");
+
     if ( (flags & PERL_PV_PRETTY_ELLIPSES) && ( escaped < count ) )
-	    sv_catpvs(dsv, "...");
- 
-    return SvPVX(dsv);
+        _sv_catpv(dsv, "...");
+
+    return dsv;
 }
 
+char *
+Perl_pv_pretty( pTHX_ SV *dsv, char const * const str, const STRLEN count,
+  const STRLEN max, char const * const start_color, char const * const end_color,
+  const U32 flags )
+{
+    char *buf;
+    PERL_ARGS_ASSERT_PV_PRETTY;
+
+    if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) {
+        /* This won't alter the UTF-8 flag */
+        sv_setpvs(dsv, "");
+    }
+
+    Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
+    sv_catpv(dsv, _pv_pretty(aTHX_ buf, str, count, max, start_color, end_color, flags));
+    Safefree(buf);
+
+    return SvPVX(dsv);
+}
 /*
 =for apidoc pv_display
 
@@ -320,17 +353,39 @@ Note that the final string may be up to 7 chars longer than pvlim.
 */
 
 char *
+_pv_display( pTHX_ char *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim)
+{
+    _sv_setpv(dsv, "");
+    _pv_pretty( aTHX_ dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP);
+    if (len > cur && pv[cur] == '\0')
+        _sv_catpv( dsv, "\\0");
+    return dsv;
+}
+
+char *
 Perl_pv_display(pTHX_ SV *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim)
 {
+    char *buf;
     PERL_ARGS_ASSERT_PV_DISPLAY;
 
-    pv_pretty( dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP);
-    if (len > cur && pv[cur] == '\0')
-            sv_catpvs( dsv, "\\0");
+    Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
+    sv_setpv(dsv, _pv_display(aTHX_ buf, pv, cur, len, pvlim));
+    Safefree(buf);
+
     return SvPVX(dsv);
 }
 
 char *
+_sv_uni_display( pTHX_ char *dest, SV *ssv, STRLEN pvlim, UV flags)
+{
+    STRLEN len = SvCUR(ssv);
+    U8 *spv = (U8 *)
+        (isREGEXP(ssv) ? RX_WRAPPED((REGEXP*)ssv) : SvPVX_const(ssv));
+
+    return str_uni_display(dest, DO_SV_DUMP_BUFSIZE, spv, len, pvlim, flags);
+}
+
+char *
 Perl_sv_peek(pTHX_ SV *sv)
 {
     dVAR;
@@ -421,11 +476,12 @@ Perl_sv_peek(pTHX_ SV *sv)
     }
     type = SvTYPE(sv);
     if (type == SVt_PVCV) {
-        SV * const tmp = newSVpvs_flags("", SVs_TEMP);
         GV* gvcv = CvGV(sv);
+        char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
         Perl_sv_catpvf(aTHX_ t, "CV(%s)", gvcv
                        ? generic_pv_escape( tmp, GvNAME(gvcv), GvNAMELEN(gvcv), GvNAMEUTF8(gvcv))
                        : "");
+        Safefree(tmp);
 	goto finish;
     } else if (type < SVt_LAST) {
 	sv_catpv(t, svshorttypenames[type]);
@@ -580,19 +636,19 @@ Perl_dump_sub_perl(pTHX_ const GV *gv, bool justperl)
 {
     STRLEN len;
     SV * const sv = newSVpvs_flags("", SVs_TEMP);
-    SV *tmpsv;
     const char * name;
+    char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 
     PERL_ARGS_ASSERT_DUMP_SUB_PERL;
 
     if (justperl && (CvISXSUB(GvCV(gv)) || !CvROOT(GvCV(gv))))
 	return;
 
-    tmpsv = newSVpvs_flags("", SVs_TEMP);
     gv_fullname3(sv, gv, NULL);
     name = SvPV_const(sv, len);
     Perl_dump_indent(aTHX_ 0, Perl_debug_log, "\nSUB %s = ",
-                     generic_pv_escape(tmpsv, name, len, SvUTF8(sv)));
+                     generic_pv_escape(tmp, name, len, SvUTF8(sv)));
+    Safefree(tmp);
     if (CvISXSUB(GvCV(gv)))
 	Perl_dump_indent(aTHX_ 0, Perl_debug_log, "(xsub 0x%"UVxf" %d)\n",
 	    PTR2UV(CvXSUB(GvCV(gv))),
@@ -685,37 +741,42 @@ const struct flag_to_name pmflags_flags_names[] = {
 static SV *
 S_pm_description(pTHX_ const PMOP *pm)
 {
-    SV * const desc = newSVpvs("");
+    char *desc;
+    SV *sv;
     const REGEXP * const regex = PM_GETRE(pm);
     const U32 pmflags = pm->op_pmflags;
 
     PERL_ARGS_ASSERT_PM_DESCRIPTION;
 
+    Newxz(desc, DO_SV_DUMP_BUFSIZE, char);
+
     if (pmflags & PMf_ONCE)
-	sv_catpv(desc, ",ONCE");
+	_sv_catpv(desc, ",ONCE");
 #ifdef USE_ITHREADS
     if (SvREADONLY(PL_regex_pad[pm->op_pmoffset]))
-        sv_catpv(desc, ":USED");
+        _sv_catpv(desc, ":USED");
 #else
     if (pmflags & PMf_USED)
-        sv_catpv(desc, ":USED");
+        _sv_catpv(desc, ":USED");
 #endif
 
     if (regex) {
         if (RX_ISTAINTED(regex))
-            sv_catpv(desc, ",TAINTED");
+            _sv_catpv(desc, ",TAINTED");
         if (RX_CHECK_SUBSTR(regex)) {
             if (!(RX_INTFLAGS(regex) & PREGf_NOSCAN))
-                sv_catpv(desc, ",SCANFIRST");
+                _sv_catpv(desc, ",SCANFIRST");
             if (RX_EXTFLAGS(regex) & RXf_CHECK_ALL)
-                sv_catpv(desc, ",ALL");
+                _sv_catpv(desc, ",ALL");
         }
         if (RX_EXTFLAGS(regex) & RXf_SKIPWHITE)
-            sv_catpv(desc, ",SKIPWHITE");
+            _sv_catpv(desc, ",SKIPWHITE");
     }
 
     append_flags(desc, pmflags, pmflags_flags_names);
-    return desc;
+    sv = newSVpv(desc, 0);
+    Safefree(desc);
+    return sv;
 }
 
 void
@@ -863,57 +924,58 @@ const struct op_private_by_op op_private_names[] = {
 };
 
 static bool
-S_op_private_to_names(pTHX_ SV *tmpsv, U32 optype, U32 op_private) {
+S_op_private_to_names(char *tmp, U32 optype, U32 op_private) {
     const struct op_private_by_op *start = op_private_names;
     const struct op_private_by_op *const end = C_ARRAY_END(op_private_names);
 
     /* This is a linear search, but no worse than the code that it replaced.
        It's debugging code - size is more important than speed.  */
     do {
-	if (optype == start->op_type) {
-	    S_append_flags(aTHX_ tmpsv, op_private, start->start,
-			   start->start + start->len);
-	    return TRUE;
-	}
+        if (optype == start->op_type) {
+            S_append_flags(tmp, op_private, start->start,
+                    start->start + start->len);
+            return TRUE;
+        }
     } while (++start < end);
     return FALSE;
 }
 
 #define DUMP_OP_FLAGS(o,level,file)                                 \
     if (o->op_flags || o->op_slabbed || o->op_savefree || o->op_static) { \
-        SV * const tmpsv = newSVpvs("");                                \
+        char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);                \
         switch (o->op_flags & OPf_WANT) {                               \
         case OPf_WANT_VOID:                                             \
-            sv_catpv(tmpsv, ",VOID");                                   \
+            _sv_catpv(tmp, ",VOID");                                    \
             break;                                                      \
         case OPf_WANT_SCALAR:                                           \
-            sv_catpv(tmpsv, ",SCALAR");                                 \
+            _sv_catpv(tmp, ",SCALAR");                                  \
             break;                                                      \
         case OPf_WANT_LIST:                                             \
-            sv_catpv(tmpsv, ",LIST");                                   \
+            _sv_catpv(tmp, ",LIST");                                    \
             break;                                                      \
         default:                                                        \
-            sv_catpv(tmpsv, ",UNKNOWN");                                \
+            _sv_catpv(tmp, ",UNKNOWN");                                 \
             break;                                                      \
         }                                                               \
-        append_flags(tmpsv, o->op_flags, op_flags_names);               \
-        if (o->op_slabbed)  sv_catpvs(tmpsv, ",SLABBED");               \
-        if (o->op_savefree) sv_catpvs(tmpsv, ",SAVEFREE");              \
-        if (o->op_static)   sv_catpvs(tmpsv, ",STATIC");                \
-        if (o->op_folded)   sv_catpvs(tmpsv, ",FOLDED");                \
-        if (o->op_lastsib)  sv_catpvs(tmpsv, ",LASTSIB");               \
+        append_flags(tmp, o->op_flags, op_flags_names);                 \
+        if (o->op_slabbed)  _sv_catpv(tmp, ",SLABBED");                 \
+        if (o->op_savefree) _sv_catpv(tmp, ",SAVEFREE");                \
+        if (o->op_static)   _sv_catpv(tmp, ",STATIC");                  \
+        if (o->op_folded)   _sv_catpv(tmp, ",FOLDED");                  \
+        if (o->op_lastsib)  _sv_catpv(tmp, ",LASTSIB");                 \
         Perl_dump_indent(aTHX_ level, file, "FLAGS = (%s)\n",           \
-                         SvCUR(tmpsv) ? SvPVX_const(tmpsv) + 1 : "");   \
+                         strlen(tmp) ? tmp + 1 : "");                   \
     }
 
 #define DUMP_OP_PRIVATE(o,level,file)                                   \
     if (o->op_private) {                                                \
         U32 optype = o->op_type;                                        \
         U32 oppriv = o->op_private;                                     \
-        SV * const tmpsv = newSVpvs("");                                \
+        char *tmp, tmp2[PV_ESCAPE_OCTBUFSIZE];                          \
+        Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);                           \
 	if (PL_opargs[optype] & OA_TARGLEX) {                           \
 	    if (oppriv & OPpTARGET_MY)                                  \
-		sv_catpv(tmpsv, ",TARGET_MY");                          \
+		_sv_catpv(tmp, ",TARGET_MY");                           \
 	}                                                               \
 	else if (optype == OP_ENTERSUB ||                               \
                  optype == OP_RV2SV ||                                  \
@@ -925,70 +987,72 @@ S_op_private_to_names(pTHX_ SV *tmpsv, U32 optype, U32 op_private) {
                  optype == OP_HELEM )                                   \
         {                                                               \
             if (optype == OP_ENTERSUB) {                                \
-                append_flags(tmpsv, oppriv, op_entersub_names);         \
+                append_flags(tmp, oppriv, op_entersub_names);           \
             }                                                           \
             else {                                                      \
                 switch (oppriv & OPpDEREF) {                            \
                 case OPpDEREF_SV:                                       \
-                    sv_catpv(tmpsv, ",SV");                             \
+                    _sv_catpv(tmp, ",SV");                              \
                     break;                                              \
                 case OPpDEREF_AV:                                       \
-                    sv_catpv(tmpsv, ",AV");                             \
+                    _sv_catpv(tmp, ",AV");                              \
                     break;                                              \
                 case OPpDEREF_HV:                                       \
-                    sv_catpv(tmpsv, ",HV");                             \
+                    _sv_catpv(tmp, ",HV");                              \
                     break;                                              \
                 }                                                       \
                 if (oppriv & OPpMAYBE_LVSUB)                            \
-                    sv_catpv(tmpsv, ",MAYBE_LVSUB");                    \
+                    _sv_catpv(tmp, ",MAYBE_LVSUB");                     \
             }                                                           \
             if (optype == OP_AELEM || optype == OP_HELEM) {             \
                 if (oppriv & OPpLVAL_DEFER)                             \
-                    sv_catpv(tmpsv, ",LVAL_DEFER");                     \
+                    _sv_catpv(tmp, ",LVAL_DEFER");                      \
             }                                                           \
             else if (optype == OP_RV2HV || optype == OP_PADHV) {        \
                 if (oppriv & OPpMAYBE_TRUEBOOL)                         \
-                    sv_catpvs(tmpsv, ",OPpMAYBE_TRUEBOOL");             \
+                    _sv_catpv(tmp, ",OPpMAYBE_TRUEBOOL");               \
                 if (oppriv & OPpTRUEBOOL)                               \
-                    sv_catpvs(tmpsv, ",OPpTRUEBOOL");                   \
+                    _sv_catpv(tmp, ",OPpTRUEBOOL");                     \
             }                                                           \
             else {                                                      \
                 if (oppriv & HINT_STRICT_REFS)                          \
-                    sv_catpv(tmpsv, ",STRICT_REFS");                    \
+                    _sv_catpv(tmp, ",STRICT_REFS");                     \
                 if (oppriv & OPpOUR_INTRO)                              \
-                    sv_catpv(tmpsv, ",OUR_INTRO");                      \
+                    _sv_catpv(tmp, ",OUR_INTRO");                       \
             }                                                           \
         }                                                               \
-	else if (S_op_private_to_names(aTHX_ tmpsv, optype, oppriv)) {  \
+	else if (S_op_private_to_names(tmp, optype, oppriv)) {          \
 	}                                                               \
 	else if (OP_IS_FILETEST(o->op_type)) {                          \
             if (oppriv & OPpFT_ACCESS)                                  \
-                sv_catpv(tmpsv, ",FT_ACCESS");                          \
+                _sv_catpv(tmp, ",FT_ACCESS");                           \
             if (oppriv & OPpFT_STACKED)                                 \
-                sv_catpv(tmpsv, ",FT_STACKED");                         \
+                _sv_catpv(tmp, ",FT_STACKED");                          \
             if (oppriv & OPpFT_STACKING)                                \
-                sv_catpv(tmpsv, ",FT_STACKING");                        \
+                _sv_catpv(tmp, ",FT_STACKING");                         \
             if (oppriv & OPpFT_AFTER_t)                                 \
-                sv_catpv(tmpsv, ",AFTER_t");                            \
+                _sv_catpv(tmp, ",AFTER_t");                             \
 	}                                                               \
 	else if (o->op_type == OP_AASSIGN) {                            \
 	    if (oppriv & OPpASSIGN_COMMON)                              \
-		sv_catpvs(tmpsv, ",COMMON");                            \
+		_sv_catpv(tmp, ",COMMON");                              \
 	    if (oppriv & OPpMAYBE_LVSUB)                                \
-		sv_catpvs(tmpsv, ",MAYBE_LVSUB");                       \
+		_sv_catpv(tmp, ",MAYBE_LVSUB");                         \
 	}                                                               \
 	if (o->op_flags & OPf_MOD && oppriv & OPpLVAL_INTRO)            \
-	    sv_catpv(tmpsv, ",INTRO");                                  \
-	if (o->op_type == OP_PADRANGE)                                  \
-	    Perl_sv_catpvf(aTHX_ tmpsv, ",COUNT=%"UVuf,                 \
+	    _sv_catpv(tmp, ",INTRO");                                   \
+	if (o->op_type == OP_PADRANGE) {                                \
+            my_snprintf(tmp2, sizeof(tmp2), ",COUNT=%"UVuf,             \
                            (UV)(oppriv & OPpPADRANGE_COUNTMASK));       \
+            _sv_catpv(tmp, tmp2);                                       \
+        }                                                               \
         if (  (o->op_type == OP_RV2HV || o->op_type == OP_RV2AV ||      \
                o->op_type == OP_PADAV || o->op_type == OP_PADHV ||      \
                o->op_type == OP_ASLICE || o->op_type == OP_HSLICE)      \
            && oppriv & OPpSLICEWARNING  )                               \
-            sv_catpvs(tmpsv, ",SLICEWARNING");                          \
-	if (SvCUR(tmpsv)) {                                             \
-            Perl_dump_indent(aTHX_ level, file, "PRIVATE = (%s)\n", SvPVX_const(tmpsv) + 1); \
+            _sv_catpv(tmp, ",SLICEWARNING");                            \
+	if (strlen(tmp)) {                                              \
+            Perl_dump_indent(aTHX_ level, file, "PRIVATE = (%s)\n", tmp + 1); \
 	} else                                                          \
             Perl_dump_indent(aTHX_ level, file, "PRIVATE = (0x%"UVxf")\n", \
                              (UV)oppriv);                               \
@@ -1027,22 +1091,24 @@ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, const OP *o)
 		    Perl_dump_indent(aTHX_ level, file, "LINE = %"UVuf"\n",
 				     (UV)CopLINE(cCOPo));
         if (CopSTASHPV(cCOPo)) {
-            SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
             HV *stash = CopSTASH(cCOPo);
             const char * const hvname = HvNAME_get(stash);
+            char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 
 		    Perl_dump_indent(aTHX_ level, file, "PACKAGE = \"%s\"\n",
-                           generic_pv_escape( tmpsv, hvname, HvNAMELEN(stash), HvNAMEUTF8(stash)));
+                           generic_pv_escape( tmp, hvname, HvNAMELEN(stash), HvNAMEUTF8(stash)));
+            Safefree(tmp);
        }
      if (CopLABEL(cCOPo)) {
-          SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
           STRLEN label_len;
           U32 label_flags;
           const char *label = CopLABEL_len_flags(cCOPo,
                                                  &label_len,
                                                  &label_flags);
+          char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 		    Perl_dump_indent(aTHX_ level, file, "LABEL = \"%s\"\n",
-                           generic_pv_escape( tmpsv, label, label_len,(label_flags & SVf_UTF8)));
+                           generic_pv_escape( tmp, label, label_len,(label_flags & SVf_UTF8)));
+          Safefree(tmp);
       }
 
 	    }
@@ -1070,11 +1136,11 @@ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, const OP *o)
       STRLEN len;
       const char * name;
       SV * const tmpsv  = newSVpvs_flags("", SVs_TEMP);
-      SV * const tmpsv2 = newSVpvs_flags("", SVs_TEMP);
+      char *tmp2; Newxz(tmp2, DO_SV_DUMP_BUFSIZE, char);
 		gv_fullname3(tmpsv, MUTABLE_GV(cSVOPo->op_sv), NULL);
       name = SvPV_const(tmpsv, len);
 		Perl_dump_indent(aTHX_ level, file, "GV = %s\n",
-                       generic_pv_escape( tmpsv2, name, len, SvUTF8(tmpsv)));
+                       generic_pv_escape( tmp2, name, len, SvUTF8(tmpsv)));
 	    }
 	    else
 		Perl_dump_indent(aTHX_ level, file, "GV = NULL\n");
@@ -1096,23 +1162,25 @@ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, const OP *o)
 	    Perl_dump_indent(aTHX_ level, file, "LINE = %"UVuf"\n",
 			     (UV)CopLINE(cCOPo));
     if (CopSTASHPV(cCOPo)) {
-        SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
         HV *stash = CopSTASH(cCOPo);
         const char * const hvname = HvNAME_get(stash);
+        char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
         
 	    Perl_dump_indent(aTHX_ level, file, "PACKAGE = \"%s\"\n",
-                           generic_pv_escape(tmpsv, hvname,
+                           generic_pv_escape(tmp, hvname,
                               HvNAMELEN(stash), HvNAMEUTF8(stash)));
+        Safefree(tmp);
     }
   if (CopLABEL(cCOPo)) {
-       SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
        STRLEN label_len;
        U32 label_flags;
        const char *label = CopLABEL_len_flags(cCOPo,
                                                 &label_len, &label_flags);
+       char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
        Perl_dump_indent(aTHX_ level, file, "LABEL = \"%s\"\n",
-                           generic_pv_escape( tmpsv, label, label_len,
+                           generic_pv_escape( tmp, label, label_len,
                                       (label_flags & SVf_UTF8)));
+       Safefree(tmp);
    }
 	break;
     case OP_ENTERLOOP:
@@ -1190,7 +1258,8 @@ Perl_gv_dump(pTHX_ GV *gv)
 {
     STRLEN len;
     const char* name;
-    SV *sv, *tmp = newSVpvs_flags("", SVs_TEMP);
+    SV *sv;
+    char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 
 
     PERL_ARGS_ASSERT_GV_DUMP;
@@ -1205,12 +1274,14 @@ Perl_gv_dump(pTHX_ GV *gv)
     name = SvPV_const(sv, len);
     Perl_dump_indent(aTHX_ 1, Perl_debug_log, "GV_NAME = %s",
                      generic_pv_escape( tmp, name, len, SvUTF8(sv) ));
+    _sv_setpv(tmp, "");
     if (gv != GvEGV(gv)) {
 	gv_efullname3(sv, GvEGV(gv), NULL);
         name = SvPV_const(sv, len);
         Perl_dump_indent(aTHX_ 1, Perl_debug_log, "-> %s",
                      generic_pv_escape( tmp, name, len, SvUTF8(sv) ));
     }
+    Safefree(tmp);
     PerlIO_putc(Perl_debug_log, '\n');
     Perl_dump_indent(aTHX_ 0, Perl_debug_log, "}\n");
 }
@@ -1369,10 +1440,11 @@ Perl_do_hv_dump(pTHX_ I32 level, PerlIO *file, const char *name, HV *sv)
            name which quite legally could contain insane things like tabs, newlines, nulls or
            other scary crap - this should produce sane results - except maybe for unicode package
            names - but we will wait for someone to file a bug on that - demerphq */
-        SV * const tmpsv = newSVpvs_flags("", SVs_TEMP);
+        char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
         PerlIO_printf(file, "\t\"%s\"\n",
-                              generic_pv_escape( tmpsv, hvname,
+                              generic_pv_escape( tmp, hvname,
                                    HvNAMELEN(sv), HvNAMEUTF8(sv)));
+        Safefree(tmp);
     }
     else
 	PerlIO_putc(file, '\n');
@@ -1385,9 +1457,10 @@ Perl_do_gv_dump(pTHX_ I32 level, PerlIO *file, const char *name, GV *sv)
 
     Perl_dump_indent(aTHX_ level, file, "%s = 0x%"UVxf, name, PTR2UV(sv));
     if (sv && GvNAME(sv)) {
-        SV * const tmpsv = newSVpvs("");
+        char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
         PerlIO_printf(file, "\t\"%s\"\n",
-                              generic_pv_escape( tmpsv, GvNAME(sv), GvNAMELEN(sv), GvNAMEUTF8(sv) ));
+                              generic_pv_escape( tmp, GvNAME(sv), GvNAMELEN(sv), GvNAMEUTF8(sv) ));
+        Safefree(tmp);
     }
     else
 	PerlIO_putc(file, '\n');
@@ -1400,18 +1473,20 @@ Perl_do_gvgv_dump(pTHX_ I32 level, PerlIO *file, const char *name, GV *sv)
 
     Perl_dump_indent(aTHX_ level, file, "%s = 0x%"UVxf, name, PTR2UV(sv));
     if (sv && GvNAME(sv)) {
-       SV *tmp = newSVpvs_flags("", SVs_TEMP);
 	const char *hvname;
         HV * const stash = GvSTASH(sv);
+        char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 	PerlIO_printf(file, "\t");
    /* TODO might have an extra \" here */
 	if (stash && (hvname = HvNAME_get(stash))) {
             PerlIO_printf(file, "\"%s\" :: \"",
                                   generic_pv_escape(tmp, hvname,
                                       HvNAMELEN(stash), HvNAMEUTF8(stash)));
+            _sv_setpv(tmp, "");
         }
         PerlIO_printf(file, "%s\"\n",
                               generic_pv_escape( tmp, GvNAME(sv), GvNAMELEN(sv), GvNAMEUTF8(sv)));
+        Safefree(tmp);
     }
     else
 	PerlIO_putc(file, '\n');
@@ -1529,8 +1604,8 @@ const struct flag_to_name regexp_core_intflags_names[] = {
 void
 Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bool dumpops, STRLEN pvlim)
 {
-    SV *d;
-    const char *s;
+    char *d;
+    STRLEN len;
     U32 flags;
     U32 type;
 
@@ -1546,34 +1621,35 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 
     /* process general SV flags */
 
-    d = Perl_newSVpvf(aTHX_
-		   "(0x%"UVxf") at 0x%"UVxf"\n%*s  REFCNT = %"IVdf"\n%*s  FLAGS = (",
-		   PTR2UV(SvANY(sv)), PTR2UV(sv),
-		   (int)(PL_dumpindent*level), "", (IV)SvREFCNT(sv),
-		   (int)(PL_dumpindent*level), "");
+    Newx(d, DO_SV_DUMP_BUFSIZE, char);
+    my_snprintf(d, DO_SV_DUMP_BUFSIZE,
+                   "(0x%"UVxf") at 0x%"UVxf"\n%*s  REFCNT = %"IVdf"\n%*s  FLAGS = (",
+                   PTR2UV(SvANY(sv)), PTR2UV(sv),
+                   (int)(PL_dumpindent*level), "", (IV)SvREFCNT(sv),
+                   (int)(PL_dumpindent*level), "");
 
     if (!((flags & SVpad_NAME) == SVpad_NAME
 	  && (type == SVt_PVMG || type == SVt_PVNV))) {
 	if ((flags & SVs_PADMY) && (flags & SVs_PADSTALE))
-	    sv_catpv(d, "PADSTALE,");
+	    _sv_catpv(d, "PADSTALE,");
     }
     if (!((flags & SVpad_NAME) == SVpad_NAME && type == SVt_PVMG)) {
 	if (!(flags & SVs_PADMY) && (flags & SVs_PADTMP))
-	    sv_catpv(d, "PADTMP,");
-	if (flags & SVs_PADMY)	sv_catpv(d, "PADMY,");
+	    _sv_catpv(d, "PADTMP,");
+	if (flags & SVs_PADMY)	_sv_catpv(d, "PADMY,");
     }
     append_flags(d, flags, first_sv_flags_names);
     if (flags & SVf_ROK)  {	
-    				sv_catpv(d, "ROK,");
-	if (SvWEAKREF(sv))	sv_catpv(d, "WEAKREF,");
+    				_sv_catpv(d, "ROK,");
+	if (SvWEAKREF(sv))	_sv_catpv(d, "WEAKREF,");
     }
     append_flags(d, flags, second_sv_flags_names);
     if (flags & SVp_SCREAM && type != SVt_PVHV && !isGV_with_GP(sv)
 			   && type != SVt_PVAV) {
 	if (SvPCS_IMPORTED(sv))
-				sv_catpv(d, "PCS_IMPORTED,");
+				_sv_catpv(d, "PCS_IMPORTED,");
 	else
-				sv_catpv(d, "SCREAM,");
+				_sv_catpv(d, "SCREAM,");
     }
 
     /* process type-specific SV flags */
@@ -1592,44 +1668,42 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	    append_flags(d, GvFLAGS(sv), gp_flags_names);
 	}
 	if (isGV_with_GP(sv) && GvIMPORTED(sv)) {
-	    sv_catpv(d, "IMPORT");
+	    _sv_catpv(d, "IMPORT");
 	    if (GvIMPORTED(sv) == GVf_IMPORTED)
-		sv_catpv(d, "ALL,");
+		_sv_catpv(d, "ALL,");
 	    else {
-		sv_catpv(d, "(");
+		_sv_catpv(d, "(");
 		append_flags(d, GvFLAGS(sv), gp_flags_imported_names);
-		sv_catpv(d, " ),");
+		_sv_catpv(d, " ),");
 	    }
 	}
 	/* FALLTHROUGH */
     default:
     evaled_or_uv:
-	if (SvEVALED(sv))	sv_catpv(d, "EVALED,");
-	if (SvIsUV(sv) && !(flags & SVf_ROK))	sv_catpv(d, "IsUV,");
+	if (SvEVALED(sv))	_sv_catpv(d, "EVALED,");
+	if (SvIsUV(sv) && !(flags & SVf_ROK))	_sv_catpv(d, "IsUV,");
 	break;
     case SVt_PVMG:
-	if (SvTAIL(sv))		sv_catpv(d, "TAIL,");
-	if (SvVALID(sv))	sv_catpv(d, "VALID,");
-	if (SvPAD_TYPED(sv))	sv_catpv(d, "TYPED,");
-	if (SvPAD_OUR(sv))	sv_catpv(d, "OUR,");
+	if (SvTAIL(sv))		_sv_catpv(d, "TAIL,");
+	if (SvVALID(sv))	_sv_catpv(d, "VALID,");
+	if (SvPAD_TYPED(sv))	_sv_catpv(d, "TYPED,");
+	if (SvPAD_OUR(sv))	_sv_catpv(d, "OUR,");
 	/* FALLTHROUGH */
     case SVt_PVNV:
-	if (SvPAD_STATE(sv))	sv_catpv(d, "STATE,");
+	if (SvPAD_STATE(sv))	_sv_catpv(d, "STATE,");
 	goto evaled_or_uv;
     case SVt_PVAV:
-	if (AvPAD_NAMELIST(sv))	sv_catpvs(d, "NAMELIST,");
+	if (AvPAD_NAMELIST(sv))	_sv_catpv(d, "NAMELIST,");
 	break;
     }
     /* SVphv_SHAREKEYS is also 0x20000000 */
     if ((type != SVt_PVHV) && SvUTF8(sv))
-        sv_catpv(d, "UTF8");
+        _sv_catpv(d, "UTF8");
 
-    if (*(SvEND(d) - 1) == ',') {
-        SvCUR_set(d, SvCUR(d) - 1);
-	SvPVX(d)[SvCUR(d)] = '\0';
-    }
-    sv_catpv(d, ")");
-    s = SvPVX_const(d);
+    len = strlen(d);
+    if (d[len - 1] == ',')
+        d[len - 1] = '\0';
+    _sv_catpv(d, ")");
 
     /* dump initial SV details */
 
@@ -1649,15 +1723,15 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
     /* Dump SV type */
 
     if (type < SVt_LAST) {
-	PerlIO_printf(file, "%s%s\n", svtypenames[type], s);
+	PerlIO_printf(file, "%s%s\n", svtypenames[type], d);
 
 	if (type ==  SVt_NULL) {
-	    SvREFCNT_dec_NN(d);
+	    Safefree(d);
 	    return;
 	}
     } else {
-	PerlIO_printf(file, "UNKNOWN(0x%"UVxf") %s\n", (UV)type, s);
-	SvREFCNT_dec_NN(d);
+	PerlIO_printf(file, "UNKNOWN(0x%"UVxf") %s\n", (UV)type, d);
+	Safefree(d);
 	return;
     }
 
@@ -1711,7 +1785,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
     }
 
     if (type < SVt_PV) {
-	SvREFCNT_dec_NN(d);
+	Safefree(d);
 	return;
     }
 
@@ -1732,7 +1806,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	    Perl_dump_indent(aTHX_ level, file,"  PV = 0x%"UVxf" ", PTR2UV(ptr));
 	    if (SvOOK(sv)) {
 		PerlIO_printf(file, "( %s . ) ",
-			      pv_display(d, ptr - delta, delta, 0,
+			      _pv_display(aTHX_ d, ptr - delta, delta, 0,
 					 pvlim));
 	    }
             if (type == SVt_INVLIST) {
@@ -1741,12 +1815,12 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
                 _invlist_dump(file, level, "    ", sv);
             }
             else {
-                PerlIO_printf(file, "%s", pv_display(d, ptr, SvCUR(sv),
+                PerlIO_printf(file, "%s", _pv_display(aTHX_ d, ptr, SvCUR(sv),
                                                      re ? 0 : SvLEN(sv),
                                                      pvlim));
                 if (SvUTF8(sv)) /* the 6?  \x{....} */
                     PerlIO_printf(file, " [UTF8 \"%s\"]",
-                                         sv_uni_display(d, sv, 6 * SvCUR(sv),
+                                         _sv_uni_display(aTHX_ d, sv, 6 * SvCUR(sv),
                                                         UNI_DISPLAY_QQ));
                 PerlIO_printf(file, "\n");
             }
@@ -1802,11 +1876,11 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	if (!AvPAD_NAMELIST(sv))
 	    Perl_dump_indent(aTHX_ level, file, "  ARYLEN = 0x%"UVxf"\n",
 				   SvMAGIC(sv) ? PTR2UV(AvARYLEN(sv)) : 0);
-	sv_setpvs(d, "");
-	if (AvREAL(sv))	sv_catpv(d, ",REAL");
-	if (AvREIFY(sv))	sv_catpv(d, ",REIFY");
+	_sv_setpv(d, "");
+	if (AvREAL(sv))	_sv_catpv(d, ",REAL");
+	if (AvREIFY(sv))	_sv_catpv(d, ",REIFY");
 	Perl_dump_indent(aTHX_ level, file, "  FLAGS = (%s)\n",
-			 SvCUR(d) ? SvPVX_const(d) + 1 : "");
+			 strlen(d) ? d + 1 : "");
 	if (nest < maxnest && av_tindex(MUTABLE_AV(sv)) >= 0) {
 	    SSize_t count;
 	    for (count = 0; count <=  av_tindex(MUTABLE_AV(sv)) && count < maxnest; count++) {
@@ -1927,10 +2001,11 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	{
 	    const char * const hvname = HvNAME_get(sv);
 	    if (hvname) {
-          SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
+          char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
      Perl_dump_indent(aTHX_ level, file, "  NAME = \"%s\"\n",
-                                       generic_pv_escape( tmpsv, hvname,
+                                       generic_pv_escape( tmp, hvname,
                                            HvNAMELEN(sv), HvNAMEUTF8(sv)));
+          Safefree(tmp);
         }
 	}
 	if (SvOOK(sv)) {
@@ -1945,35 +2020,42 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	    if (HvAUX(sv)->xhv_name_u.xhvnameu_name && HvENAME_HEK_NN(sv)) {
 		const I32 count = HvAUX(sv)->xhv_name_count;
 		if (count) {
-		    SV * const names = newSVpvs_flags("", SVs_TEMP);
 		    /* The starting point is the first element if count is
 		       positive and the second element if count is negative. */
 		    HEK *const *hekp = HvAUX(sv)->xhv_name_u.xhvnameu_names
 			+ (count < 0 ? 1 : 0);
 		    HEK *const *const endp = HvAUX(sv)->xhv_name_u.xhvnameu_names
 			+ (count < 0 ? -count : count);
+                    char *names; Newxz(names, DO_SV_DUMP_BUFSIZE, char);
 		    while (hekp < endp) {
 			if (HEK_LEN(*hekp)) {
-             SV *tmp = newSVpvs_flags("", SVs_TEMP);
-			    Perl_sv_catpvf(aTHX_ names, ", \"%s\"",
+             char *tmp, *tmp2;
+             Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
+             Newx(tmp2, DO_SV_DUMP_BUFSIZE, char);
+                            my_snprintf(tmp2, DO_SV_DUMP_BUFSIZE, ", \"%s\"",
                               generic_pv_escape(tmp, HEK_KEY(*hekp), HEK_LEN(*hekp), HEK_UTF8(*hekp)));
+             _sv_catpv(names, tmp2);
+             Safefree(tmp);
+             Safefree(tmp2);
 			} else {
 			    /* This should never happen. */
-			    sv_catpvs(names, ", (null)");
+			    _sv_catpv(names, ", (null)");
 			}
 			++hekp;
 		    }
 		    Perl_dump_indent(aTHX_
-		     level, file, "  ENAME = %s\n", SvPV_nolen(names)+2
+		     level, file, "  ENAME = %s\n", names+2
 		    );
+                    Safefree(names);
 		}
 		else {
-                    SV * const tmp = newSVpvs_flags("", SVs_TEMP);
                     const char *const hvename = HvENAME_get(sv);
+                    char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 		    Perl_dump_indent(aTHX_
 		     level, file, "  ENAME = \"%s\"\n",
                      generic_pv_escape(tmp, hvename,
                                        HvENAMELEN_get(sv), HvENAMEUTF8(sv)));
+                    Safefree(tmp);
                 }
 	    }
 	    if (backrefs) {
@@ -1983,12 +2065,13 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 			   dumpops, pvlim);
 	    }
 	    if (meta) {
-		SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
+                char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 		Perl_dump_indent(aTHX_ level, file, "  MRO_WHICH = \"%s\" (0x%"UVxf")\n",
-				 generic_pv_escape( tmpsv, meta->mro_which->name,
+				 generic_pv_escape( tmp, meta->mro_which->name,
                                 meta->mro_which->length,
                                 (meta->mro_which->kflags & HVhek_UTF8)),
 				 PTR2UV(meta->mro_which));
+                Safefree(tmp);
 		Perl_dump_indent(aTHX_ level, file, "  CACHE_GEN = 0x%"UVxf"\n",
 				 (UV)meta->cache_gen);
 		Perl_dump_indent(aTHX_ level, file, "  PKG_GEN = 0x%"UVxf"\n",
@@ -2041,9 +2124,9 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 			keypv = SvPV_const(keysv, len);
 			elt = HeVAL(he);
 
-                        Perl_dump_indent(aTHX_ level+1, file, "Elt %s ", pv_display(d, keypv, len, 0, pvlim));
+                        Perl_dump_indent(aTHX_ level+1, file, "Elt %s ", _pv_display(aTHX_ d, keypv, len, 0, pvlim));
                         if (SvUTF8(keysv))
-                            PerlIO_printf(file, "[UTF8 \"%s\"] ", sv_uni_display(d, keysv, 6 * SvCUR(keysv), UNI_DISPLAY_QQ));
+                            PerlIO_printf(file, "[UTF8 \"%s\"] ", _sv_uni_display(aTHX_ d, keysv, 6 * SvCUR(keysv), UNI_DISPLAY_QQ));
 			if (HvEITER_get(hv) == he)
 			    PerlIO_printf(file, "[CURRENT] ");
                         PerlIO_printf(file, "HASH = 0x%"UVxf"\n", (UV) hash);
@@ -2058,18 +2141,20 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 
     case SVt_PVCV:
 	if (CvAUTOLOAD(sv)) {
-	    SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
        STRLEN len;
 	    const char *const name =  SvPV_const(sv, len);
+            char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 	    Perl_dump_indent(aTHX_ level, file, "  AUTOLOAD = \"%s\"\n",
-			     generic_pv_escape(tmpsv, name, len, SvUTF8(sv)));
+			     generic_pv_escape(tmp, name, len, SvUTF8(sv)));
+            Safefree(tmp);
 	}
 	if (SvPOK(sv)) {
-       SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
        const char *const proto = CvPROTO(sv);
+       char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 	    Perl_dump_indent(aTHX_ level, file, "  PROTOTYPE = \"%s\"\n",
-			     generic_pv_escape(tmpsv, proto, CvPROTOLEN(sv),
+			     generic_pv_escape(tmp, proto, CvPROTOLEN(sv),
                                 SvUTF8(sv)));
+       Safefree(tmp);
 	}
 	/* FALLTHROUGH */
     case SVt_PVFM:
@@ -2116,6 +2201,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	}
 	{
 	    const CV * const outside = CvOUTSIDE(sv);
+            char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
 	    Perl_dump_indent(aTHX_ level, file, "  OUTSIDE = 0x%"UVxf" (%s)\n",
 			PTR2UV(outside),
 			(!outside ? "null"
@@ -2124,11 +2210,12 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 			 : CvUNIQUE(outside) ? "UNIQUE"
 			 : CvGV(outside) ?
 			     generic_pv_escape(
-			         newSVpvs_flags("", SVs_TEMP),
+			         tmp,
 			         GvNAME(CvGV(outside)),
 			         GvNAMELEN(CvGV(outside)),
 			         GvNAMEUTF8(CvGV(outside)))
 			 : "UNDEFINED"));
+            Safefree(tmp);
 	}
 	if (nest < maxnest && (CvCLONE(sv) || CvCLONED(sv)))
 	    do_sv_dump(level+1, file, MUTABLE_SV(CvOUTSIDE(sv)), nest+1, maxnest, dumpops, pvlim);
@@ -2150,11 +2237,12 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	if (!isGV_with_GP(sv))
 	    break;
        {
-          SV* tmpsv = newSVpvs_flags("", SVs_TEMP);
+          char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
           Perl_dump_indent(aTHX_ level, file, "  NAME = \"%s\"\n",
-                    generic_pv_escape(tmpsv, GvNAME(sv),
+                    generic_pv_escape(tmp, GvNAME(sv),
                                       GvNAMELEN(sv),
                                       GvNAMEUTF8(sv)));
+          Safefree(tmp);
        }
 	Perl_dump_indent(aTHX_ level, file, "  NAMELEN = %"IVdf"\n", (IV)GvNAMELEN(sv));
 	do_hv_dump (level, file, "  GvSTASH", GvSTASH(sv));
@@ -2226,27 +2314,26 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	    struct regexp * const r = ReANY((REGEXP*)sv);
 
 #define SV_SET_STRINGIFY_REGEXP_FLAGS(d,flags,names) STMT_START { \
-            sv_setpv(d,"");                                 \
-            append_flags(d, flags, names);     \
-            if (SvCUR(d) > 0 && *(SvEND(d) - 1) == ',') {       \
-                SvCUR_set(d, SvCUR(d) - 1);                 \
-                SvPVX(d)[SvCUR(d)] = '\0';                  \
-            }                                               \
+            _sv_setpv(d,"");                                \
+            append_flags(d, flags, names);                  \
+            len = strlen(d);                                \
+            if (len > 0 && d[len - 1] == ',')               \
+                d[len - 1] = '\0';                          \
 } STMT_END
             SV_SET_STRINGIFY_REGEXP_FLAGS(d,r->compflags,regexp_extflags_names);
             Perl_dump_indent(aTHX_ level, file, "  COMPFLAGS = 0x%"UVxf" (%s)\n",
-                                (UV)(r->compflags), SvPVX_const(d));
+                                (UV)(r->compflags), d);
 
             SV_SET_STRINGIFY_REGEXP_FLAGS(d,r->extflags,regexp_extflags_names);
 	    Perl_dump_indent(aTHX_ level, file, "  EXTFLAGS = 0x%"UVxf" (%s)\n",
-                                (UV)(r->extflags), SvPVX_const(d));
+                                (UV)(r->extflags), d);
 
             Perl_dump_indent(aTHX_ level, file, "  ENGINE = 0x%"UVxf" (%s)\n",
                                 PTR2UV(r->engine), (r->engine == &PL_core_reg_engine) ? "STANDARD" : "PLUG-IN" );
             if (r->engine == &PL_core_reg_engine) {
                 SV_SET_STRINGIFY_REGEXP_FLAGS(d,r->intflags,regexp_core_intflags_names);
                 Perl_dump_indent(aTHX_ level, file, "  INTFLAGS = 0x%"UVxf" (%s)\n",
-                                (UV)(r->intflags), SvPVX_const(d));
+                                (UV)(r->intflags), d);
             } else {
                 Perl_dump_indent(aTHX_ level, file, "  INTFLAGS = 0x%"UVxf"\n",
 				(UV)(r->intflags));
@@ -2275,7 +2362,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	    if (r->subbeg)
 		Perl_dump_indent(aTHX_ level, file, "  SUBBEG = 0x%"UVxf" %s\n",
 			    PTR2UV(r->subbeg),
-			    pv_display(d, r->subbeg, r->sublen, 50, pvlim));
+			    _pv_display(aTHX_ d, r->subbeg, r->sublen, 50, pvlim));
 	    else
 		Perl_dump_indent(aTHX_ level, file, "  SUBBEG = 0x0\n");
 	    Perl_dump_indent(aTHX_ level, file, "  MOTHER_RE = 0x%"UVxf"\n",
@@ -2300,7 +2387,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	}
 	break;
     }
-    SvREFCNT_dec_NN(d);
+    Safefree(d);
 }
 
 /*
diff --git a/embed.fnc b/embed.fnc
index 90c56ed..8dd179e 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -1618,6 +1618,7 @@ Ap	|U8*	|uvuni_to_utf8	|NN U8 *d|UV uv
 Adm	|U8*	|uvchr_to_utf8_flags	|NN U8 *d|UV uv|UV flags
 Apd	|U8*	|uvoffuni_to_utf8_flags	|NN U8 *d|UV uv|UV flags
 Ap	|U8*	|uvuni_to_utf8_flags	|NN U8 *d|UV uv|UV flags
+Ap	|char*	|str_uni_display	|NN char *dest|STRLEN maxlen|NN const U8 *spv|STRLEN len|STRLEN pvlim|UV flags
 Apd	|char*	|pv_uni_display	|NN SV *dsv|NN const U8 *spv|STRLEN len|STRLEN pvlim|UV flags
 ApdR	|char*	|sv_uni_display	|NN SV *dsv|NN SV *ssv|STRLEN pvlim|UV flags
 : Used by Data::Alias
diff --git a/embed.h b/embed.h
index 7ca719d..9278180 100644
--- a/embed.h
+++ b/embed.h
@@ -557,6 +557,7 @@
 #define stack_grow(a,b,c)	Perl_stack_grow(aTHX_ a,b,c)
 #define start_subparse(a,b)	Perl_start_subparse(aTHX_ a,b)
 #define str_to_version(a)	Perl_str_to_version(aTHX_ a)
+#define str_uni_display(a,b,c,d,e,f)	Perl_str_uni_display(aTHX_ a,b,c,d,e,f)
 #define sv_2bool_flags(a,b)	Perl_sv_2bool_flags(aTHX_ a,b)
 #define sv_2cv(a,b,c,d)		Perl_sv_2cv(aTHX_ a,b,c,d)
 #define sv_2io(a)		Perl_sv_2io(aTHX_ a)
diff --git a/proto.h b/proto.h
index 6abd867..736fc06 100644
--- a/proto.h
+++ b/proto.h
@@ -3922,6 +3922,12 @@ PERL_CALLCONV NV	Perl_str_to_version(pTHX_ SV *sv)
 #define PERL_ARGS_ASSERT_STR_TO_VERSION	\
 	assert(sv)
 
+PERL_CALLCONV char*	Perl_str_uni_display(pTHX_ char *dest, STRLEN maxlen, const U8 *spv, STRLEN len, STRLEN pvlim, UV flags)
+			__attribute__nonnull__(pTHX_1)
+			__attribute__nonnull__(pTHX_3);
+#define PERL_ARGS_ASSERT_STR_UNI_DISPLAY	\
+	assert(dest); assert(spv)
+
 PERL_CALLCONV void	Perl_sub_crush_depth(pTHX_ CV* cv)
 			__attribute__nonnull__(pTHX_1);
 #define PERL_ARGS_ASSERT_SUB_CRUSH_DEPTH	\
diff --git a/utf8.c b/utf8.c
index bfde692..5c22320 100644
--- a/utf8.c
+++ b/utf8.c
@@ -3731,63 +3731,83 @@ The pointer to the PV of the C<dsv> is returned.
 
 =cut */
 char *
-Perl_pv_uni_display(pTHX_ SV *dsv, const U8 *spv, STRLEN len, STRLEN pvlim, UV flags)
+Perl_str_uni_display(pTHX_ char *dest, STRLEN maxlen, const U8 *spv, STRLEN len, STRLEN pvlim, UV flags)
 {
     int truncated = 0;
     const char *s, *e;
+    char buf[32];
 
-    PERL_ARGS_ASSERT_PV_UNI_DISPLAY;
+    PERL_ARGS_ASSERT_STR_UNI_DISPLAY;
 
-    sv_setpvs(dsv, "");
-    SvUTF8_off(dsv);
+    dest[0] = '\0';
     for (s = (const char *)spv, e = s + len; s < e; s += UTF8SKIP(s)) {
-	 UV u;
-	  /* This serves double duty as a flag and a character to print after
-	     a \ when flags & UNI_DISPLAY_BACKSLASH is true.
-	  */
-	 char ok = 0;
-
-	 if (pvlim && SvCUR(dsv) >= pvlim) {
-	      truncated++;
-	      break;
-	 }
-	 u = utf8_to_uvchr_buf((U8*)s, (U8*)e, 0);
-	 if (u < 256) {
-	     const unsigned char c = (unsigned char)u & 0xFF;
-	     if (flags & UNI_DISPLAY_BACKSLASH) {
-	         switch (c) {
-		 case '\n':
-		     ok = 'n'; break;
-		 case '\r':
-		     ok = 'r'; break;
-		 case '\t':
-		     ok = 't'; break;
-		 case '\f':
-		     ok = 'f'; break;
-		 case '\a':
-		     ok = 'a'; break;
-		 case '\\':
-		     ok = '\\'; break;
-		 default: break;
-		 }
-		 if (ok) {
-		     const char string = ok;
-		     sv_catpvs(dsv, "\\");
-		     sv_catpvn(dsv, &string, 1);
-		 }
-	     }
-	     /* isPRINT() is the locale-blind version. */
-	     if (!ok && (flags & UNI_DISPLAY_ISPRINT) && isPRINT(c)) {
-		 const char string = c;
-		 sv_catpvn(dsv, &string, 1);
-		 ok = 1;
-	     }
-	 }
-	 if (!ok)
-	     Perl_sv_catpvf(aTHX_ dsv, "\\x{%"UVxf"}", u);
+        UV u;
+        /* This serves double duty as a flag and a character to print after
+           a \ when flags & UNI_DISPLAY_BACKSLASH is true.
+           */
+        char ok = 0;
+
+        if (pvlim && strlen(dest) >= pvlim) {
+            truncated++;
+            break;
+        }
+        u = utf8_to_uvchr_buf((U8*)s, (U8*)e, 0);
+        if (u < 256) {
+            const unsigned char c = (unsigned char)u & 0xFF;
+            if (flags & UNI_DISPLAY_BACKSLASH) {
+                switch (c) {
+                    case '\n':
+                        ok = 'n'; break;
+                    case '\r':
+                        ok = 'r'; break;
+                    case '\t':
+                        ok = 't'; break;
+                    case '\f':
+                        ok = 'f'; break;
+                    case '\a':
+                        ok = 'a'; break;
+                    case '\\':
+                        ok = '\\'; break;
+                    default: break;
+                }
+                if (ok) {
+                    buf[0] = '\\';
+                    buf[1] = ok;
+                    buf[2] = '\0';
+                    my_strlcat(dest, buf, maxlen);
+                }
+            }
+            /* isPRINT() is the locale-blind version. */
+            if (!ok && (flags & UNI_DISPLAY_ISPRINT) && isPRINT(c)) {
+                buf[0] = c;
+                buf[1] = '\0';
+                my_strlcat(dest, buf, maxlen);
+                ok = 1;
+            }
+        }
+        if (!ok) {
+            my_snprintf(buf, sizeof(buf), "\\x{%"UVxf"}", u);
+            my_strlcat(dest, buf, maxlen);
+        }
     }
     if (truncated)
-	 sv_catpvs(dsv, "...");
+        my_strlcat(dest, "...", maxlen);
+
+    return dest;
+}
+
+char *
+Perl_pv_uni_display(pTHX_ SV *dsv, const U8 *spv, STRLEN len, STRLEN pvlim, UV flags)
+{
+    char *buf;
+    STRLEN maxlen = 6 * (len + 1);
+
+    PERL_ARGS_ASSERT_PV_UNI_DISPLAY;
+
+    Newxz(buf, maxlen, char);
+    sv_setpv(dsv, str_uni_display(buf, maxlen, spv, len, pvlim, flags));
+    SvUTF8_off(dsv);
+    Safefree(buf);
 
     return SvPVX(dsv);
 }
-- 
2.0.4

@p5pRT
Copy link
Author

p5pRT commented Aug 5, 2014

From creaktive@gmail.com

0002-Cleanup-whitespace-error-detected-by-git-am.patch
From 1fd5ca6aff63a7486d08d83f4254560f99b9aeba Mon Sep 17 00:00:00 2001
From: James E Keenan <jkeenan@cpan.org>
Date: Sat, 26 Jul 2014 10:49:40 -0400
Subject: [PATCH 2/3] Cleanup whitespace error detected by 'git am'.

---
 dump.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dump.c b/dump.c
index c368794..5f81704 100644
--- a/dump.c
+++ b/dump.c
@@ -1640,7 +1640,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
     }
     append_flags(d, flags, first_sv_flags_names);
     if (flags & SVf_ROK)  {	
-    				_sv_catpv(d, "ROK,");
+        _sv_catpv(d, "ROK,");
 	if (SvWEAKREF(sv))	_sv_catpv(d, "WEAKREF,");
     }
     append_flags(d, flags, second_sv_flags_names);
-- 
2.0.4

@p5pRT
Copy link
Author

p5pRT commented Aug 5, 2014

From creaktive@gmail.com

0003-Proper-naming-for-the-new-helper-functions-more-newS.patch
From 78197f452327b2e737a540ef64a7e3dd167c0e57 Mon Sep 17 00:00:00 2001
From: Stanislaw Pusep <creaktive@gmail.com>
Date: Mon, 28 Jul 2014 12:21:00 +0200
Subject: [PATCH 3/3] Proper naming for the new helper functions; more
 newSVpv() references removed.

Perl_sv_peek() now operates internally without allocating new SVs. But then,
a single SV is allocated for the result so we can return SvPV_nolen().
Does that configure a memory leak? Perl_sv_peek() already works that way.
---
 dump.c | 151 ++++++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 83 insertions(+), 68 deletions(-)

diff --git a/dump.c b/dump.c
index 5f81704..9b80afa 100644
--- a/dump.c
+++ b/dump.c
@@ -90,7 +90,7 @@ S_append_flags(char *s, U32 flags, const struct flag_to_name *start,
 #define append_flags(s, f, flags) \
     S_append_flags((s), (f), (flags), C_ARRAY_END(flags))
 
-#define generic_pv_escape(sv,s,len,utf8) _pv_escape( aTHX_ (sv), (s), (len), \
+#define generic_pv_escape(sv,s,len,utf8) S_pv_escape( aTHX_ (sv), (s), (len), \
                               (len) * (4+UTF8_MAXBYTES) + 1, NULL, \
                               PERL_PV_ESCAPE_NONASCII | PERL_PV_ESCAPE_DWIM \
                               | ((utf8) ? PERL_PV_ESCAPE_UNI : 0) )
@@ -137,8 +137,8 @@ Returns a pointer to the escaped text as held by dsv.
 */
 #define PV_ESCAPE_OCTBUFSIZE 32
 
-char *
-_pv_escape( pTHX_ char *dsv, char const * const str,
+static char *
+S_pv_escape( pTHX_ char *dsv, char const * const str,
             const STRLEN count, const STRLEN max,
             STRLEN * const escaped, const U32 flags )
 {
@@ -256,7 +256,7 @@ Perl_pv_escape( pTHX_ SV *dsv, char const * const str,
     }
 
     Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
-    sv_catpv(dsv, _pv_escape(aTHX_ buf, str, count, max, escaped, flags));
+    sv_catpv(dsv, S_pv_escape(aTHX_ buf, str, count, max, escaped, flags));
     Safefree(buf);
 
     return SvPVX(dsv);
@@ -286,8 +286,8 @@ Returns a pointer to the prettified text as held by dsv.
 =cut           
 */
 
-char *
-_pv_pretty( pTHX_ char *dsv, char const * const str, const STRLEN count,
+static char *
+S_pv_pretty( pTHX_ char *dsv, char const * const str, const STRLEN count,
             const STRLEN max, char const * const start_color, char const * const end_color,
             const U32 flags )
 {
@@ -302,7 +302,7 @@ _pv_pretty( pTHX_ char *dsv, char const * const str, const STRLEN count,
     if ( start_color != NULL )
         _sv_catpv(dsv, start_color);
 
-    _pv_escape( aTHX_ dsv, str, count, max, &escaped, flags );
+    S_pv_escape( aTHX_ dsv, str, count, max, &escaped, flags );
 
     if ( end_color != NULL )
         _sv_catpv(dsv, end_color);
@@ -332,7 +332,7 @@ Perl_pv_pretty( pTHX_ SV *dsv, char const * const str, const STRLEN count,
     }
 
     Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
-    sv_catpv(dsv, _pv_pretty(aTHX_ buf, str, count, max, start_color, end_color, flags));
+    sv_catpv(dsv, S_pv_pretty(aTHX_ buf, str, count, max, start_color, end_color, flags));
     Safefree(buf);
 
     return SvPVX(dsv);
@@ -352,11 +352,11 @@ Note that the final string may be up to 7 chars longer than pvlim.
 =cut
 */
 
-char *
-_pv_display( pTHX_ char *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim)
+static char *
+S_pv_display( pTHX_ char *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim)
 {
     _sv_setpv(dsv, "");
-    _pv_pretty( aTHX_ dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP);
+    S_pv_pretty( aTHX_ dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP);
     if (len > cur && pv[cur] == '\0')
         _sv_catpv( dsv, "\\0");
     return dsv;
@@ -369,14 +369,14 @@ Perl_pv_display(pTHX_ SV *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pv
     PERL_ARGS_ASSERT_PV_DISPLAY;
 
     Newxz(buf, DO_SV_DUMP_BUFSIZE, char);
-    sv_setpv(dsv, _pv_display(aTHX_ buf, pv, cur, len, pvlim));
+    sv_setpv(dsv, S_pv_display(aTHX_ buf, pv, cur, len, pvlim));
     Safefree(buf);
 
     return SvPVX(dsv);
 }
 
-char *
-_sv_uni_display( pTHX_ char *dest, SV *ssv, STRLEN pvlim, UV flags)
+static char *
+S_sv_uni_display( pTHX_ char *dest, SV *ssv, STRLEN pvlim, UV flags)
 {
     STRLEN len = SvCUR(ssv);
     U8 *spv = (U8 *)
@@ -389,31 +389,34 @@ char *
 Perl_sv_peek(pTHX_ SV *sv)
 {
     dVAR;
-    SV * const t = sv_newmortal();
+    SV * const out = sv_newmortal();
     int unref = 0;
     U32 type;
+    char *s, *t;
+    Newx(s, DO_SV_DUMP_BUFSIZE, char);
+    Newx(t, DO_SV_DUMP_BUFSIZE, char);
 
-    sv_setpvs(t, "");
+    _sv_setpv(t, "");
   retry:
     if (!sv) {
-	sv_catpv(t, "VOID");
+	_sv_catpv(t, "VOID");
 	goto finish;
     }
     else if (sv == (const SV *)0x55555555 || ((char)SvTYPE(sv)) == 'U') {
         /* detect data corruption under memory poisoning */
-	sv_catpv(t, "WILD");
+	_sv_catpv(t, "WILD");
 	goto finish;
     }
     else if (sv == &PL_sv_undef || sv == &PL_sv_no || sv == &PL_sv_yes || sv == &PL_sv_placeholder) {
 	if (sv == &PL_sv_undef) {
-	    sv_catpv(t, "SV_UNDEF");
+	    _sv_catpv(t, "SV_UNDEF");
 	    if (!(SvFLAGS(sv) & (SVf_OK|SVf_OOK|SVs_OBJECT|
 				 SVs_GMG|SVs_SMG|SVs_RMG)) &&
 		SvREADONLY(sv))
 		goto finish;
 	}
 	else if (sv == &PL_sv_no) {
-	    sv_catpv(t, "SV_NO");
+	    _sv_catpv(t, "SV_NO");
 	    if (!(SvFLAGS(sv) & (SVf_ROK|SVf_OOK|SVs_OBJECT|
 				 SVs_GMG|SVs_SMG|SVs_RMG)) &&
 		!(~SvFLAGS(sv) & (SVf_POK|SVf_NOK|SVf_READONLY|
@@ -423,7 +426,7 @@ Perl_sv_peek(pTHX_ SV *sv)
 		goto finish;
 	}
 	else if (sv == &PL_sv_yes) {
-	    sv_catpv(t, "SV_YES");
+	    _sv_catpv(t, "SV_YES");
 	    if (!(SvFLAGS(sv) & (SVf_ROK|SVf_OOK|SVs_OBJECT|
 				 SVs_GMG|SVs_SMG|SVs_RMG)) &&
 		!(~SvFLAGS(sv) & (SVf_POK|SVf_NOK|SVf_READONLY|
@@ -434,16 +437,16 @@ Perl_sv_peek(pTHX_ SV *sv)
 		goto finish;
 	}
 	else {
-	    sv_catpv(t, "SV_PLACEHOLDER");
+	    _sv_catpv(t, "SV_PLACEHOLDER");
 	    if (!(SvFLAGS(sv) & (SVf_OK|SVf_OOK|SVs_OBJECT|
 				 SVs_GMG|SVs_SMG|SVs_RMG)) &&
 		SvREADONLY(sv))
 		goto finish;
 	}
-	sv_catpv(t, ":");
+	_sv_catpv(t, ":");
     }
     else if (SvREFCNT(sv) == 0) {
-	sv_catpv(t, "(");
+	_sv_catpv(t, "(");
 	unref++;
     }
     else if (DEBUG_R_TEST_) {
@@ -456,19 +459,19 @@ Perl_sv_peek(pTHX_ SV *sv)
 		break;
 	    }
 	}
-	if (SvREFCNT(sv) > 1)
-	    Perl_sv_catpvf(aTHX_ t, "<%"UVuf"%s>", (UV)SvREFCNT(sv),
-		    is_tmp ? "T" : "");
-	else if (is_tmp)
-	    sv_catpv(t, "<T>");
+	if (SvREFCNT(sv) > 1) {
+            my_snprintf(s, DO_SV_DUMP_BUFSIZE, "<%"UVuf"%s>", (UV)SvREFCNT(sv),
+                is_tmp ? "T" : "");
+            _sv_catpv(t, s);
+        } else if (is_tmp)
+            _sv_catpv(t, "<T>");
     }
 
     if (SvROK(sv)) {
-	sv_catpv(t, "\\");
-	if (SvCUR(t) + unref > 10) {
-	    SvCUR_set(t, unref + 3);
-	    *SvEND(t) = '\0';
-	    sv_catpv(t, "...");
+	_sv_catpv(t, "\\");
+	if (strlen(t) + unref > 10) {
+            t[unref + 4] = '\0';
+	    _sv_catpv(t, "...");
 	    goto finish;
 	}
 	sv = SvRV(sv);
@@ -478,60 +481,71 @@ Perl_sv_peek(pTHX_ SV *sv)
     if (type == SVt_PVCV) {
         GV* gvcv = CvGV(sv);
         char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
-        Perl_sv_catpvf(aTHX_ t, "CV(%s)", gvcv
+        my_snprintf(s, DO_SV_DUMP_BUFSIZE, "CV(%s)", gvcv
                        ? generic_pv_escape( tmp, GvNAME(gvcv), GvNAMELEN(gvcv), GvNAMEUTF8(gvcv))
                        : "");
+        _sv_catpv(t, s);
         Safefree(tmp);
 	goto finish;
     } else if (type < SVt_LAST) {
-	sv_catpv(t, svshorttypenames[type]);
+	_sv_catpv(t, svshorttypenames[type]);
 
 	if (type == SVt_NULL)
 	    goto finish;
     } else {
-	sv_catpv(t, "FREED");
+	_sv_catpv(t, "FREED");
 	goto finish;
     }
 
     if (SvPOKp(sv)) {
 	if (!SvPVX_const(sv))
-	    sv_catpv(t, "(null)");
+	    _sv_catpv(t, "(null)");
 	else {
-	    SV * const tmp = newSVpvs("");
-	    sv_catpv(t, "(");
+            char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
+	    _sv_catpv(t, "(");
 	    if (SvOOK(sv)) {
 		STRLEN delta;
 		SvOOK_offset(sv, delta);
-		Perl_sv_catpvf(aTHX_ t, "[%s]", pv_display(tmp, SvPVX_const(sv)-delta, delta, 0, 127));
+                my_snprintf(s, DO_SV_DUMP_BUFSIZE, "[%s]", S_pv_display(tmp, SvPVX_const(sv)-delta, delta, 0, 127));
+                _sv_catpv(t, s);
 	    }
-	    Perl_sv_catpvf(aTHX_ t, "%s)", pv_display(tmp, SvPVX_const(sv), SvCUR(sv), SvLEN(sv), 127));
-	    if (SvUTF8(sv))
-		Perl_sv_catpvf(aTHX_ t, " [UTF8 \"%s\"]",
-			       sv_uni_display(tmp, sv, 6 * SvCUR(sv),
-					      UNI_DISPLAY_QQ));
-	    SvREFCNT_dec_NN(tmp);
+            my_snprintf(s, DO_SV_DUMP_BUFSIZE, "%s)", S_pv_display(tmp, SvPVX_const(sv), SvCUR(sv), SvLEN(sv), 127));
+            _sv_catpv(t, s);
+            if (SvUTF8(sv)) {
+                my_snprintf(s, DO_SV_DUMP_BUFSIZE, " [UTF8 \"%s\"]",
+                            S_sv_uni_display(tmp, sv, 6 * SvCUR(sv),
+                            UNI_DISPLAY_QQ));
+                _sv_catpv(t, s);
+            }
+            Safefree(tmp);
 	}
     }
     else if (SvNOKp(sv)) {
 	STORE_NUMERIC_LOCAL_SET_STANDARD();
-	Perl_sv_catpvf(aTHX_ t, "(%"NVgf")",SvNVX(sv));
+        my_snprintf(s, DO_SV_DUMP_BUFSIZE, "(%"NVgf")",SvNVX(sv));
+        _sv_catpv(t, s);
 	RESTORE_NUMERIC_LOCAL();
     }
     else if (SvIOKp(sv)) {
-	if (SvIsUV(sv))
-	    Perl_sv_catpvf(aTHX_ t, "(%"UVuf")", (UV)SvUVX(sv));
-	else
-            Perl_sv_catpvf(aTHX_ t, "(%"IVdf")", (IV)SvIVX(sv));
+        if (SvIsUV(sv))
+            my_snprintf(s, DO_SV_DUMP_BUFSIZE, "(%"UVuf")", (UV)SvUVX(sv));
+        else
+            my_snprintf(s, DO_SV_DUMP_BUFSIZE, "(%"IVdf")", (IV)SvIVX(sv));
+        _sv_catpv(t, s);
     }
     else
-	sv_catpv(t, "()");
+	_sv_catpv(t, "()");
 
   finish:
     while (unref--)
-	sv_catpv(t, ")");
+	_sv_catpv(t, ")");
     if (TAINTING_get && sv && SvTAINTED(sv))
-	sv_catpv(t, " [tainted]");
-    return SvPV_nolen(t);
+	_sv_catpv(t, " [tainted]");
+
+    sv_setpv(out, t);
+    Safefree(s);
+    Safefree(t);
+    return SvPV_nolen(out);
 }
 
 /*
@@ -1365,13 +1379,14 @@ Perl_do_magic_dump(pTHX_ I32 level, PerlIO *file, const MAGIC *mg, I32 nest, I32
 	        PTR2UV(mg->mg_obj));
             if (mg->mg_type == PERL_MAGIC_qr) {
 		REGEXP* const re = (REGEXP *)mg->mg_obj;
-		SV * const dsv = sv_newmortal();
-                const char * const s
-		    = pv_pretty(dsv, RX_WRAPPED(re), RX_WRAPLEN(re),
+                char *s;
+                char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
+                s = S_pv_pretty(tmp, RX_WRAPPED(re), RX_WRAPLEN(re),
                     60, NULL, NULL,
                     ( PERL_PV_PRETTY_QUOTE | PERL_PV_ESCAPE_RE | PERL_PV_PRETTY_ELLIPSES |
                     (RX_UTF8(re) ? PERL_PV_ESCAPE_UNI : 0))
                 );
+                Safefree(tmp);
 		Perl_dump_indent(aTHX_ level+1, file, "    PAT = %s\n", s);
 		Perl_dump_indent(aTHX_ level+1, file, "    REFCNT = %"IVdf"\n",
 			(IV)RX_REFCNT(re));
@@ -1385,9 +1400,9 @@ Perl_do_magic_dump(pTHX_ I32 level, PerlIO *file, const MAGIC *mg, I32 nest, I32
 	    Perl_dump_indent(aTHX_ level, file, "    MG_PTR = 0x%"UVxf, PTR2UV(mg->mg_ptr));
 	    if (mg->mg_len >= 0) {
 		if (mg->mg_type != PERL_MAGIC_utf8) {
-		    SV * const sv = newSVpvs("");
-		    PerlIO_printf(file, " %s", pv_display(sv, mg->mg_ptr, mg->mg_len, 0, pvlim));
-		    SvREFCNT_dec_NN(sv);
+                    char *tmp; Newxz(tmp, DO_SV_DUMP_BUFSIZE, char);
+                    PerlIO_printf(file, " %s", S_pv_display(tmp, mg->mg_ptr, mg->mg_len, 0, pvlim));
+                    Safefree(tmp);
 		}
             }
 	    else if (mg->mg_len == HEf_SVKEY) {
@@ -1806,7 +1821,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	    Perl_dump_indent(aTHX_ level, file,"  PV = 0x%"UVxf" ", PTR2UV(ptr));
 	    if (SvOOK(sv)) {
 		PerlIO_printf(file, "( %s . ) ",
-			      _pv_display(aTHX_ d, ptr - delta, delta, 0,
+			      S_pv_display(aTHX_ d, ptr - delta, delta, 0,
 					 pvlim));
 	    }
             if (type == SVt_INVLIST) {
@@ -1815,12 +1830,12 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
                 _invlist_dump(file, level, "    ", sv);
             }
             else {
-                PerlIO_printf(file, "%s", _pv_display(aTHX_ d, ptr, SvCUR(sv),
+                PerlIO_printf(file, "%s", S_pv_display(aTHX_ d, ptr, SvCUR(sv),
                                                      re ? 0 : SvLEN(sv),
                                                      pvlim));
                 if (SvUTF8(sv)) /* the 6?  \x{....} */
                     PerlIO_printf(file, " [UTF8 \"%s\"]",
-                                         _sv_uni_display(aTHX_ d, sv, 6 * SvCUR(sv),
+                                         S_sv_uni_display(aTHX_ d, sv, 6 * SvCUR(sv),
                                                         UNI_DISPLAY_QQ));
                 PerlIO_printf(file, "\n");
             }
@@ -2124,9 +2139,9 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 			keypv = SvPV_const(keysv, len);
 			elt = HeVAL(he);
 
-                        Perl_dump_indent(aTHX_ level+1, file, "Elt %s ", _pv_display(aTHX_ d, keypv, len, 0, pvlim));
+                        Perl_dump_indent(aTHX_ level+1, file, "Elt %s ", S_pv_display(aTHX_ d, keypv, len, 0, pvlim));
                         if (SvUTF8(keysv))
-                            PerlIO_printf(file, "[UTF8 \"%s\"] ", _sv_uni_display(aTHX_ d, keysv, 6 * SvCUR(keysv), UNI_DISPLAY_QQ));
+                            PerlIO_printf(file, "[UTF8 \"%s\"] ", S_sv_uni_display(aTHX_ d, keysv, 6 * SvCUR(keysv), UNI_DISPLAY_QQ));
 			if (HvEITER_get(hv) == he)
 			    PerlIO_printf(file, "[CURRENT] ");
                         PerlIO_printf(file, "HASH = 0x%"UVxf"\n", (UV) hash);
@@ -2362,7 +2377,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
 	    if (r->subbeg)
 		Perl_dump_indent(aTHX_ level, file, "  SUBBEG = 0x%"UVxf" %s\n",
 			    PTR2UV(r->subbeg),
-			    _pv_display(aTHX_ d, r->subbeg, r->sublen, 50, pvlim));
+			    S_pv_display(aTHX_ d, r->subbeg, r->sublen, 50, pvlim));
 	    else
 		Perl_dump_indent(aTHX_ level, file, "  SUBBEG = 0x0\n");
 	    Perl_dump_indent(aTHX_ level, file, "  MOTHER_RE = 0x%"UVxf"\n",
-- 
2.0.4

@p5pRT
Copy link
Author

p5pRT commented Aug 13, 2014

From creaktive@gmail.com

I have to admit I've made a hell of a mess within this ticket.
Should I squash my commits & apply for a new ticket to supersede this one?

@p5pRT
Copy link
Author

p5pRT commented Oct 8, 2014

From @tonycoz

On Wed Aug 13 01​:41​:56 2014, creaktive@​gmail.com wrote​:

I have to admit I've made a hell of a mess within this ticket.
Should I squash my commits & apply for a new ticket to supersede this one?

Could you supply a new squashed patch for this ticket?

Some of the issues I see so far​:

- many of the changes appear to be pure whitespace changes, which should be a separate patch

- your naming patch left _sv_catpv(), which still uses a leading _ and doesn't operate on SVs

At a higher level I'm a bit worried that you're going to run out of space displaying a complex SV.

From reading Nicholas' note in Porting/todo.pod it reads like he's expecting a more complex buffer implementation, eg​:

  struct bf {
  char *buf;
  size_t used;
  size_t alloced;
  };

with a small set of functions to allocate and update that - like a mini SV.

I'm not sure how well that would integrate into PerlIO though.

Tony

@p5pRT
Copy link
Author

p5pRT commented Oct 8, 2014

From @demerphq

On 8 October 2014 02​:40, Tony Cook via RT <perlbug-followup@​perl.org> wrote​:

On Wed Aug 13 01​:41​:56 2014, creaktive@​gmail.com wrote​:

I have to admit I've made a hell of a mess within this ticket.
Should I squash my commits & apply for a new ticket to supersede this
one?

Could you supply a new squashed patch for this ticket?

Some of the issues I see so far​:

- many of the changes appear to be pure whitespace changes, which should
be a separate patch

- your naming patch left _sv_catpv(), which still uses a leading _ and
doesn't operate on SVs

At a higher level I'm a bit worried that you're going to run out of space
displaying a complex SV.

From reading Nicholas' note in Porting/todo.pod it reads like he's
expecting a more complex buffer implementation, eg​:

struct bf {
char *buf;
size_t used;
size_t alloced;
};

with a small set of functions to allocate and update that - like a mini SV.

I'm not sure how well that would integrate into PerlIO though.

Why are we doing this? I see no point in inventing a "mini-sv" which will
essentially duplicate a real SV.

Yves

@p5pRT
Copy link
Author

p5pRT commented Oct 8, 2014

From perl5-porters@perl.org

Yves Orton asked​:

Why are we doing this? I see no point in inventing a "mini-sv" which will
essentially duplicate a real SV.

I don't remember the details, but I think it is to make debugging SV-
handling code easier.

@p5pRT
Copy link
Author

p5pRT commented Oct 8, 2014

From @jhi

Why are we doing this? I see no point in inventing a "mini-sv" which will
essentially duplicate a real SV.

I don't remember the details, but I think it is to make debugging SV-
handling code easier.

I never even knew the details (so can't have forgotten them), but at a
high-level
having some sort abstraction somewhere between a PV and and and a SvPV doesn't
sound too bad. The suggested tuple of {pointer, allocated, used} is
such basic (as in "important", not as in "trivial") building block for
... well, everything. Such basic management doesn't need to duplicate
a SV but instead form the ... ta-dah, basis.

The usual caveats apply​: you think I actually bothered to read the
discussion so far?

--
There is this special biologist word we use for 'stable'. It is
'dead'. -- Jack Cohen

@p5pRT
Copy link
Author

p5pRT commented Oct 9, 2014

From @tonycoz

On Wed, Oct 08, 2014 at 10​:37​:47AM +0200, demerphq wrote​:

On 8 October 2014 02​:40, Tony Cook via RT <perlbug-followup@​perl.org> wrote​:

From reading Nicholas' note in Porting/todo.pod it reads like he's
expecting a more complex buffer implementation, eg​:

struct bf {
char *buf;
size_t used;
size_t alloced;
};

with a small set of functions to allocate and update that - like a mini SV.

I'm not sure how well that would integrate into PerlIO though.

Why are we doing this? I see no point in inventing a "mini-sv" which will
essentially duplicate a real SV.

Well, my example would be much simpler than an SV - the basics needed
to manage a buffer. Allocation, append, destruction, maybe an append
formatted to make it more useful for dump.c (through sn?printf(), not
Perl_form()/sv_catpvf()).

If you haven't, you might want to read "Remove the use of SVs as
temporaries in dump.c" in Porting/todo.pod to see where this came
from.

I don't know that this removal is necessary, but I think that doing is
with a fixed size buffer as in the supplied patch isn't correct. I
think using a slightly more complex structure matches Nicholas's
intent more closely.

Tony

@p5pRT
Copy link
Author

p5pRT commented Oct 10, 2014

From @demerphq

On 10 October 2014 01​:20, Tony Cook <tony@​develop-help.com> wrote​:

On Wed, Oct 08, 2014 at 10​:37​:47AM +0200, demerphq wrote​:

On 8 October 2014 02​:40, Tony Cook via RT <perlbug-followup@​perl.org>
wrote​:

From reading Nicholas' note in Porting/todo.pod it reads like he's
expecting a more complex buffer implementation, eg​:

struct bf {
char *buf;
size_t used;
size_t alloced;
};

with a small set of functions to allocate and update that - like a
mini SV.

I'm not sure how well that would integrate into PerlIO though.

Why are we doing this? I see no point in inventing a "mini-sv" which will
essentially duplicate a real SV.

Well, my example would be much simpler than an SV - the basics needed
to manage a buffer. Allocation, append, destruction, maybe an append
formatted to make it more useful for dump.c (through sn?printf(), not
Perl_form()/sv_catpvf()).

If you haven't, you might want to read "Remove the use of SVs as
temporaries in dump.c" in Porting/todo.pod to see where this came
from.

Ok thanks that explains everything.

I don't know that this removal is necessary, but I think that doing is
with a fixed size buffer as in the supplied patch isn't correct. I
think using a slightly more complex structure matches Nicholas's
intent more closely.

Yep. I agree. FWIW, Sereal uses a similar technique, creating and managing
a buffer just like this.

I doubt our code is worth stealing tho, better to roll a new implementation.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 11, 2015

From @tonycoz

On Tue Oct 07 17​:40​:08 2014, tonyc wrote​:

At a higher level I'm a bit worried that you're going to run out of
space displaying a complex SV.

From reading Nicholas' note in Porting/todo.pod it reads like he's
expecting a more complex buffer implementation, eg​:

struct bf {
char *buf;
size_t used;
size_t alloced;
};

with a small set of functions to allocate and update that - like a
mini SV.

I'm not sure how well that would integrate into PerlIO though.

There have been no updates to this ticket since October, and I don't think
the patch as-is is suitable for blead.

I'll close this ticket in a few days if there's no activity.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jul 8, 2015

From @tonycoz

On Wed Jun 10 22​:40​:52 2015, tonyc wrote​:

On Tue Oct 07 17​:40​:08 2014, tonyc wrote​:

At a higher level I'm a bit worried that you're going to run out of
space displaying a complex SV.

From reading Nicholas' note in Porting/todo.pod it reads like he's
expecting a more complex buffer implementation, eg​:

struct bf {
char *buf;
size_t used;
size_t alloced;
};

with a small set of functions to allocate and update that - like a
mini SV.

I'm not sure how well that would integrate into PerlIO though.

There have been no updates to this ticket since October, and I don't think
the patch as-is is suitable for blead.

I'll close this ticket in a few days if there's no activity.

Closed.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jul 8, 2015

@tonycoz - Status changed from 'open' to 'rejected'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant