X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/d4c19fe8d8a6e04364af0548bf783e83ab5987d2..e4c5322dee1b8e87ff0e7aee20effad846301447:/mg.c?ds=sidebyside diff --git a/mg.c b/mg.c index 210d681..1aaf0ac 100644 --- a/mg.c +++ b/mg.c @@ -1,7 +1,7 @@ /* mg.c * * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - * 2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others + * 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. @@ -100,7 +100,10 @@ S_save_magic(pTHX_ I32 mgs_ix, SV *sv) SvMAGICAL_off(sv); SvREADONLY_off(sv); - SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT; + if (!(SvFLAGS(sv) & (SVf_IOK|SVf_NOK|SVf_POK))) { + /* No public flags are set, so promote any private flags to public. */ + SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT; + } } /* @@ -129,6 +132,39 @@ Perl_mg_magical(pTHX_ SV *sv) } } + +/* is this container magic (%ENV, $1 etc), or value magic (pos, taint etc)? */ + +STATIC bool +S_is_container_magic(const MAGIC *mg) +{ + switch (mg->mg_type) { + case PERL_MAGIC_bm: + case PERL_MAGIC_fm: + case PERL_MAGIC_regex_global: + case PERL_MAGIC_nkeys: +#ifdef USE_LOCALE_COLLATE + case PERL_MAGIC_collxfrm: +#endif + case PERL_MAGIC_qr: + case PERL_MAGIC_taint: + case PERL_MAGIC_vec: + case PERL_MAGIC_vstring: + case PERL_MAGIC_utf8: + case PERL_MAGIC_substr: + case PERL_MAGIC_defelem: + case PERL_MAGIC_arylen: + case PERL_MAGIC_pos: + case PERL_MAGIC_backref: + case PERL_MAGIC_arylen_p: + case PERL_MAGIC_rhash: + case PERL_MAGIC_symtab: + return 0; + default: + return 1; + } +} + /* =for apidoc mg_get @@ -152,7 +188,7 @@ Perl_mg_get(pTHX_ SV *sv) cause the SV's buffer to get stolen (and maybe other stuff). So restore it. */ - sv_2mortal(SvREFCNT_inc_simple(sv)); + sv_2mortal(SvREFCNT_inc_simple_NN(sv)); if (!was_temp) { SvTEMP_off(sv); } @@ -235,6 +271,8 @@ Perl_mg_set(pTHX_ SV *sv) mg->mg_flags &= ~MGf_GSKIP; /* setting requires another read */ (SSPTR(mgs_ix, MGS*))->mgs_flags = 0; } + if (PL_localizing == 2 && !S_is_container_magic(mg)) + continue; if (vtbl && vtbl->svt_set) CALL_FPTR(vtbl->svt_set)(aTHX_ sv, mg); } @@ -272,7 +310,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 +417,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) @@ -410,31 +448,9 @@ Perl_mg_localize(pTHX_ SV *sv, SV *nsv) dVAR; MAGIC *mg; for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { - MGVTBL* const vtbl = mg->mg_virtual; - switch (mg->mg_type) { - /* value magic types: don't copy */ - case PERL_MAGIC_bm: - case PERL_MAGIC_fm: - case PERL_MAGIC_regex_global: - case PERL_MAGIC_nkeys: -#ifdef USE_LOCALE_COLLATE - case PERL_MAGIC_collxfrm: -#endif - case PERL_MAGIC_qr: - case PERL_MAGIC_taint: - case PERL_MAGIC_vec: - case PERL_MAGIC_vstring: - case PERL_MAGIC_utf8: - case PERL_MAGIC_substr: - case PERL_MAGIC_defelem: - case PERL_MAGIC_arylen: - case PERL_MAGIC_pos: - case PERL_MAGIC_backref: - case PERL_MAGIC_arylen_p: - case PERL_MAGIC_rhash: - case PERL_MAGIC_symtab: + const MGVTBL* const vtbl = mg->mg_virtual; + if (!S_is_container_magic(mg)) continue; - } if ((mg->mg_flags & MGf_LOCAL) && vtbl->svt_local) (void)CALL_FPTR(vtbl->svt_local)(aTHX_ nsv, mg); @@ -497,9 +513,19 @@ Perl_magic_regdata_cnt(pTHX_ SV *sv, MAGIC *mg) if (PL_curpm) { register const REGEXP * const rx = PM_GETRE(PL_curpm); if (rx) { - return mg->mg_obj - ? rx->nparens /* @+ */ - : rx->lastparen; /* @- */ + if (mg->mg_obj) { /* @+ */ + /* return the number possible */ + return rx->nparens; + } else { /* @- */ + I32 paren = rx->lastparen; + + /* return the last filled */ + while ( paren >= 0 + && (rx->offs[paren].start == -1 + || rx->offs[paren].end == -1) ) + paren--; + return (U32)paren; + } } } @@ -519,8 +545,8 @@ Perl_magic_regdatum_get(pTHX_ SV *sv, MAGIC *mg) if (paren < 0) return 0; if (paren <= (I32)rx->nparens && - (s = rx->startp[paren]) != -1 && - (t = rx->endp[paren]) != -1) + (s = rx->offs[paren].start) != -1 && + (t = rx->offs[paren].end) != -1) { register I32 i; if (mg->mg_obj) /* @+ */ @@ -531,7 +557,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); @@ -567,8 +593,8 @@ Perl_magic_len(pTHX_ SV *sv, MAGIC *mg) paren = atoi(mg->mg_ptr); /* $& is in [0] */ getparen: if (paren <= (I32)rx->nparens && - (s1 = rx->startp[paren]) != -1 && - (t1 = rx->endp[paren]) != -1) + (s1 = rx->offs[paren].start) != -1 && + (t1 = rx->offs[paren].end) != -1) { i = t1 - s1; getlen: @@ -611,8 +637,8 @@ Perl_magic_len(pTHX_ SV *sv, MAGIC *mg) return 0; case '`': if (PL_curpm && (rx = PM_GETRE(PL_curpm))) { - if (rx->startp[0] != -1) { - i = rx->startp[0]; + if (rx->offs[0].start != -1) { + i = rx->offs[0].start; if (i > 0) { s1 = 0; t1 = i; @@ -623,10 +649,10 @@ Perl_magic_len(pTHX_ SV *sv, MAGIC *mg) return 0; case '\'': if (PL_curpm && (rx = PM_GETRE(PL_curpm))) { - if (rx->endp[0] != -1) { - i = rx->sublen - rx->endp[0]; + if (rx->offs[0].end != -1) { + i = rx->sublen - rx->offs[0].end; if (i > 0) { - s1 = rx->endp[0]; + s1 = rx->offs[0].end; t1 = rx->sublen; goto getlen; } @@ -654,13 +680,38 @@ Perl_magic_len(pTHX_ SV *sv, MAGIC *mg) } \ } STMT_END +void +Perl_emulate_cop_io(pTHX_ const COP *const c, SV *const sv) +{ + if (!(CopHINTS_get(c) & (HINT_LEXICAL_IO_IN|HINT_LEXICAL_IO_OUT))) + sv_setsv(sv, &PL_sv_undef); + else { + sv_setpvs(sv, ""); + SvUTF8_off(sv); + if ((CopHINTS_get(c) & HINT_LEXICAL_IO_IN)) { + SV *const value = Perl_refcounted_he_fetch(aTHX_ + c->cop_hints_hash, + 0, "open<", 5, 0, 0); + assert(value); + sv_catsv(sv, value); + } + sv_catpvs(sv, "\0"); + if ((CopHINTS_get(c) & HINT_LEXICAL_IO_OUT)) { + SV *const value = Perl_refcounted_he_fetch(aTHX_ + c->cop_hints_hash, + 0, "open>", 5, 0, 0); + assert(value); + sv_catsv(sv, value); + } + } +} + int Perl_magic_get(pTHX_ SV *sv, MAGIC *mg) { dVAR; register I32 paren; register char *s = NULL; - register I32 i; register REGEXP *rx; const char * const remaining = mg->mg_ptr + 1; const char nextchar = *remaining; @@ -758,15 +809,17 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg) SvTAINTED_off(sv); } else if (strEQ(remaining, "PEN")) { - if (!PL_compiling.cop_io) - sv_setsv(sv, &PL_sv_undef); - else { - sv_setsv(sv, PL_compiling.cop_io); - } + Perl_emulate_cop_io(aTHX_ &PL_compiling, sv); } break; - case '\020': /* ^P */ - sv_setiv(sv, (IV)PL_perldb); + case '\020': + if (nextchar == '\0') { /* ^P */ + sv_setiv(sv, (IV)PL_perldb); + } else if (strEQ(remaining, "REMATCH")) { /* $^PREMATCH */ + goto do_prematch_fetch; + } else if (strEQ(remaining, "OSTMATCH")) { /* $^POSTMATCH */ + goto do_postmatch_fetch; + } break; case '\023': /* ^S */ if (nextchar == '\0') { @@ -816,102 +869,71 @@ 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) ; } } else { - sv_setsv(sv, PL_compiling.cop_warnings); + sv_setpvn(sv, (char *) (PL_compiling.cop_warnings + 1), + *PL_compiling.cop_warnings); } SvPOK_only(sv); } break; + case '\015': /* $^MATCH */ + if (strEQ(remaining, "ATCH")) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '&': - if (PL_curpm && (rx = PM_GETRE(PL_curpm))) { - I32 s1, t1; - - /* - * Pre-threads, this was paren = atoi(GvENAME((GV*)mg->mg_obj)); - * XXX Does the new way break anything? - */ - paren = atoi(mg->mg_ptr); /* $& is in [0] */ - getparen: - if (paren <= (I32)rx->nparens && - (s1 = rx->startp[paren]) != -1 && - (t1 = rx->endp[paren]) != -1) - { - i = t1 - s1; - s = rx->subbeg + s1; - assert(rx->subbeg); - - getrx: - if (i >= 0) { - const int oldtainted = PL_tainted; - TAINT_NOT; - sv_setpvn(sv, s, i); - PL_tainted = oldtainted; - if (RX_MATCH_UTF8(rx) && is_utf8_string((U8*)s, i)) - SvUTF8_on(sv); - else - SvUTF8_off(sv); - if (PL_tainting) { - if (RX_MATCH_TAINTED(rx)) { - MAGIC* const mg = SvMAGIC(sv); - MAGIC* mgt; - PL_tainted = 1; - SvMAGIC_set(sv, mg->mg_moremagic); - SvTAINT(sv); - if ((mgt = SvMAGIC(sv))) { - mg->mg_moremagic = mgt; - SvMAGIC_set(sv, mg); - } - } else - SvTAINTED_off(sv); - } - break; - } + if (PL_curpm && (rx = PM_GETRE(PL_curpm))) { + /* + * Pre-threads, this was paren = atoi(GvENAME((GV*)mg->mg_obj)); + * XXX Does the new way break anything? + */ + paren = atoi(mg->mg_ptr); /* $& is in [0] */ + CALLREG_NUMBUF(rx,paren,sv); + break; } + sv_setsv(sv,&PL_sv_undef); } - sv_setsv(sv,&PL_sv_undef); break; case '+': if (PL_curpm && (rx = PM_GETRE(PL_curpm))) { - paren = rx->lastparen; - if (paren) - goto getparen; + if (rx->lastparen) { + CALLREG_NUMBUF(rx,rx->lastparen,sv); + break; + } } sv_setsv(sv,&PL_sv_undef); break; case '\016': /* ^N */ if (PL_curpm && (rx = PM_GETRE(PL_curpm))) { - paren = rx->lastcloseparen; - if (paren) - goto getparen; + if (rx->lastcloseparen) { + CALLREG_NUMBUF(rx,rx->lastcloseparen,sv); + break; + } + } sv_setsv(sv,&PL_sv_undef); break; case '`': + do_prematch_fetch: if (PL_curpm && (rx = PM_GETRE(PL_curpm))) { - if ((s = rx->subbeg) && rx->startp[0] != -1) { - i = rx->startp[0]; - goto getrx; - } + CALLREG_NUMBUF(rx,-2,sv); + break; } sv_setsv(sv,&PL_sv_undef); break; case '\'': + do_postmatch_fetch: if (PL_curpm && (rx = PM_GETRE(PL_curpm))) { - if (rx->subbeg && rx->endp[0] != -1) { - s = rx->subbeg + rx->endp[0]; - i = rx->sublen - rx->endp[0]; - goto getrx; - } + CALLREG_NUMBUF(rx,-1,sv); + break; } sv_setsv(sv,&PL_sv_undef); break; @@ -963,7 +985,7 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg) case '/': break; case '[': - WITH_THR(sv_setiv(sv, (IV)PL_curcop->cop_arybase)); + sv_setiv(sv, (IV)CopARYBASE_get(PL_curcop)); break; case '|': if (GvIOp(PL_defoutgv)) @@ -1042,8 +1064,8 @@ int Perl_magic_setenv(pTHX_ SV *sv, MAGIC *mg) { dVAR; - STRLEN len, klen; - const char *s = SvPV_const(sv,len); + STRLEN len = 0, klen; + const char *s = SvOK(sv) ? SvPV_const(sv,len) : ""; const char * const ptr = MgPV_const(mg,klen); my_setenv(ptr, s); @@ -1053,7 +1075,7 @@ Perl_magic_setenv(pTHX_ SV *sv, MAGIC *mg) if (!len) { SV ** const valp = hv_fetch(GvHVn(PL_envgv), ptr, klen, FALSE); if (valp) - s = SvPV_const(*valp, len); + s = SvOK(*valp) ? SvPV_const(*valp, len) : ""; } #endif @@ -1068,8 +1090,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 */ @@ -1098,11 +1119,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 >= sizeof tmpbuf /* too long -- assume the worst */ - || *tmpbuf != '/' + if (i >= (I32)sizeof tmpbuf /* too long -- assume the worst */ +#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; @@ -1165,7 +1195,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 @@ -1178,20 +1208,21 @@ Perl_magic_getsig(pTHX_ SV *sv, MAGIC *mg) if(PL_psig_ptr[i]) sv_setsv(sv,PL_psig_ptr[i]); else { - Sighandler_t sigstate; - sigstate = rsignal_state(i); + Sighandler_t sigstate = rsignal_state(i); #ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS - if (PL_sig_handlers_initted && PL_sig_ignoring[i]) sigstate = SIG_IGN; + if (PL_sig_handlers_initted && PL_sig_ignoring[i]) + sigstate = SIG_IGN; #endif #ifdef FAKE_DEFAULT_SIGNAL_HANDLERS - if (PL_sig_handlers_initted && PL_sig_defaulting[i]) sigstate = SIG_DFL; + if (PL_sig_handlers_initted && PL_sig_defaulting[i]) + sigstate = SIG_DFL; #endif /* cache state so we don't fetch it again */ if(sigstate == (Sighandler_t) SIG_IGN) - sv_setpv(sv,"IGNORE"); + sv_setpvs(sv,"IGNORE"); else sv_setsv(sv,&PL_sv_undef); - PL_psig_ptr[i] = SvREFCNT_inc_simple(sv); + PL_psig_ptr[i] = SvREFCNT_inc_simple_NN(sv); SvTEMP_off(sv); } } @@ -1210,14 +1241,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 { @@ -1263,6 +1292,23 @@ Perl_magic_clearsig(pTHX_ SV *sv, MAGIC *mg) return 0; } +/* + * The signal handling nomenclature has gotten a bit confusing since the advent of + * safe signals. S_raise_signal only raises signals by analogy with what the + * underlying system's signal mechanism does. It might be more proper to say that + * it defers signals that have already been raised and caught. + * + * PL_sig_pending and PL_psig_pend likewise do not track signals that are pending + * in the sense of being on the system's signal queue in between raising and delivery. + * They are only pending on Perl's deferral list, i.e., they track deferred signals + * awaiting delivery after the current Perl opcode completes and say nothing about + * signals raised but not yet caught in the underlying signal implementation. + */ + +#ifndef SIG_PENDING_DIE_COUNT +# define SIG_PENDING_DIE_COUNT 120 +#endif + static void S_raise_signal(pTHX_ int sig) { @@ -1270,7 +1316,9 @@ S_raise_signal(pTHX_ int sig) /* Set a flag to say this signal is pending */ PL_psig_pend[sig]++; /* And one to say _a_ signal is pending */ - PL_sig_pending = 1; + if (++PL_sig_pending >= SIG_PENDING_DIE_COUNT) + Perl_croak(aTHX_ "Maximal count of pending signals (%lu) exceeded", + (unsigned long)SIG_PENDING_DIE_COUNT); } Signal_t @@ -1297,7 +1345,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); @@ -1370,7 +1428,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; } } @@ -1403,7 +1462,7 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg) #endif SvREFCNT_dec(PL_psig_name[i]); to_dec = PL_psig_ptr[i]; - PL_psig_ptr[i] = SvREFCNT_inc_simple(sv); + PL_psig_ptr[i] = SvREFCNT_inc_simple_NN(sv); SvTEMP_off(sv); /* Make sure it doesn't go away on us */ PL_psig_name[i] = newSVpvn(s, len); SvREADONLY_on(PL_psig_name[i]); @@ -1421,7 +1480,7 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg) SvREFCNT_dec(to_dec); return 0; } - s = SvPV_force(sv,len); + s = SvOK(sv) ? SvPV_force(sv,len) : "DEFAULT"; if (strEQ(s,"IGNORE")) { if (i) { #ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS @@ -1454,7 +1513,7 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg) if (i) (void)rsignal(i, PL_csighandlerp); else - *svp = SvREFCNT_inc_simple(sv); + *svp = SvREFCNT_inc_simple_NN(sv); } #ifdef HAS_SIGPROCMASK if(i) @@ -1657,7 +1716,7 @@ Perl_magic_nextpack(pTHX_ SV *sv, MAGIC *mg, SV *key) } int -Perl_magic_existspack(pTHX_ SV *sv, MAGIC *mg) +Perl_magic_existspack(pTHX_ SV *sv, const MAGIC *mg) { return magic_methpack(sv,mg,"EXISTS"); } @@ -1666,7 +1725,7 @@ SV * Perl_magic_scalarpack(pTHX_ HV *hv, MAGIC *mg) { dVAR; dSP; - SV *retval = &PL_sv_undef; + SV *retval; SV * const tied = SvTIED_obj((SV*)hv, mg); HV * const pkg = SvSTASH((SV*)SvRV(tied)); @@ -1692,6 +1751,8 @@ Perl_magic_scalarpack(pTHX_ HV *hv, MAGIC *mg) if (call_method("SCALAR", G_SCALAR)) retval = *PL_stack_sp--; + else + retval = &PL_sv_undef; POPSTACK; LEAVE; return retval; @@ -1724,7 +1785,7 @@ Perl_magic_getarylen(pTHX_ SV *sv, const MAGIC *mg) dVAR; const AV * const obj = (AV*)mg->mg_obj; if (obj) { - sv_setiv(sv, AvFILL(obj) + PL_curcop->cop_arybase); + sv_setiv(sv, AvFILL(obj) + CopARYBASE_get(PL_curcop)); } else { SvOK_off(sv); } @@ -1737,7 +1798,7 @@ Perl_magic_setarylen(pTHX_ SV *sv, MAGIC *mg) dVAR; AV * const obj = (AV*)mg->mg_obj; if (obj) { - av_fill(obj, SvIV(sv) - PL_curcop->cop_arybase); + av_fill(obj, SvIV(sv) - CopARYBASE_get(PL_curcop)); } else { if (ckWARN(WARN_MISC)) Perl_warner(aTHX_ packWARN(WARN_MISC), @@ -1773,14 +1834,15 @@ Perl_magic_getpos(pTHX_ SV *sv, MAGIC *mg) { dVAR; SV* const lsv = LvTARG(sv); + PERL_UNUSED_ARG(mg); if (SvTYPE(lsv) >= SVt_PVMG && SvMAGIC(lsv)) { - mg = mg_find(lsv, PERL_MAGIC_regex_global); - if (mg && mg->mg_len >= 0) { - I32 i = mg->mg_len; + MAGIC * const found = mg_find(lsv, PERL_MAGIC_regex_global); + if (found && found->mg_len >= 0) { + I32 i = found->mg_len; if (DO_UTF8(lsv)) sv_pos_b2u(lsv, &i); - sv_setiv(sv, i + PL_curcop->cop_arybase); + sv_setiv(sv, i + CopARYBASE_get(PL_curcop)); return 0; } } @@ -1796,28 +1858,31 @@ Perl_magic_setpos(pTHX_ SV *sv, MAGIC *mg) SSize_t pos; STRLEN len; STRLEN ulen = 0; + MAGIC* found; - mg = 0; + PERL_UNUSED_ARG(mg); if (SvTYPE(lsv) >= SVt_PVMG && SvMAGIC(lsv)) - mg = mg_find(lsv, PERL_MAGIC_regex_global); - if (!mg) { + found = mg_find(lsv, PERL_MAGIC_regex_global); + else + found = NULL; + if (!found) { if (!SvOK(sv)) return 0; #ifdef PERL_OLD_COPY_ON_WRITE if (SvIsCOW(lsv)) sv_force_normal_flags(lsv, 0); #endif - mg = sv_magicext(lsv, NULL, PERL_MAGIC_regex_global, &PL_vtbl_mglob, - NULL, 0); + found = sv_magicext(lsv, NULL, PERL_MAGIC_regex_global, &PL_vtbl_mglob, + NULL, 0); } else if (!SvOK(sv)) { - mg->mg_len = -1; + found->mg_len = -1; return 0; } len = SvPOK(lsv) ? SvCUR(lsv) : sv_len(lsv); - pos = SvIV(sv) - PL_curcop->cop_arybase; + pos = SvIV(sv) - CopARYBASE_get(PL_curcop); if (DO_UTF8(lsv)) { ulen = sv_len_utf8(lsv); @@ -1839,8 +1904,8 @@ Perl_magic_setpos(pTHX_ SV *sv, MAGIC *mg) pos = p; } - mg->mg_len = pos; - mg->mg_flags &= ~MGf_MINMATCH; + found->mg_len = pos; + found->mg_flags &= ~MGf_MINMATCH; return 0; } @@ -1853,8 +1918,7 @@ Perl_magic_setglob(pTHX_ SV *sv, MAGIC *mg) if (!SvOK(sv)) return 0; - if (SvFLAGS(sv) & SVp_SCREAM - && (SvTYPE(sv) == SVt_PVGV || SvTYPE(sv) == SVt_PVGV)) { + if (isGV_with_GP(sv)) { /* We're actually already a typeglob, so don't need the stuff below. */ return 0; @@ -1895,7 +1959,7 @@ Perl_magic_setsubstr(pTHX_ SV *sv, MAGIC *mg) { dVAR; STRLEN len; - const char *tmps = SvPV_const(sv, len); + const char * const tmps = SvPV_const(sv, len); SV * const lsv = LvTARG(sv); I32 lvoff = LvTARGOFF(sv); I32 lvlen = LvTARGLEN(sv); @@ -1909,11 +1973,12 @@ Perl_magic_setsubstr(pTHX_ SV *sv, MAGIC *mg) SvUTF8_on(lsv); } else if (lsv && SvUTF8(lsv)) { + const char *utf8; sv_pos_u2b(lsv, &lvoff, &lvlen); LvTARGLEN(sv) = len; - tmps = (char*)bytes_to_utf8((U8*)tmps, &len); - sv_insert(lsv, lvoff, lvlen, tmps, len); - Safefree(tmps); + utf8 = (char*)bytes_to_utf8((U8*)tmps, &len); + sv_insert(lsv, lvoff, lvlen, utf8, len); + Safefree(utf8); } else { sv_insert(lsv, lvoff, lvlen, tmps, len); @@ -1938,13 +2003,11 @@ Perl_magic_settaint(pTHX_ SV *sv, MAGIC *mg) { dVAR; PERL_UNUSED_ARG(sv); - /* update taint status unless we're restoring at scope exit */ - if (PL_localizing != 2) { - if (PL_tainted) - mg->mg_len |= 1; - else - mg->mg_len &= ~1; - } + /* update taint status */ + if (PL_tainted) + mg->mg_len |= 1; + else + mg->mg_len &= ~1; return 0; } @@ -1987,7 +2050,7 @@ Perl_magic_getdefelem(pTHX_ SV *sv, MAGIC *mg) if ((I32)LvTARGOFF(sv) <= AvFILL(av)) targ = AvARRAY(av)[LvTARGOFF(sv)]; } - if (targ && targ != &PL_sv_undef) { + if (targ && (targ != &PL_sv_undef)) { /* somebody else defined it for us */ SvREFCNT_dec(LvTARG(sv)); LvTARG(sv) = SvREFCNT_inc_simple_NN(targ); @@ -2031,7 +2094,7 @@ Perl_vivify_defelem(pTHX_ SV *sv) if (he) value = HeVAL(he); if (!value || value == &PL_sv_undef) - Perl_croak(aTHX_ PL_no_helem_sv, mg->mg_obj); + Perl_croak(aTHX_ PL_no_helem_sv, SVfARG(mg->mg_obj)); } else { AV* const av = (AV*)LvTARG(sv); @@ -2072,6 +2135,7 @@ Perl_magic_setbm(pTHX_ SV *sv, MAGIC *mg) { PERL_UNUSED_ARG(mg); sv_unmagic(sv, PERL_MAGIC_bm); + SvTAIL_off(sv); SvVALID_off(sv); return 0; } @@ -2140,7 +2204,7 @@ Perl_magic_setutf8(pTHX_ SV *sv, MAGIC *mg) PERL_UNUSED_CONTEXT; PERL_UNUSED_ARG(sv); Safefree(mg->mg_ptr); /* The mg_ptr holds the pos cache. */ - mg->mg_ptr = 0; + mg->mg_ptr = NULL; mg->mg_len = -1; /* The mg_len holds the len cache. */ return 0; } @@ -2157,7 +2221,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) sv_setsv(PL_bodytarget, sv); break; case '\003': /* ^C */ - PL_minus_c = (bool)(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); + PL_minus_c = (bool)SvIV(sv); break; case '\004': /* ^D */ @@ -2166,25 +2230,25 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) PL_debug = get_debug_opts(&s, 0) | DEBUG_TOP_FLAG; DEBUG_x(dump_all()); #else - PL_debug = (SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)) | DEBUG_TOP_FLAG; + PL_debug = (SvIV(sv)) | DEBUG_TOP_FLAG; #endif break; case '\005': /* ^E */ if (*(mg->mg_ptr+1) == '\0') { #ifdef MACOS_TRADITIONAL - gMacPerl_OSErr = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + gMacPerl_OSErr = SvIV(sv); #else # ifdef VMS - set_vaxc_errno(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); + set_vaxc_errno(SvIV(sv)); # else # ifdef WIN32 SetLastError( SvIV(sv) ); # else # ifdef OS2 - os2_setsyserrno(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); + os2_setsyserrno(SvIV(sv)); # else /* will anyone ever use this? */ - SETERRNO(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv), 4); + SETERRNO(SvIV(sv), 4); # endif # endif # endif @@ -2202,10 +2266,10 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) } break; case '\006': /* ^F */ - PL_maxsysfd = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + PL_maxsysfd = SvIV(sv); break; case '\010': /* ^H */ - PL_hints = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + PL_hints = SvIV(sv); break; case '\011': /* ^I */ /* NOT \t in EBCDIC */ Safefree(PL_inplace); @@ -2221,14 +2285,37 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) } } else if (strEQ(mg->mg_ptr, "\017PEN")) { - if (!PL_compiling.cop_io) - PL_compiling.cop_io = newSVsv(sv); - else - sv_setsv(PL_compiling.cop_io,sv); + STRLEN len; + const char *const start = SvPV(sv, len); + const char *out = (const char*)memchr(start, '\0', len); + SV *tmp; + struct refcounted_he *tmp_he; + + + PL_compiling.cop_hints |= HINT_LEXICAL_IO_IN | HINT_LEXICAL_IO_OUT; + PL_hints + |= HINT_LOCALIZE_HH | HINT_LEXICAL_IO_IN | HINT_LEXICAL_IO_OUT; + + /* Opening for input is more common than opening for output, so + ensure that hints for input are sooner on linked list. */ + tmp = sv_2mortal(out ? newSVpvn(out + 1, start + len - out - 1) + : newSVpvs("")); + SvFLAGS(tmp) |= SvUTF8(sv); + + tmp_he + = Perl_refcounted_he_new(aTHX_ PL_compiling.cop_hints_hash, + sv_2mortal(newSVpvs("open>")), tmp); + + /* The UTF-8 setting is carried over */ + sv_setpvn(tmp, start, out ? (STRLEN)(out - start) : len); + + PL_compiling.cop_hints_hash + = Perl_refcounted_he_new(aTHX_ tmp_he, + sv_2mortal(newSVpvs("open<")), tmp); } break; case '\020': /* ^P */ - PL_perldb = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + PL_perldb = SvIV(sv); if (PL_perldb && !PL_DBsingle) init_debugger(); break; @@ -2236,7 +2323,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) #ifdef BIG_TIME PL_basetime = (Time_t)(SvNOK(sv) ? SvNVX(sv) : sv_2nv(sv)); #else - PL_basetime = (Time_t)(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); + PL_basetime = (Time_t)SvIV(sv); #endif break; case '\025': /* ^UTF8CACHE */ @@ -2247,7 +2334,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) case '\027': /* ^W & $^WARNING_BITS */ if (*(mg->mg_ptr+1) == '\0') { if ( ! (PL_dowarn & G_WARN_ALL_MASK)) { - i = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + i = SvIV(sv); PL_dowarn = (PL_dowarn & ~G_WARN_ON) | (i ? G_WARN_ON : G_WARN_OFF) ; } @@ -2268,17 +2355,27 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) accumulate |= ptr[i] ; any_fatals |= (ptr[i] & 0xAA) ; } - if (!accumulate) - PL_compiling.cop_warnings = pWARN_NONE; - else if (isWARN_on(sv, WARN_ALL) && !any_fatals) { + 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 ; } else { - if (specialWARN(PL_compiling.cop_warnings)) - PL_compiling.cop_warnings = newSVsv(sv) ; - else - sv_setsv(PL_compiling.cop_warnings, sv); + STRLEN len; + const char *const p = SvPV_const(sv, len); + + PL_compiling.cop_warnings + = Perl_new_warnings_bitfield(aTHX_ PL_compiling.cop_warnings, + p, len); + if (isWARN_on(PL_compiling.cop_warnings, WARN_ONCE)) PL_dowarn |= G_WARN_ONCE ; } @@ -2306,22 +2403,22 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) IoFMT_GV(GvIOp(PL_defoutgv)) = gv_fetchsv(sv, GV_ADD, SVt_PVIO); break; case '=': - IoPAGE_LEN(GvIOp(PL_defoutgv)) = (SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); + IoPAGE_LEN(GvIOp(PL_defoutgv)) = (SvIV(sv)); break; case '-': - IoLINES_LEFT(GvIOp(PL_defoutgv)) = (SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); + IoLINES_LEFT(GvIOp(PL_defoutgv)) = (SvIV(sv)); if (IoLINES_LEFT(GvIOp(PL_defoutgv)) < 0L) IoLINES_LEFT(GvIOp(PL_defoutgv)) = 0L; break; case '%': - IoPAGE(GvIOp(PL_defoutgv)) = (SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); + IoPAGE(GvIOp(PL_defoutgv)) = (SvIV(sv)); break; case '|': { IO * const io = GvIOp(PL_defoutgv); if(!io) break; - if ((SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)) == 0) + if ((SvIV(sv)) == 0) IoFLAGS(io) &= ~IOf_FLUSH; else { if (!(IoFLAGS(io) & IOf_FLUSH)) { @@ -2358,7 +2455,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) } break; case '[': - PL_compiling.cop_arybase = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + CopARYBASE_set(&PL_compiling, SvIV(sv)); break; case '?': #ifdef COMPLEX_STATUS @@ -2373,7 +2470,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) STATUS_NATIVE_CHILD_SET((U32)SvIV(sv)); else #endif - STATUS_UNIX_EXIT_SET(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); + STATUS_UNIX_EXIT_SET(SvIV(sv)); break; case '!': { @@ -2387,7 +2484,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) } break; case '<': - PL_uid = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + PL_uid = SvIV(sv); if (PL_delaymagic) { PL_delaymagic |= DM_RUID; break; /* don't do magic till later */ @@ -2419,7 +2516,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) PL_tainting |= (PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid)); break; case '>': - PL_euid = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + PL_euid = SvIV(sv); if (PL_delaymagic) { PL_delaymagic |= DM_EUID; break; /* don't do magic till later */ @@ -2446,7 +2543,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) PL_tainting |= (PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid)); break; case '(': - PL_gid = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + PL_gid = SvIV(sv); if (PL_delaymagic) { PL_delaymagic |= DM_RGID; break; /* don't do magic till later */ @@ -2496,11 +2593,10 @@ 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 = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv); + PL_egid = SvIV(sv); #endif /* HAS_SETGROUPS */ if (PL_delaymagic) { PL_delaymagic |= DM_EGID; @@ -2556,15 +2652,14 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) setproctitle("%s", s); # endif } -#endif -#if defined(__hpux) && defined(PSTAT_SETCMD) +#elif defined(__hpux) && defined(PSTAT_SETCMD) if (PL_origalen != 1) { union pstun un; s = SvPV_const(sv, len); un.pst_command = (char *)s; pstat(PSTAT_SETCMD, un, len, 0, 0); } -#endif +#else if (PL_origalen > 1) { /* PL_origalen is set in perl_parse(). */ s = SvPV_force(sv,len); @@ -2575,20 +2670,26 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg) } else { /* Shorter than original, will be padded. */ +#ifdef PERL_DARWIN + /* Special case for Mac OS X: see [perl #38868] */ + const int pad = 0; +#else + /* Is the space counterintuitive? Yes. + * (You were expecting \0?) + * Does it work? Seems to. (In Linux 2.4.20 at least.) + * --jhi */ + const int pad = ' '; +#endif Copy(s, PL_origargv[0], len, char); PL_origargv[0][len] = 0; memset(PL_origargv[0] + len + 1, - /* Is the space counterintuitive? Yes. - * (You were expecting \0?) - * Does it work? Seems to. (In Linux 2.4.20 at least.) - * --jhi */ - (int)' ', - PL_origalen - len - 1); + pad, PL_origalen - len - 1); } PL_origargv[0][PL_origalen-1] = 0; for (i = 1; i < PL_origargc; i++) PL_origargv[i] = 0; } +#endif UNLOCK_DOLLARZERO_MUTEX; break; #endif @@ -2718,7 +2819,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); @@ -2793,10 +2894,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 ); } } } @@ -2838,6 +2939,62 @@ S_unwind_handler_stack(pTHX_ const void *p) } /* +=for apidoc magic_sethint + +Triggered by a store to %^H, records the key/value pair to +C. It is assumed that hints aren't storing +anything that would need a deep copy. Maybe we should warn if we find a +reference. + +=cut +*/ +int +Perl_magic_sethint(pTHX_ SV *sv, MAGIC *mg) +{ + dVAR; + assert(mg->mg_len == HEf_SVKEY); + + /* mg->mg_obj isn't being used. If needed, it would be possible to store + an alternative leaf in there, with PL_compiling.cop_hints being used if + it's NULL. If needed for threads, the alternative could lock a mutex, + or take other more complex action. */ + + /* Something changed in %^H, so it will need to be restored on scope exit. + Doing this here saves a lot of doing it manually in perl code (and + forgetting to do it, and consequent subtle errors. */ + PL_hints |= HINT_LOCALIZE_HH; + PL_compiling.cop_hints_hash + = Perl_refcounted_he_new(aTHX_ PL_compiling.cop_hints_hash, + (SV *)mg->mg_ptr, sv); + return 0; +} + +/* +=for apidoc magic_sethint + +Triggered by a delete from %^H, records the key to +C. + +=cut +*/ +int +Perl_magic_clearhint(pTHX_ SV *sv, MAGIC *mg) +{ + dVAR; + PERL_UNUSED_ARG(sv); + + assert(mg->mg_len == HEf_SVKEY); + + PERL_UNUSED_ARG(sv); + + PL_hints |= HINT_LOCALIZE_HH; + PL_compiling.cop_hints_hash + = Perl_refcounted_he_new(aTHX_ PL_compiling.cop_hints_hash, + (SV *)mg->mg_ptr, &PL_sv_placeholder); + return 0; +} + +/* * Local variables: * c-indentation-style: bsd * c-basic-offset: 4