applied suggested fix for xhv_array sizing, with portability tweaks
[p5sagit/p5-mst-13.2.git] / pp_hot.c
index 8331bb3..8e3bf70 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -250,9 +250,13 @@ PP(pp_aelemfast)
 {
     djSP;
     AV *av = GvAV((GV*)cSVOP->op_sv);
-    SV** svp = av_fetch(av, op->op_private, op->op_flags & OPf_MOD);
+    U32 lval = op->op_flags & OPf_MOD;
+    SV** svp = av_fetch(av, op->op_private, lval);
+    SV *sv = (svp ? *svp : &sv_undef);
     EXTEND(SP, 1);
-    PUSHs(svp ? *svp : &sv_undef);
+    if (!lval && SvGMAGICAL(sv))       /* see note in pp_helem() */
+       sv = sv_mortalcopy(sv);
+    PUSHs(sv);
     RETURN;
 }
 
@@ -626,7 +630,6 @@ PP(pp_aassign)
                hv_clear(hash);
 
                while (relem < lastrelem) {     /* gobble up all the rest */
-                   STRLEN len;
                    HE *didstore;
                    if (*relem)
                        sv = *(relem++);
@@ -645,21 +648,36 @@ PP(pp_aassign)
                    }
                    TAINT_NOT;
                }
-               if (relem == lastrelem && dowarn) {
-                   if (relem == firstrelem &&
-                       SvROK(*relem) &&
-                       ( SvTYPE(SvRV(*relem)) == SVt_PVAV ||
-                         SvTYPE(SvRV(*relem)) == SVt_PVHV ) )
-                       warn("Reference found where even-sized list expected");
-                   else
-                       warn("Odd number of elements in hash assignment");
+               if (relem == lastrelem) {
+                   if (*relem) {
+                       HE *didstore;
+                       if (dowarn) {
+                           if (relem == firstrelem &&
+                               SvROK(*relem) &&
+                               ( SvTYPE(SvRV(*relem)) == SVt_PVAV ||
+                                 SvTYPE(SvRV(*relem)) == SVt_PVHV ) )
+                               warn("Reference found where even-sized list expected");
+                           else
+                               warn("Odd number of elements in hash assignment");
+                       }
+                       tmpstr = NEWSV(29,0);
+                       didstore = hv_store_ent(hash,*relem,tmpstr,0);
+                       if (magic) {
+                           if (SvSMAGICAL(tmpstr))
+                               mg_set(tmpstr);
+                           if (!didstore)
+                               SvREFCNT_dec(tmpstr);
+                       }
+                       TAINT_NOT;
+                   }
+                   relem++;
                }
            }
            break;
        default:
            if (SvTHINKFIRST(sv)) {
                if (SvREADONLY(sv) && curcop != &compiling) {
-                   if (sv != &sv_undef && sv != &sv_yes && sv != &sv_no)
+                   if (!SvIMMORTAL(sv))
                        DIE(no_modify);
                    if (relem <= lastrelem)
                        relem++;
@@ -772,6 +790,7 @@ PP(pp_match)
     I32 safebase;
     char *truebase;
     register REGEXP *rx = pm->op_pmregexp;
+    bool rxtainted;
     I32 gimme = GIMME;
     STRLEN len;
     I32 minmatch = 0;
@@ -790,6 +809,8 @@ PP(pp_match)
     strend = s + len;
     if (!s)
        DIE("panic: do_match");
+    rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
+                (tainted && (pm->op_pmflags & PMf_RETAINT)));
     TAINT_NOT;
 
     if (pm->op_pmdynflags & PMdf_USED) {
@@ -855,7 +876,7 @@ play_it_again:
            }
            else if (!(s = fbm_instr((unsigned char*)s + rx->check_offset_min,
                                     (unsigned char*)strend, 
-                                    rx->check_substr)))
+                                    rx->check_substr, 0)))
                goto nope;
            else if ((rx->reganch & ROPT_CHECK_ALL) && !sawampersand)
                goto yup;
@@ -896,6 +917,8 @@ play_it_again:
     /*NOTREACHED*/
 
   gotcha:
+    if (rxtainted)
+       RX_MATCH_TAINTED_on(rx);
     TAINT_IF(RX_MATCH_TAINTED(rx));
     if (gimme == G_ARRAY) {
        I32 iters, i, len;
@@ -949,6 +972,8 @@ play_it_again:
     }
 
 yup:                                   /* Confirmed by check_substr */
+    if (rxtainted)
+       RX_MATCH_TAINTED_on(rx);
     TAINT_IF(RX_MATCH_TAINTED(rx));
     ++BmUSEFUL(rx->check_substr);
     curpm = pm;
@@ -1294,6 +1319,7 @@ PP(pp_helem)
     HV *hv = (HV*)POPs;
     U32 lval = op->op_flags & OPf_MOD;
     U32 defer = op->op_private & OPpLVAL_DEFER;
+    SV *sv;
 
     if (SvTYPE(hv) == SVt_PVHV) {
        he = hv_fetch_ent(hv, keysv, lval && !defer, 0);
@@ -1330,7 +1356,16 @@ PP(pp_helem)
        else if (op->op_private & OPpDEREF)
            vivify_ref(*svp, op->op_private & OPpDEREF);
     }
-    PUSHs(svp ? *svp : &sv_undef);
+    sv = (svp ? *svp : &sv_undef);
+    /* This makes C<local $tied{foo} = $tied{foo}> possible.
+     * Pushing the magical RHS on to the stack is useless, since
+     * that magic is soon destined to be misled by the local(),
+     * and thus the later pp_sassign() will fail to mg_get() the
+     * old value.  This should also cure problems with delayed
+     * mg_get()s.  GSAR 98-07-03 */
+    if (!lval && SvGMAGICAL(sv))
+       sv = sv_mortalcopy(sv);
+    PUSHs(sv);
     RETURN;
 }
 
@@ -1506,7 +1541,10 @@ PP(pp_subst)
     s = SvPV(TARG, len);
     if (!SvPOKp(TARG) || SvTYPE(TARG) == SVt_PVGV)
        force_on_match = 1;
-    rxtainted = tainted << 1;
+    rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
+                (tainted && (pm->op_pmflags & PMf_RETAINT)));
+    if (tainted)
+       rxtainted |= 2;
     TAINT_NOT;
 
   force_it:
@@ -1542,7 +1580,7 @@ PP(pp_subst)
            }
            else if (!(s = fbm_instr((unsigned char*)s + rx->check_offset_min, 
                                     (unsigned char*)strend,
-                                    rx->check_substr)))
+                                    rx->check_substr, 0)))
                goto nope;
            if (s && rx->check_offset_max < s - m) {
                ++BmUSEFUL(rx->check_substr);
@@ -2300,6 +2338,7 @@ PP(pp_aelem)
     AV* av = (AV*)POPs;
     U32 lval = op->op_flags & OPf_MOD;
     U32 defer = (op->op_private & OPpLVAL_DEFER) && (elem > AvFILL(av));
+    SV *sv;
 
     if (elem > 0)
        elem -= curcop->cop_arybase;
@@ -2326,7 +2365,10 @@ PP(pp_aelem)
        else if (op->op_private & OPpDEREF)
            vivify_ref(*svp, op->op_private & OPpDEREF);
     }
-    PUSHs(svp ? *svp : &sv_undef);
+    sv = (svp ? *svp : &sv_undef);
+    if (!lval && SvGMAGICAL(sv))       /* see note in pp_helem() */
+       sv = sv_mortalcopy(sv);
+    PUSHs(sv);
     RETURN;
 }