pp_print didn't extend the stack before pushing its return value
[p5sagit/p5-mst-13.2.git] / util.c
diff --git a/util.c b/util.c
index 2f5e2c3..fad5520 100644 (file)
--- a/util.c
+++ b/util.c
@@ -365,7 +365,7 @@ Analyses the string in order to make fast searches on it using fbm_instr()
 void
 Perl_fbm_compile(pTHX_ SV *sv, U32 flags)
 {
-    const register U8 *s;
+    register const U8 *s;
     register U32 i;
     STRLEN len;
     I32 rarest = 0;
@@ -552,7 +552,7 @@ Perl_fbm_instr(pTHX_ unsigned char *big, register unsigned char *bigend, SV *lit
        return Nullch;
     }
     if (SvTYPE(littlestr) != SVt_PVBM || !SvVALID(littlestr)) {
-       char *b = ninstr((char*)big,(char*)bigend,
+       char * const b = ninstr((char*)big,(char*)bigend,
                         (char*)little, (char*)little + littlelen);
 
        if (!b && SvTAIL(littlestr)) {  /* Automatically multiline!  */
@@ -569,8 +569,8 @@ Perl_fbm_instr(pTHX_ unsigned char *big, register unsigned char *bigend, SV *lit
     }
 
     {  /* Do actual FBM.  */
-       register const unsigned char *table = little + littlelen + FBM_TABLE_OFFSET;
-       const register unsigned char *oldlittle;
+       register const unsigned char * const table = little + littlelen + FBM_TABLE_OFFSET;
+       register const unsigned char *oldlittle;
 
        if (littlelen > (STRLEN)(bigend - big))
            return Nullch;
@@ -632,13 +632,13 @@ Perl_fbm_instr(pTHX_ unsigned char *big, register unsigned char *bigend, SV *lit
 char *
 Perl_screaminstr(pTHX_ SV *bigstr, SV *littlestr, I32 start_shift, I32 end_shift, I32 *old_posp, I32 last)
 {
-    const register unsigned char *big;
+    register const unsigned char *big;
     register I32 pos;
     register I32 previous;
     register I32 first;
-    const register unsigned char *little;
+    register const unsigned char *little;
     register I32 stop_pos;
-    const register unsigned char *littleend;
+    register const unsigned char *littleend;
     I32 found = 0;
 
     if (*old_posp == -1
@@ -680,7 +680,7 @@ Perl_screaminstr(pTHX_ SV *bigstr, SV *littlestr, I32 start_shift, I32 end_shift
     }
     big -= previous;
     do {
-       const register unsigned char *s, *x;
+       register const unsigned char *s, *x;
        if (pos >= stop_pos) break;
        if (big[pos] != first)
            continue;
@@ -985,7 +985,7 @@ S_closest_cop(pTHX_ COP *cop, const OP *o)
 SV *
 Perl_vmess(pTHX_ const char *pat, va_list *args)
 {
-    SV *sv = mess_alloc();
+    SV * const sv = mess_alloc();
     static const char dgd[] = " during global destruction.\n";
 
     sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
@@ -1495,20 +1495,41 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
     my_setenv_format(environ[i], nam, nlen, val, vlen);
     } else {
 # endif
-#   if defined(__CYGWIN__) || defined(EPOC) || defined(SYMBIAN) 
-    setenv(nam, val, 1);
+#   if defined(__CYGWIN__) || defined(EPOC) || defined(__SYMBIAN32__)
+#       if defined(HAS_UNSETENV)
+        if (val == NULL) {
+            (void)unsetenv(nam);
+        } else {
+            (void)setenv(nam, val, 1);
+        }
+#       else /* ! HAS_UNSETENV */
+        (void)setenv(nam, val, 1);
+#       endif /* HAS_UNSETENV */
 #   else
-    char *new_env;
-    const int nlen = strlen(nam);
-    int vlen;
-    if (!val) {
-       val = "";
-    }
-    vlen = strlen(val);
-    new_env = (char*)safesysmalloc((nlen + vlen + 2) * sizeof(char));
-    /* all that work just for this */
-    my_setenv_format(new_env, nam, nlen, val, vlen);
-    (void)putenv(new_env);
+#       if defined(HAS_UNSETENV)
+        if (val == NULL) {
+            (void)unsetenv(nam);
+        } else {
+           const int nlen = strlen(nam);
+           const int vlen = strlen(val);
+           char * const new_env =
+                (char*)safesysmalloc((nlen + vlen + 2) * sizeof(char));
+            my_setenv_format(new_env, nam, nlen, val, vlen);
+            (void)putenv(new_env);
+        }
+#       else /* ! HAS_UNSETENV */
+        char *new_env;
+       const int nlen = strlen(nam);
+       int vlen;
+        if (!val) {
+          val = "";
+        }
+        vlen = strlen(val);
+        new_env = (char*)safesysmalloc((nlen + vlen + 2) * sizeof(char));
+        /* all that work just for this */
+        my_setenv_format(new_env, nam, nlen, val, vlen);
+        (void)putenv(new_env);
+#       endif /* HAS_UNSETENV */
 #   endif /* __CYGWIN__ */
 #ifndef PERL_USE_SAFE_PUTENV
     }
@@ -1543,7 +1564,7 @@ I32
 Perl_setenv_getix(pTHX_ const char *nam)
 {
     register I32 i;
-    const register I32 len = strlen(nam);
+    register const I32 len = strlen(nam);
 
     for (i = 0; environ[i]; i++) {
        if (
@@ -2212,7 +2233,9 @@ Perl_my_popen(pTHX_ const char *cmd, const char *mode)
        PL_ppid = (IV)getppid();
 #endif
        PL_forkprocess = 0;
+#ifdef PERL_USES_PL_PIDSTATUS
        hv_clear(PL_pidstatus); /* we have no children */
+#endif
        return Nullfp;
 #undef THIS
 #undef THAT
@@ -2615,17 +2638,16 @@ Perl_wait4pid(pTHX_ Pid_t pid, int *statusp, int flags)
     I32 result = 0;
     if (!pid)
        return -1;
-#if !defined(HAS_WAITPID) && !defined(HAS_WAIT4) || defined(HAS_WAITPID_RUNTIME)
+#ifdef PERL_USES_PL_PIDSTATUS
     {
-       char spid[TYPE_CHARS(IV)];
-
        if (pid > 0) {
-           SV** svp;
-           sprintf(spid, "%"IVdf, (IV)pid);
-           svp = hv_fetch(PL_pidstatus,spid,strlen(spid),FALSE);
+           /* The keys in PL_pidstatus are now the raw 4 (or 8) bytes of the
+              pid, rather than a string form.  */
+           SV * const * const svp = hv_fetch(PL_pidstatus,(const char*) &pid,sizeof(Pid_t),FALSE);
            if (svp && *svp != &PL_sv_undef) {
                *statusp = SvIVX(*svp);
-               (void)hv_delete(PL_pidstatus,spid,strlen(spid),G_DISCARD);
+               (void)hv_delete(PL_pidstatus,(const char*) &pid,sizeof(Pid_t),
+                               G_DISCARD);
                return pid;
            }
        }
@@ -2634,12 +2656,21 @@ Perl_wait4pid(pTHX_ Pid_t pid, int *statusp, int flags)
 
            hv_iterinit(PL_pidstatus);
            if ((entry = hv_iternext(PL_pidstatus))) {
-               SV *sv = hv_iterval(PL_pidstatus,entry);
+               SV * const sv = hv_iterval(PL_pidstatus,entry);
+               I32 len;
+               const char *spid = hv_iterkey(entry,&len);
 
-               pid = atoi(hv_iterkey(entry,(I32*)statusp));
+               assert (len == sizeof(Pid_t));
+               memcpy((char *)&pid, spid, len);
                *statusp = SvIVX(sv);
-               sprintf(spid, "%"IVdf, (IV)pid);
-               (void)hv_delete(PL_pidstatus,spid,strlen(spid),G_DISCARD);
+               /* The hash iterator is currently on this entry, so simply
+                  calling hv_delete would trigger the lazy delete, which on
+                  aggregate does more work, beacuse next call to hv_iterinit()
+                  would spot the flag, and have to call the delete routine,
+                  while in the meantime any new entries can't re-use that
+                  memory.  */
+               hv_iterinit(PL_pidstatus);
+               (void)hv_delete(PL_pidstatus,spid,len,G_DISCARD);
                return pid;
            }
        }
@@ -2657,7 +2688,7 @@ Perl_wait4pid(pTHX_ Pid_t pid, int *statusp, int flags)
     result = wait4((pid==-1)?0:pid,statusp,flags,Null(struct rusage *));
     goto finish;
 #endif
-#if !defined(HAS_WAITPID) && !defined(HAS_WAIT4) || defined(HAS_WAITPID_RUNTIME)
+#ifdef PERL_USES_PL_PIDSTATUS
 #if defined(HAS_WAITPID) && defined(HAS_WAITPID_RUNTIME)
   hard_way:
 #endif
@@ -2682,18 +2713,18 @@ Perl_wait4pid(pTHX_ Pid_t pid, int *statusp, int flags)
 }
 #endif /* !DOSISH || OS2 || WIN32 || NETWARE */
 
+#ifdef PERL_USES_PL_PIDSTATUS
 void
 Perl_pidgone(pTHX_ Pid_t pid, int status)
 {
     register SV *sv;
-    char spid[TYPE_CHARS(IV)];
 
-    sprintf(spid, "%"IVdf, (IV)pid);
-    sv = *hv_fetch(PL_pidstatus,spid,strlen(spid),TRUE);
+    sv = *hv_fetch(PL_pidstatus,(const char*)&pid,sizeof(Pid_t),TRUE);
     SvUPGRADE(sv,SVt_IV);
     SvIV_set(sv, status);
     return;
 }
+#endif
 
 #if defined(atarist) || defined(OS2) || defined(EPOC)
 int pclose();
@@ -2707,7 +2738,7 @@ Perl_my_pclose(pTHX_ PerlIO *ptr)
 #endif
 {
     /* Needs work for PerlIO ! */
-    FILE *f = PerlIO_findFILE(ptr);
+    FILE * const f = PerlIO_findFILE(ptr);
     I32 result = pclose(f);
     PerlIO_releaseFILE(ptr,f);
     return result;
@@ -2720,7 +2751,7 @@ I32
 Perl_my_pclose(pTHX_ PerlIO *ptr)
 {
     /* Needs work for PerlIO ! */
-    FILE *f = PerlIO_findFILE(ptr);
+    FILE * const f = PerlIO_findFILE(ptr);
     I32 result = djgpp_pclose(f);
     result = (result << 8) & 0xff00;
     PerlIO_releaseFILE(ptr,f);
@@ -2732,7 +2763,7 @@ void
 Perl_repeatcpy(pTHX_ register char *to, register const char *from, I32 len, register I32 count)
 {
     register I32 todo;
-    register const char *frombase = from;
+    register const char * const frombase = from;
 
     if (len == 1) {
        register const char c = *from;
@@ -2756,7 +2787,7 @@ Perl_same_dirent(pTHX_ const char *a, const char *b)
     char *fb = strrchr(b,'/');
     Stat_t tmpstatbuf1;
     Stat_t tmpstatbuf2;
-    SV *tmpsv = sv_newmortal();
+    SV * const tmpsv = sv_newmortal();
 
     if (fa)
        fa++;
@@ -2786,7 +2817,8 @@ Perl_same_dirent(pTHX_ const char *a, const char *b)
 #endif /* !HAS_RENAME */
 
 char*
-Perl_find_script(pTHX_ const char *scriptname, bool dosearch, const char **search_ext, I32 flags)
+Perl_find_script(pTHX_ const char *scriptname, bool dosearch,
+                const char *const *const search_ext, I32 flags)
 {
     const char *xfound = Nullch;
     char *xfailed = Nullch;
@@ -2808,8 +2840,8 @@ Perl_find_script(pTHX_ const char *scriptname, bool dosearch, const char **searc
 #endif
     /* additional extensions to try in each dir if scriptname not found */
 #ifdef SEARCH_EXTS
-    const char *exts[] = { SEARCH_EXTS };
-    const char **ext = search_ext ? search_ext : exts;
+    const char *const exts[] = { SEARCH_EXTS };
+    const char *const *const ext = search_ext ? search_ext : exts;
     int extidx = 0, i = 0;
     const char *curext = Nullch;
 #else
@@ -2841,16 +2873,16 @@ Perl_find_script(pTHX_ const char *scriptname, bool dosearch, const char **searc
 #  ifdef ALWAYS_DEFTYPES
     len = strlen(scriptname);
     if (!(len == 1 && *scriptname == '-') && scriptname[len-1] != ':') {
-       int hasdir, idx = 0, deftypes = 1;
+       int idx = 0, deftypes = 1;
        bool seen_dot = 1;
 
-       hasdir = !dosearch || (strpbrk(scriptname,":[</") != Nullch) ;
+       const int hasdir = !dosearch || (strpbrk(scriptname,":[</") != Nullch);
 #  else
     if (dosearch) {
-       int hasdir, idx = 0, deftypes = 1;
+       int idx = 0, deftypes = 1;
        bool seen_dot = 1;
 
-       hasdir = (strpbrk(scriptname,":[</") != Nullch) ;
+       const int hasdir = (strpbrk(scriptname,":[</") != Nullch);
 #  endif
        /* The first time through, just add SEARCH_EXTS to whatever we
         * already have, so we can check for default file types. */
@@ -3882,11 +3914,12 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv)
     const char *pos;
     const char *last;
     int saw_period = 0;
-    int saw_under = 0;
+    int alpha = 0;
     int width = 3;
     AV *av = newAV();
-    SV* hv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */
+    SV *hv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */
     (void)sv_upgrade(hv, SVt_PVHV); /* needs to be an HV type */
+
 #ifndef NODEFAULT_SHAREKEYS
     HvSHAREKEYS_on(hv);         /* key-sharing on by default */
 #endif
@@ -3906,16 +3939,16 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv)
     {
        if ( *pos == '.' )
        {
-           if ( saw_under )
+           if ( alpha )
                Perl_croak(aTHX_ "Invalid version format (underscores before decimal)");
            saw_period++ ;
            last = pos;
        }
        else if ( *pos == '_' )
        {
-           if ( saw_under )
+           if ( alpha )
                Perl_croak(aTHX_ "Invalid version format (multiple underscores)");
-           saw_under = 1;
+           alpha = 1;
            width = pos - last - 1; /* natural width of sub-version */
        }
        pos++;
@@ -3927,9 +3960,9 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv)
     pos = s;
 
     if ( qv )
-       hv_store((HV *)hv, "qv", 2, &PL_sv_yes, 0);
-    if ( saw_under )
-       hv_store((HV *)hv, "alpha", 5, &PL_sv_yes, 0);
+       hv_store((HV *)hv, "qv", 2, newSViv(qv), 0);
+    if ( alpha )
+       hv_store((HV *)hv, "alpha", 5, newSViv(alpha), 0);
     if ( !qv && width < 3 )
        hv_store((HV *)hv, "width", 5, newSViv(width), 0);
     
@@ -4018,7 +4051,7 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv)
        av_push(av, newSViv(0));
 
     /* And finally, store the AV in the hash */
-    hv_store((HV *)hv, "version", 7, (SV *)av, 0);
+    hv_store((HV *)hv, "version", 7, newRV_noinc((SV *)av), 0);
     return s;
 }
 
@@ -4067,7 +4100,7 @@ Perl_new_version(pTHX_ SV *ver)
            hv_store((HV *)hv, "width", 5, newSViv(width), 0);
        }
 
-       sav = (AV *)*hv_fetch((HV*)ver, "version", 7, FALSE);
+       sav = (AV *)SvRV(*hv_fetch((HV*)ver, "version", 7, FALSE));
        /* This will get reblessed later if a derived class*/
        for ( key = 0; key <= av_len(sav); key++ )
        {
@@ -4075,7 +4108,7 @@ Perl_new_version(pTHX_ SV *ver)
            av_push(av, newSViv(rev));
        }
 
-       hv_store((HV *)hv, "version", 7, (SV *)av, 0);
+       hv_store((HV *)hv, "version", 7, newRV_noinc((SV *)av), 0);
        return rv;
     }
 #ifdef SvVOK
@@ -4117,8 +4150,8 @@ Perl_upg_version(pTHX_ SV *ver)
     if ( SvNOK(ver) ) /* may get too much accuracy */ 
     {
        char tbuf[64];
-       sprintf(tbuf,"%.9"NVgf, SvNVX(ver));
-       version = savepv(tbuf);
+       const STRLEN len = my_sprintf(tbuf,"%.9"NVgf, SvNVX(ver));
+       version = savepvn(tbuf, len);
     }
 #ifdef SvVOK
     else if ( SvVOK(ver) ) { /* already a v-string */
@@ -4148,11 +4181,11 @@ confused by derived classes which may contain additional hash entries):
 
 =over 4
 
-=item * The SV contains a hash (or a reference to one)
+=item * The SV contains a [reference to a] hash
 
 =item * The hash contains a "version" key
 
-=item * The "version" key has an AV as its value
+=item * The "version" key has [a reference to] an AV as its value
 
 =back
 
@@ -4169,7 +4202,7 @@ Perl_vverify(pTHX_ SV *vs)
     /* see if the appropriate elements exist */
     if ( SvTYPE(vs) == SVt_PVHV
         && hv_exists((HV*)vs, "version", 7)
-        && (sv = *hv_fetch((HV*)vs, "version", 7, FALSE))
+        && (sv = SvRV(*hv_fetch((HV*)vs, "version", 7, FALSE)))
         && SvTYPE(sv) == SVt_PVAV )
        return TRUE;
     else
@@ -4214,7 +4247,7 @@ Perl_vnumify(pTHX_ SV *vs)
 
 
     /* attempt to retrieve the version array */
-    if ( !(av = (AV *)*hv_fetch((HV*)vs, "version", 7, FALSE) ) ) {
+    if ( !(av = (AV *)SvRV(*hv_fetch((HV*)vs, "version", 7, FALSE)) ) ) {
        sv_catpvn(sv,"0",1);
        return sv;
     }
@@ -4284,7 +4317,7 @@ Perl_vnormal(pTHX_ SV *vs)
 
     if ( hv_exists((HV*)vs, "alpha", 5 ) )
        alpha = TRUE;
-    av = (AV *)*hv_fetch((HV*)vs, "version", 7, FALSE);
+    av = (AV *)SvRV(*hv_fetch((HV*)vs, "version", 7, FALSE));
 
     len = av_len(av);
     if ( len == -1 )
@@ -4294,7 +4327,7 @@ Perl_vnormal(pTHX_ SV *vs)
     }
     digit = SvIV(*av_fetch(av, 0, 0));
     Perl_sv_setpvf(aTHX_ sv, "v%"IVdf, (IV)digit);
-    for ( i = 1 ; i <= len-1 ; i++ ) {
+    for ( i = 1 ; i < len ; i++ ) {
        digit = SvIV(*av_fetch(av, i, 0));
        Perl_sv_catpvf(aTHX_ sv, ".%"IVdf, (IV)digit);
     }
@@ -4330,7 +4363,6 @@ the original version contained 1 or more dots, respectively
 SV *
 Perl_vstringify(pTHX_ SV *vs)
 {
-    I32 qv = 0;
     if ( SvROK(vs) )
        vs = SvRV(vs);
     
@@ -4338,12 +4370,9 @@ Perl_vstringify(pTHX_ SV *vs)
        Perl_croak(aTHX_ "Invalid version object");
 
     if ( hv_exists((HV *)vs, "qv", 2) )
-       qv = 1;
-    
-    if ( qv )
-       return Perl_vnormal(aTHX_ vs);
+       return vnormal(vs);
     else
-       return Perl_vnumify(aTHX_ vs);
+       return vnumify(vs);
 }
 
 /*
@@ -4376,12 +4405,12 @@ Perl_vcmp(pTHX_ SV *lhv, SV *rhv)
        Perl_croak(aTHX_ "Invalid version object");
 
     /* get the left hand term */
-    lav = (AV *)*hv_fetch((HV*)lhv, "version", 7, FALSE);
+    lav = (AV *)SvRV(*hv_fetch((HV*)lhv, "version", 7, FALSE));
     if ( hv_exists((HV*)lhv, "alpha", 5 ) )
        lalpha = TRUE;
 
     /* and the right hand term */
-    rav = (AV *)*hv_fetch((HV*)rhv, "version", 7, FALSE);
+    rav = (AV *)SvRV(*hv_fetch((HV*)rhv, "version", 7, FALSE));
     if ( hv_exists((HV*)rhv, "alpha", 5 ) )
        ralpha = TRUE;
 
@@ -4705,8 +4734,9 @@ Perl_my_socketpair (int family, int type, int protocol, int fd[2]) {
 =for apidoc sv_nosharing
 
 Dummy routine which "shares" an SV when there is no sharing module present.
-Exists to avoid test for a NULL function pointer and because it could potentially warn under
-some level of strict-ness.
+Or "locks" it. Or "unlocks" it. In other words, ignores its single SV argument.
+Exists to avoid test for a NULL function pointer and because it could
+potentially warn under some level of strict-ness.
 
 =cut
 */
@@ -4717,39 +4747,6 @@ Perl_sv_nosharing(pTHX_ SV *sv)
     PERL_UNUSED_ARG(sv);
 }
 
-/*
-=for apidoc sv_nolocking
-
-Dummy routine which "locks" an SV when there is no locking module present.
-Exists to avoid test for a NULL function pointer and because it could potentially warn under
-some level of strict-ness.
-
-=cut
-*/
-
-void
-Perl_sv_nolocking(pTHX_ SV *sv)
-{
-    PERL_UNUSED_ARG(sv);
-}
-
-
-/*
-=for apidoc sv_nounlocking
-
-Dummy routine which "unlocks" an SV when there is no locking module present.
-Exists to avoid test for a NULL function pointer and because it could potentially warn under
-some level of strict-ness.
-
-=cut
-*/
-
-void
-Perl_sv_nounlocking(pTHX_ SV *sv)
-{
-    PERL_UNUSED_ARG(sv);
-}
-
 U32
 Perl_parse_unicode_opts(pTHX_ const char **popt)
 {
@@ -5023,11 +5020,12 @@ Perl_mem_log_alloc(const UV n, const UV typesize, const char *typename, Malloc_t
 #ifdef PERL_MEM_LOG_STDERR
     /* We can't use PerlIO for obvious reasons. */
     char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE];
-    sprintf(buf,
-           "alloc: %s:%d:%s: %"IVdf" %"UVuf" %s = %"IVdf": %"UVxf"\n",
-           filename, linenumber, funcname,
-           n, typesize, typename, n * typesize, PTR2UV(newalloc));
-    PerlLIO_write(2,  buf, strlen(buf));
+    const STRLEN len = my_sprintf(buf,
+                                 "alloc: %s:%d:%s: %"IVdf" %"UVuf
+                                 " %s = %"IVdf": %"UVxf"\n",
+                                 filename, linenumber, funcname, n, typesize,
+                                 typename, n * typesize, PTR2UV(newalloc));
+    PerlLIO_write(2,  buf, len));
 #endif
     return newalloc;
 }
@@ -5038,11 +5036,12 @@ Perl_mem_log_realloc(const UV n, const UV typesize, const char *typename, Malloc
 #ifdef PERL_MEM_LOG_STDERR
     /* We can't use PerlIO for obvious reasons. */
     char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE];
-    sprintf(buf,
-           "realloc: %s:%d:%s: %"IVdf" %"UVuf" %s = %"IVdf": %"UVxf" -> %"UVxf"\n",
-           filename, linenumber, funcname,
-           n, typesize, typename, n * typesize, PTR2UV(oldalloc), PTR2UV(newalloc));
-    PerlLIO_write(2,  buf, strlen(buf));
+    const STRLEN len = my_sprintf(buf, "realloc: %s:%d:%s: %"IVdf" %"UVuf
+                                 " %s = %"IVdf": %"UVxf" -> %"UVxf"\n",
+                                 filename, linenumber, funcname, n, typesize,
+                                 typename, n * typesize, PTR2UV(oldalloc),
+                                 PTR2UV(newalloc));
+    PerlLIO_write(2,  buf, len);
 #endif
     return newalloc;
 }
@@ -5053,9 +5052,10 @@ Perl_mem_log_free(Malloc_t oldalloc, const char *filename, const int linenumber,
 #ifdef PERL_MEM_LOG_STDERR
     /* We can't use PerlIO for obvious reasons. */
     char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE];
-    sprintf(buf, "free: %s:%d:%s: %"UVxf"\n",
-           filename, linenumber, funcname, PTR2UV(oldalloc));
-    PerlLIO_write(2,  buf, strlen(buf));
+    const STRLEN len = my_sprintf(buf, "free: %s:%d:%s: %"UVxf"\n",
+                                 filename, linenumber, funcname,
+                                 PTR2UV(oldalloc));
+    PerlLIO_write(2,  buf, len);
 #endif
     return oldalloc;
 }
@@ -5063,6 +5063,81 @@ Perl_mem_log_free(Malloc_t oldalloc, const char *filename, const int linenumber,
 #endif /* PERL_MEM_LOG */
 
 /*
+=for apidoc my_sprintf
+
+The C library C<sprintf>, wrapped if necessary, to ensure that it will return
+the length of the string written to the buffer. Only rare pre-ANSI systems
+need the wrapper function - usually this is a direct call to C<sprintf>.
+
+=cut
+*/
+#ifndef SPRINTF_RETURNS_STRLEN
+int
+Perl_my_sprintf(char *buffer, const char* pat, ...)
+{
+    va_list args;
+    va_start(args, pat);
+    vsprintf(buffer, pat, args);
+    va_end(args);
+    return strlen(buffer);
+}
+#endif
+
+void
+Perl_my_clearenv(pTHX)
+{
+    dVAR;
+#if ! defined(PERL_MICRO)
+#  if defined(PERL_IMPLICIT_SYS) || defined(WIN32)
+    PerlEnv_clearenv();
+#  else /* ! (PERL_IMPLICIT_SYS || WIN32) */
+#    if defined(USE_ENVIRON_ARRAY)
+#      if defined(USE_ITHREADS)
+    /* only the parent thread can clobber the process environment */
+    if (PL_curinterp == aTHX)
+#      endif /* USE_ITHREADS */
+    {
+#      if ! defined(PERL_USE_SAFE_PUTENV)
+    if ( !PL_use_safe_putenv) {
+      I32 i;
+      if (environ == PL_origenviron)
+        environ = (char**)safesysmalloc(sizeof(char*));
+      else
+        for (i = 0; environ[i]; i++)
+          (void)safesysfree(environ[i]);
+    }
+    environ[0] = NULL;
+#      else /* PERL_USE_SAFE_PUTENV */
+#        if defined(HAS_CLEARENV)
+    (void)clearenv();
+#        elif defined(HAS_UNSETENV)
+    int bsiz = 80; /* Most envvar names will be shorter than this. */
+    char *buf = (char*)safesysmalloc(bsiz * sizeof(char));
+    while (*environ != NULL) {
+      char *e = strchr(*environ, '=');
+      int l = e ? e - *environ : strlen(*environ);
+      if (bsiz < l + 1) {
+        (void)safesysfree(buf);
+        bsiz = l + 1;
+        buf = (char*)safesysmalloc(bsiz * sizeof(char));
+      } 
+      strncpy(buf, *environ, l);
+      *(buf + l) = '\0';
+      (void)unsetenv(buf);
+    }
+    (void)safesysfree(buf);
+#        else /* ! HAS_CLEARENV && ! HAS_UNSETENV */
+    /* Just null environ and accept the leakage. */
+    *environ = NULL;
+#        endif /* HAS_CLEARENV || HAS_UNSETENV */
+#      endif /* ! PERL_USE_SAFE_PUTENV */
+    }
+#    endif /* USE_ENVIRON_ARRAY */
+#  endif /* PERL_IMPLICIT_SYS || WIN32 */
+#endif /* PERL_MICRO */
+}
+
+/*
  * Local variables:
  * c-indentation-style: bsd
  * c-basic-offset: 4