This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate:
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index 16c7bbc..5efd546 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -4497,14 +4497,17 @@ Perl_sv_force_normal_flags(pTHX_ register SV *sv, U32 flags)
     if (SvREADONLY(sv)) {
        if (SvFAKE(sv)) {
            char *pvx = SvPVX(sv);
+           int is_utf8 = SvUTF8(sv);
            STRLEN len = SvCUR(sv);
             U32 hash   = SvUVX(sv);
            SvFAKE_off(sv);
            SvREADONLY_off(sv);
+            SvPVX(sv) = 0;
+            SvLEN(sv) = 0;
            SvGROW(sv, len + 1);
            Move(pvx,SvPVX(sv),len,char);
            *SvEND(sv) = '\0';
-           unsharepvn(pvx, SvUTF8(sv) ? -(I32)len : len, hash);
+           unsharepvn(pvx, is_utf8 ? -(I32)len : len, hash);
        }
        else if (IN_PERL_RUNTIME)
            Perl_croak(aTHX_ PL_no_modify);
@@ -4896,6 +4899,7 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
            && how != PERL_MAGIC_bm
            && how != PERL_MAGIC_fm
            && how != PERL_MAGIC_sv
+           && how != PERL_MAGIC_backref
           )
        {
            Perl_croak(aTHX_ PL_no_modify);
@@ -5134,15 +5138,13 @@ S_sv_add_backref(pTHX_ SV *tsv, SV *sv)
         * by magic_killbackrefs() when tsv is being freed */
     }
     if (AvFILLp(av) >= AvMAX(av)) {
+        I32 i;
         SV **svp = AvARRAY(av);
-        I32 i = AvFILLp(av);
-        while (i >= 0) {
-            if (svp[i] == &PL_sv_undef) {
+        for (i = AvFILLp(av); i >= 0; i--)
+            if (!svp[i]) {
                 svp[i] = sv;        /* reuse the slot */
                 return;
             }
-            i--;
-        }
         av_extend(av, AvFILLp(av)+1);
     }
     AvARRAY(av)[++AvFILLp(av)] = sv; /* av_push() */
@@ -5164,13 +5166,8 @@ S_sv_del_backref(pTHX_ SV *sv)
        Perl_croak(aTHX_ "panic: del_backref");
     av = (AV *)mg->mg_obj;
     svp = AvARRAY(av);
-    i = AvFILLp(av);
-    while (i >= 0) {
-       if (svp[i] == sv) {
-           svp[i] = &PL_sv_undef; /* XXX */
-       }
-       i--;
-    }
+    for (i = AvFILLp(av); i >= 0; i--)
+       if (svp[i] == sv) svp[i] = Nullsv;
 }
 
 /*
@@ -5732,10 +5729,8 @@ S_utf8_mg_pos_init(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offse
     bool found = FALSE; 
 
     if (SvMAGICAL(sv) && !SvREADONLY(sv)) {
-       if (!*mgp) {
-           sv_magic(sv, 0, PERL_MAGIC_utf8, 0, 0);
-           *mgp = mg_find(sv, PERL_MAGIC_utf8);
-       }
+       if (!*mgp)
+           *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, &PL_vtbl_utf8, 0, 0);
        assert(*mgp);
 
        if ((*mgp)->mg_ptr)
@@ -5828,6 +5823,12 @@ S_utf8_mg_pos(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offsetp, I
                      /* Update the cache. */
                      (*cachep)[i]   = (STRLEN)uoff;
                      (*cachep)[i+1] = p - start;
+
+                     /* Drop the stale "length" cache */
+                     if (i == 0) {
+                         (*cachep)[2] = 0;
+                         (*cachep)[3] = 0;
+                     }
  
                      found = TRUE;
                 }
@@ -8546,7 +8547,7 @@ F0convert(NV nv, char *endbuf, STRLEN *len)
        nv = -nv;
     if (nv < UV_MAX) {
        nv += 0.5;
-       uv = nv;
+       uv = (UV)nv;
        if (uv & 1 && uv == nv)
            uv--;                       /* Round to even */
        do {
@@ -8640,7 +8641,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        pp = pat + 2;
        while (*pp >= '0' && *pp <= '9')
            digits = 10 * digits + (*pp++ - '0');
-       if (pp - pat == patlen - 1) {
+       if (pp - pat == (int)patlen - 1) {
            NV nv;
 
            if (args)
@@ -8650,8 +8651,12 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            else
                return;
            if (*pp == 'g') {
-               if (digits < sizeof(ebuf) - NV_DIG - 10) { /* 0, point, slack */
-                   Gconvert(nv, digits, 0, ebuf);
+               /* Add check for digits != 0 because it seems that some
+                  gconverts are buggy in this case, and we don't yet have
+                  a Configure test for this.  */
+               if (digits && digits < sizeof(ebuf) - NV_DIG - 10) {
+                    /* 0, point, slack */
+                   Gconvert(nv, (int)digits, 0, ebuf);
                    sv_catpv(sv, ebuf);
                    if (*ebuf)  /* May return an empty string for digits==0 */
                        return;
@@ -9047,23 +9052,23 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            else if (args) {
                switch (intsize) {
                case 'h':       iv = (short)va_arg(*args, int); break;
-               default:        iv = va_arg(*args, int); break;
                case 'l':       iv = va_arg(*args, long); break;
                case 'V':       iv = va_arg(*args, IV); break;
+               default:        iv = va_arg(*args, int); break;
 #ifdef HAS_QUAD
                case 'q':       iv = va_arg(*args, Quad_t); break;
 #endif
                }
            }
            else {
-               iv = SvIVx(argsv);
+               IV tiv = SvIVx(argsv); /* work around GCC bug #13488 */
                switch (intsize) {
-               case 'h':       iv = (short)iv; break;
-               default:        break;
-               case 'l':       iv = (long)iv; break;
-               case 'V':       break;
+               case 'h':       iv = (short)tiv; break;
+               case 'l':       iv = (long)tiv; break;
+               case 'V':
+               default:        iv = tiv; break;
 #ifdef HAS_QUAD
-               case 'q':       iv = (Quad_t)iv; break;
+               case 'q':       iv = (Quad_t)tiv; break;
 #endif
                }
            }
@@ -9131,23 +9136,23 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            else if (args) {
                switch (intsize) {
                case 'h':  uv = (unsigned short)va_arg(*args, unsigned); break;
-               default:   uv = va_arg(*args, unsigned); break;
                case 'l':  uv = va_arg(*args, unsigned long); break;
                case 'V':  uv = va_arg(*args, UV); break;
+               default:   uv = va_arg(*args, unsigned); break;
 #ifdef HAS_QUAD
-               case 'q':  uv = va_arg(*args, Quad_t); break;
+               case 'q':  uv = va_arg(*args, Uquad_t); break;
 #endif
                }
            }
            else {
-               uv = SvUVx(argsv);
+               UV tuv = SvUVx(argsv); /* work around GCC bug #13488 */
                switch (intsize) {
-               case 'h':       uv = (unsigned short)uv; break;
-               default:        break;
-               case 'l':       uv = (unsigned long)uv; break;
-               case 'V':       break;
+               case 'h':       uv = (unsigned short)tuv; break;
+               case 'l':       uv = (unsigned long)tuv; break;
+               case 'V':
+               default:        uv = tuv; break;
 #ifdef HAS_QUAD
-               case 'q':       uv = (Quad_t)uv; break;
+               case 'q':       uv = (Uquad_t)tuv; break;
 #endif
                }
            }
@@ -9360,8 +9365,10 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
            if ( !(width || left || plus || alt) && fill != '0'
                 && has_precis && intsize != 'q' ) {    /* Shortcuts */
-               if ( c == 'g') {
-                   Gconvert(nv, precis, 0, PL_efloatbuf);
+               /* See earlier comment about buggy Gconvert when digits,
+                  aka precis is 0  */
+               if ( c == 'g' && precis) {
+                   Gconvert((NV)nv, (int)precis, 0, PL_efloatbuf);
                    if (*PL_efloatbuf)  /* May return an empty string for digits==0 */
                        goto float_converted;
                } else if ( c == 'f' && !precis) {
@@ -9786,16 +9793,15 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
            nmg->mg_obj = (SV*)re_dup((REGEXP*)mg->mg_obj, param);
        }
        else if(mg->mg_type == PERL_MAGIC_backref) {
-            AV *av = (AV*) mg->mg_obj;
-            SV **svp;
-            I32 i;
-            nmg->mg_obj = (SV*)newAV();
-            svp = AvARRAY(av);
-            i = AvFILLp(av);
-            while (i >= 0) {
-                 av_push((AV*)nmg->mg_obj,sv_dup(svp[i],param));
-                 i--;
-            }
+           AV *av = (AV*) mg->mg_obj;
+           SV **svp;
+           I32 i;
+           SvREFCNT_inc(nmg->mg_obj = (SV*)newAV());
+           svp = AvARRAY(av);
+           for (i = AvFILLp(av); i >= 0; i--) {
+               if (!svp[i] || SvREFCNT(svp[i]) < 2) continue;
+               av_push((AV*)nmg->mg_obj,sv_dup(svp[i],param));
+           }
        }
        else {
            nmg->mg_obj = (mg->mg_flags & MGf_REFCOUNTED)
@@ -10024,7 +10030,7 @@ S_gv_share(pTHX_ SV *sstr, CLONE_PARAMS *param)
         GvHV(gv) = (HV*)sv;
     }
     else {
-        SvREADONLY_on(GvAV(gv));
+        SvREADONLY_on(GvHV(gv));
     }
 
     return sstr; /* he_dup() will SvREFCNT_inc() */
@@ -11000,9 +11006,10 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_debug           = proto_perl->Idebug;
 
 #ifdef USE_REENTRANT_API
-#ifdef DEBUGGING
-    PERL_SET_CONTEXT(proto_perl);
-#endif
+    /* XXX: things like -Dm will segfault here in perlio, but doing
+     *  PERL_SET_CONTEXT(proto_perl);
+     * breaks too many other things
+     */
     Perl_reentrant_init(aTHX);
 #endif