Assert that we don't access strings saved for $1 etc. out of bounds
[p5sagit/p5-mst-13.2.git] / mg.c
diff --git a/mg.c b/mg.c
index 041a09e..f82aa0d 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -272,7 +272,7 @@ Perl_mg_length(pTHX_ SV *sv)
 
     if (DO_UTF8(sv)) {
         const U8 *s = (U8*)SvPV_const(sv, len);
-        len = Perl_utf8_length(aTHX_ s, s + len);
+       len = utf8_length(s, s + len);
     }
     else
         (void)SvPV_const(sv, len);
@@ -379,7 +379,7 @@ Perl_mg_copy(pTHX_ SV *sv, SV *nsv, const char *key, I32 klen)
        }
        else {
            const char type = mg->mg_type;
-           if (isUPPER(type)) {
+           if (isUPPER(type) && type != PERL_MAGIC_uvar) {
                sv_magic(nsv,
                     (type == PERL_MAGIC_tied)
                        ? SvTIED_obj(sv, mg)
@@ -531,7 +531,7 @@ Perl_magic_regdatum_get(pTHX_ SV *sv, MAGIC *mg)
                    if (i > 0 && RX_MATCH_UTF8(rx)) {
                        const char * const b = rx->subbeg;
                        if (b)
-                           i = Perl_utf8_length(aTHX_ (U8*)b, (U8*)(b+i));
+                           i = utf8_length((U8*)b, (U8*)(b+i));
                    }
 
                    sv_setiv(sv, i);
@@ -819,10 +819,11 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
             else if (PL_compiling.cop_warnings == pWARN_ALL) {
                /* Get the bit mask for $warnings::Bits{all}, because
                 * it could have been extended by warnings::register */
-               SV **bits_all;
                HV * const bits=get_hv("warnings::Bits", FALSE);
-               if (bits && (bits_all=hv_fetchs(bits, "all", FALSE))) {
-                   sv_setsv(sv, *bits_all);
+               if (bits) {
+                   SV ** const bits_all = hv_fetchs(bits, "all", FALSE);
+                   if (bits_all)
+                       sv_setsv(sv, *bits_all);
                }
                else {
                    sv_setpvn(sv, WARN_ALLstring, WARNsize) ;
@@ -853,6 +854,7 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
                i = t1 - s1;
                s = rx->subbeg + s1;
                assert(rx->subbeg);
+               assert(rx->sublen >= s1);
 
              getrx:
                if (i >= 0) {
@@ -860,8 +862,13 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
                    TAINT_NOT;
                    sv_setpvn(sv, s, i);
                    PL_tainted = oldtainted;
-                   if (RX_MATCH_UTF8(rx) && is_utf8_string((U8*)s, i))
+                   if ( (rx->reganch & ROPT_CANY_SEEN)
+                       ? (RX_MATCH_UTF8(rx)
+                                   && (!i || is_utf8_string((U8*)s, i)))
+                       : (RX_MATCH_UTF8(rx)) )
+                   {
                        SvUTF8_on(sv);
+                   }
                    else
                        SvUTF8_off(sv);
                    if (PL_tainting) {
@@ -967,7 +974,7 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
     case '/':
        break;
     case '[':
-       WITH_THR(sv_setiv(sv, (IV)CopARYBASE_get(PL_curcop)));
+       sv_setiv(sv, (IV)CopARYBASE_get(PL_curcop));
        break;
     case '|':
        if (GvIOp(PL_defoutgv))
@@ -1072,8 +1079,7 @@ Perl_magic_setenv(pTHX_ SV *sv, MAGIC *mg)
            Stat_t sbuf;
            int i = 0, j = 0;
 
-           strncpy(eltbuf, s, 255);
-           eltbuf[255] = 0;
+           my_strlcpy(eltbuf, s, sizeof(eltbuf));
            elt = eltbuf;
            do {          /* DCL$PATH may be a search list */
                while (1) {   /* as may dev portion of any element */
@@ -1102,11 +1108,20 @@ Perl_magic_setenv(pTHX_ SV *sv, MAGIC *mg)
                char tmpbuf[256];
                Stat_t st;
                I32 i;
+#ifdef VMS  /* Hmm.  How do we get $Config{path_sep} from C? */
+               const char path_sep = '|';
+#else
+               const char path_sep = ':';
+#endif
                s = delimcpy(tmpbuf, tmpbuf + sizeof tmpbuf,
-                            s, strend, ':', &i);
+                            s, strend, path_sep, &i);
                s++;
                if (i >= (I32)sizeof tmpbuf   /* too long -- assume the worst */
-                     || *tmpbuf != '/'
+#ifdef VMS
+                     || !strchr(tmpbuf, ':') /* no colon thus no device name -- assume relative path */
+#else
+                     || *tmpbuf != '/'       /* no starting slash -- assume relative path */
+#endif
                      || (PerlLIO_stat(tmpbuf, &st) == 0 && (st.st_mode & 2)) ) {
                    MgTAINTEDDIR_on(mg);
                    return 0;
@@ -1169,7 +1184,7 @@ static void
 restore_sigmask(pTHX_ SV *save_sv)
 {
     const sigset_t * const ossetp = (const sigset_t *) SvPV_nolen_const( save_sv );
-    (void)sigprocmask(SIG_SETMASK, ossetp, (sigset_t *)0);
+    (void)sigprocmask(SIG_SETMASK, ossetp, NULL);
 }
 #endif
 int
@@ -1215,14 +1230,12 @@ Perl_magic_clearsig(pTHX_ SV *sv, MAGIC *mg)
        SV** svp = NULL;
        if (strEQ(s,"__DIE__"))
            svp = &PL_diehook;
-       else if (strEQ(s,"__WARN__"))
+       else if (strEQ(s,"__WARN__") && PL_warnhook != PERL_WARNHOOK_FATAL)
            svp = &PL_warnhook;
-       else
-           Perl_croak(aTHX_ "No such hook: %s", s);
        if (svp && *svp) {
-            SV * const to_dec = *svp;
+           SV *const to_dec = *svp;
            *svp = NULL;
-           SvREFCNT_dec(to_dec);
+           SvREFCNT_dec(to_dec);
        }
     }
     else {
@@ -1302,7 +1315,17 @@ Perl_csighandler(int sig)
             exit(1);
 #endif
 #endif
-   if (PL_signals & PERL_SIGNALS_UNSAFE_FLAG)
+   if (
+#ifdef SIGILL
+          sig == SIGILL ||
+#endif
+#ifdef SIGBUS
+          sig == SIGBUS ||
+#endif
+#ifdef SIGSEGV
+          sig == SIGSEGV ||
+#endif
+          (PL_signals & PERL_SIGNALS_UNSAFE_FLAG))
        /* Call the perl level handler now--
         * with risk we may be in malloc() etc. */
        (*PL_sighandlerp)(sig);
@@ -1375,7 +1398,8 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
            Perl_croak(aTHX_ "No such hook: %s", s);
        i = 0;
        if (*svp) {
-           to_dec = *svp;
+           if (*svp != PERL_WARNHOOK_FATAL)
+               to_dec = *svp;
            *svp = NULL;
        }
     }
@@ -2281,11 +2305,16 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
                        accumulate |= ptr[i] ;
                        any_fatals |= (ptr[i] & 0xAA) ;
                    }
-                   if (!accumulate)
-                       PL_compiling.cop_warnings = pWARN_NONE;
+                   if (!accumulate) {
+                       if (!specialWARN(PL_compiling.cop_warnings))
+                           PerlMemShared_free(PL_compiling.cop_warnings);
+                       PL_compiling.cop_warnings = pWARN_NONE;
+                   }
                    /* Yuck. I can't see how to abstract this:  */
                    else if (isWARN_on(((STRLEN *)SvPV_nolen_const(sv)) - 1,
                                       WARN_ALL) && !any_fatals) {
+                       if (!specialWARN(PL_compiling.cop_warnings))
+                           PerlMemShared_free(PL_compiling.cop_warnings);
                        PL_compiling.cop_warnings = pWARN_ALL;
                        PL_dowarn |= G_WARN_ONCE ;
                    }
@@ -2514,8 +2543,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
             }
             if (i)
                 (void)setgroups(i, gary);
-            if (gary)
-                Safefree(gary);
+           Safefree(gary);
        }
 #else  /* HAS_SETGROUPS */
        PL_egid = SvIV(sv);
@@ -2736,7 +2764,7 @@ Perl_sighandler(int sig)
 #endif
                   EXTEND(SP, 2);
                   PUSHs((SV*)rv);
-                  PUSHs(newSVpv((void*)sip, sizeof(*sip)));
+                  PUSHs(newSVpv((char *)sip, sizeof(*sip)));
              }
 
               va_end(args);
@@ -2811,10 +2839,10 @@ S_restore_magic(pTHX_ const void *p)
            /* downgrade public flags to private,
               and discard any other private flags */
 
-           U32 public = SvFLAGS(sv) & (SVf_IOK|SVf_NOK|SVf_POK);
-           if (public) {
-               SvFLAGS(sv) &= ~( public | SVp_IOK|SVp_NOK|SVp_POK );
-               SvFLAGS(sv) |= ( public << PRIVSHIFT );
+           const U32 pubflags = SvFLAGS(sv) & (SVf_IOK|SVf_NOK|SVf_POK);
+           if (pubflags) {
+               SvFLAGS(sv) &= ~( pubflags | (SVp_IOK|SVp_NOK|SVp_POK) );
+               SvFLAGS(sv) |= ( pubflags << PRIVSHIFT );
            }
        }
     }
@@ -2898,6 +2926,8 @@ int
 Perl_magic_clearhint(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+    PERL_UNUSED_ARG(sv);
+
     assert(mg->mg_len == HEf_SVKEY);
 
     PERL_UNUSED_ARG(sv);