This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
compare stat results on a file that isn't touched elsewhere
[perl5.git] / mg.c
diff --git a/mg.c b/mg.c
index 4a8d767..8b283d9 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -57,6 +57,10 @@ tie.
 #  include <sys/pstat.h>
 #endif
 
+#ifdef HAS_PRCTL_SET_NAME
+#  include <sys/prctl.h>
+#endif
+
 #if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
 Signal_t Perl_csighandler(int sig, siginfo_t *, void *);
 #else
@@ -174,6 +178,7 @@ S_is_container_magic(const MAGIC *mg)
     case PERL_MAGIC_arylen_p:
     case PERL_MAGIC_rhash:
     case PERL_MAGIC_symtab:
+    case PERL_MAGIC_tied: /* treat as value, so 'local @tied' isn't tied */
        return 0;
     default:
        return 1;
@@ -222,7 +227,7 @@ Perl_mg_get(pTHX_ SV *sv)
        MAGIC * const nextmg = mg->mg_moremagic;        /* it may delete itself */
 
        if (!(mg->mg_flags & MGf_GSKIP) && vtbl && vtbl->svt_get) {
-           CALL_FPTR(vtbl->svt_get)(aTHX_ sv, mg);
+           vtbl->svt_get(aTHX_ sv, mg);
 
            /* guard against magic having been deleted - eg FETCH calling
             * untie */
@@ -297,7 +302,7 @@ Perl_mg_set(pTHX_ SV *sv)
        if (PL_localizing == 2 && !S_is_container_magic(mg))
            continue;
        if (vtbl && vtbl->svt_set)
-           CALL_FPTR(vtbl->svt_set)(aTHX_ sv, mg);
+           vtbl->svt_set(aTHX_ sv, mg);
     }
 
     restore_magic(INT2PTR(void*, (IV)mgs_ix));
@@ -327,7 +332,7 @@ Perl_mg_length(pTHX_ SV *sv)
             const I32 mgs_ix = SSNEW(sizeof(MGS));
            save_magic(mgs_ix, sv);
            /* omit MGf_GSKIP -- not changed here */
-           len = CALL_FPTR(vtbl->svt_len)(aTHX_ sv, mg);
+           len = vtbl->svt_len(aTHX_ sv, mg);
            restore_magic(INT2PTR(void*, (IV)mgs_ix));
            return len;
        }
@@ -359,7 +364,7 @@ Perl_mg_size(pTHX_ SV *sv)
             I32 len;
            save_magic(mgs_ix, sv);
            /* omit MGf_GSKIP -- not changed here */
-           len = CALL_FPTR(vtbl->svt_len)(aTHX_ sv, mg);
+           len = vtbl->svt_len(aTHX_ sv, mg);
            restore_magic(INT2PTR(void*, (IV)mgs_ix));
            return len;
        }
@@ -403,7 +408,7 @@ Perl_mg_clear(pTHX_ SV *sv)
        nextmg = mg->mg_moremagic; /* it may delete itself */
 
        if (vtbl && vtbl->svt_clear)
-           CALL_FPTR(vtbl->svt_clear)(aTHX_ sv, mg);
+           vtbl->svt_clear(aTHX_ sv, mg);
     }
 
     restore_magic(INT2PTR(void*, (IV)mgs_ix));
@@ -451,7 +456,7 @@ Perl_mg_copy(pTHX_ SV *sv, SV *nsv, const char *key, I32 klen)
     for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
         const MGVTBL* const vtbl = mg->mg_virtual;
        if ((mg->mg_flags & MGf_COPY) && vtbl->svt_copy){
-           count += CALL_FPTR(vtbl->svt_copy)(aTHX_ sv, mg, nsv, key, klen);
+           count += vtbl->svt_copy(aTHX_ sv, mg, nsv, key, klen);
        }
        else {
            const char type = mg->mg_type;
@@ -498,7 +503,7 @@ Perl_mg_localize(pTHX_ SV *sv, SV *nsv, bool setmagic)
            continue;
                
        if ((mg->mg_flags & MGf_LOCAL) && vtbl->svt_local)
-           (void)CALL_FPTR(vtbl->svt_local)(aTHX_ nsv, mg);
+           (void)vtbl->svt_local(aTHX_ nsv, mg);
        else
            sv_magicext(nsv, mg->mg_obj, mg->mg_type, vtbl,
                            mg->mg_ptr, mg->mg_len);
@@ -537,7 +542,7 @@ Perl_mg_free(pTHX_ SV *sv)
         const MGVTBL* const vtbl = mg->mg_virtual;
        moremagic = mg->mg_moremagic;
        if (vtbl && vtbl->svt_free)
-           CALL_FPTR(vtbl->svt_free)(aTHX_ sv, mg);
+           vtbl->svt_free(aTHX_ sv, mg);
        if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
            if (mg->mg_len > 0 || mg->mg_type == PERL_MAGIC_utf8)
                Safefree(mg->mg_ptr);
@@ -630,7 +635,7 @@ Perl_magic_regdatum_set(pTHX_ SV *sv, MAGIC *mg)
     PERL_ARGS_ASSERT_MAGIC_REGDATUM_SET;
     PERL_UNUSED_ARG(sv);
     PERL_UNUSED_ARG(mg);
-    Perl_croak(aTHX_ "%s", PL_no_modify);
+    Perl_croak_no_modify(aTHX);
     NORETURN_FUNCTION_END;
 }
 
@@ -757,7 +762,7 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
     register I32 paren;
-    register char *s = NULL;
+    register const char *s = NULL;
     register REGEXP *rx;
     const char * const remaining = mg->mg_ptr + 1;
     const char nextchar = *remaining;
@@ -1380,6 +1385,7 @@ Perl_despatch_signals(pTHX)
     PL_sig_pending = 0;
     for (sig = 1; sig < SIG_SIZE; sig++) {
        if (PL_psig_pend[sig]) {
+           dSAVE_ERRNO;
            PERL_BLOCKSIG_ADD(set, sig);
            PL_psig_pend[sig] = 0;
            PERL_BLOCKSIG_BLOCK(set);
@@ -1389,6 +1395,7 @@ Perl_despatch_signals(pTHX)
            (*PL_sighandlerp)(sig);
 #endif
            PERL_BLOCKSIG_UNBLOCK(set);
+           RESTORE_ERRNO;
        }
     }
 }
@@ -1551,7 +1558,7 @@ Perl_magic_setisa(pTHX_ SV *sv, MAGIC *mg)
     PERL_UNUSED_ARG(sv);
 
     /* Skip _isaelem because _isa will handle it shortly */
-    if (PL_delaymagic & DM_ARRAY && mg->mg_type == PERL_MAGIC_isaelem)
+    if (PL_delaymagic & DM_ARRAY_ISA && mg->mg_type == PERL_MAGIC_isaelem)
        return 0;
 
     return magic_clearisa(NULL, mg);
@@ -1638,55 +1645,109 @@ Perl_magic_setnkeys(pTHX_ SV *sv, MAGIC *mg)
     return 0;
 }
 
-/* caller is responsible for stack switching/cleanup */
-STATIC int
-S_magic_methcall(pTHX_ SV *sv, const MAGIC *mg, const char *meth, I32 flags, int n, SV *val)
+/*
+=for apidoc magic_methcall
+
+Invoke a magic method (like FETCH).
+
+* sv and mg are the tied thinggy and the tie magic;
+* meth is the name of the method to call;
+* argc is the number of args (in addition to $self) to pass to the method;
+       the args themselves are any values following the argc argument.
+* flags:
+    G_DISCARD:     invoke method with G_DISCARD flag and don't return a value
+    G_UNDEF_FILL:  fill the stack with argc pointers to PL_sv_undef.
+
+Returns the SV (if any) returned by the method, or NULL on failure.
+
+
+=cut
+*/
+
+SV*
+Perl_magic_methcall(pTHX_ SV *sv, const MAGIC *mg, const char *meth, U32 flags,
+                   U32 argc, ...)
 {
     dVAR;
     dSP;
+    SV* ret = NULL;
 
     PERL_ARGS_ASSERT_MAGIC_METHCALL;
 
+    ENTER;
+    PUSHSTACKi(PERLSI_MAGIC);
     PUSHMARK(SP);
-    EXTEND(SP, n);
+
+    EXTEND(SP, argc+1);
     PUSHs(SvTIED_obj(sv, mg));
-    if (n > 1) {
-       if (mg->mg_ptr) {
-           if (mg->mg_len >= 0)
-               mPUSHp(mg->mg_ptr, mg->mg_len);
-           else if (mg->mg_len == HEf_SVKEY)
-               PUSHs(MUTABLE_SV(mg->mg_ptr));
-       }
-       else if (mg->mg_type == PERL_MAGIC_tiedelem) {
-           mPUSHi(mg->mg_len);
+    if (flags & G_UNDEF_FILL) {
+       while (argc--) {
+           PUSHs(&PL_sv_undef);
        }
-    }
-    if (n > 2) {
-       PUSHs(val);
+    } else if (argc > 0) {
+       va_list args;
+       va_start(args, argc);
+
+       do {
+           SV *const sv = va_arg(args, SV *);
+           PUSHs(sv);
+       } while (--argc);
+
+       va_end(args);
     }
     PUTBACK;
+    if (flags & G_DISCARD) {
+       call_method(meth, G_SCALAR|G_DISCARD);
+    }
+    else {
+       if (call_method(meth, G_SCALAR))
+           ret = *PL_stack_sp--;
+    }
+    POPSTACK;
+    LEAVE;
+    return ret;
+}
+
+
+/* wrapper for magic_methcall that creates the first arg */
+
+STATIC SV*
+S_magic_methcall1(pTHX_ SV *sv, const MAGIC *mg, const char *meth, U32 flags,
+    int n, SV *val)
+{
+    dVAR;
+    SV* arg1 = NULL;
+
+    PERL_ARGS_ASSERT_MAGIC_METHCALL1;
 
-    return call_method(meth, flags);
+    if (mg->mg_ptr) {
+       if (mg->mg_len >= 0) {
+           arg1 = newSVpvn_flags(mg->mg_ptr, mg->mg_len, SVs_TEMP);
+       }
+       else if (mg->mg_len == HEf_SVKEY)
+           arg1 = MUTABLE_SV(mg->mg_ptr);
+    }
+    else if (mg->mg_type == PERL_MAGIC_tiedelem) {
+       arg1 = newSViv((IV)(mg->mg_len));
+       sv_2mortal(arg1);
+    }
+    if (!arg1) {
+       return Perl_magic_methcall(aTHX_ sv, mg, meth, flags, n - 1, val);
+    }
+    return Perl_magic_methcall(aTHX_ sv, mg, meth, flags, n, arg1, val);
 }
 
 STATIC int
 S_magic_methpack(pTHX_ SV *sv, const MAGIC *mg, const char *meth)
 {
-    dVAR; dSP;
+    dVAR;
+    SV* ret;
 
     PERL_ARGS_ASSERT_MAGIC_METHPACK;
 
-    ENTER;
-    SAVETMPS;
-    PUSHSTACKi(PERLSI_MAGIC);
-
-    if (magic_methcall(sv, mg, meth, G_SCALAR, 2, NULL)) {
-       sv_setsv(sv, *PL_stack_sp--);
-    }
-
-    POPSTACK;
-    FREETMPS;
-    LEAVE;
+    ret = magic_methcall1(sv, mg, meth, 0, 1, NULL);
+    if (ret)
+       sv_setsv(sv, ret);
     return 0;
 }
 
@@ -1704,7 +1765,7 @@ Perl_magic_getpack(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_magic_setpack(pTHX_ SV *sv, MAGIC *mg)
 {
-    dVAR; dSP;
+    dVAR;
     MAGIC *tmg;
     SV    *val;
 
@@ -1729,11 +1790,7 @@ Perl_magic_setpack(pTHX_ SV *sv, MAGIC *mg)
     else
        val = sv;
 
-    ENTER;
-    PUSHSTACKi(PERLSI_MAGIC);
-    magic_methcall(sv, mg, "STORE", G_SCALAR|G_DISCARD, 3, val);
-    POPSTACK;
-    LEAVE;
+    magic_methcall1(sv, mg, "STORE", G_DISCARD, 2, val);
     return 0;
 }
 
@@ -1749,69 +1806,44 @@ Perl_magic_clearpack(pTHX_ SV *sv, MAGIC *mg)
 U32
 Perl_magic_sizepack(pTHX_ SV *sv, MAGIC *mg)
 {
-    dVAR; dSP;
+    dVAR;
     I32 retval = 0;
+    SV* retsv;
 
     PERL_ARGS_ASSERT_MAGIC_SIZEPACK;
 
-    ENTER;
-    SAVETMPS;
-    PUSHSTACKi(PERLSI_MAGIC);
-    if (magic_methcall(sv, mg, "FETCHSIZE", G_SCALAR, 2, NULL)) {
-       sv = *PL_stack_sp--;
-       retval = SvIV(sv)-1;
+    retsv = magic_methcall1(sv, mg, "FETCHSIZE", 0, 1, NULL);
+    if (retsv) {
+       retval = SvIV(retsv)-1;
        if (retval < -1)
            Perl_croak(aTHX_ "FETCHSIZE returned a negative value");
     }
-    POPSTACK;
-    FREETMPS;
-    LEAVE;
     return (U32) retval;
 }
 
 int
 Perl_magic_wipepack(pTHX_ SV *sv, MAGIC *mg)
 {
-    dVAR; dSP;
+    dVAR;
 
     PERL_ARGS_ASSERT_MAGIC_WIPEPACK;
 
-    ENTER;
-    PUSHSTACKi(PERLSI_MAGIC);
-    PUSHMARK(SP);
-    XPUSHs(SvTIED_obj(sv, mg));
-    PUTBACK;
-    call_method("CLEAR", G_SCALAR|G_DISCARD);
-    POPSTACK;
-    LEAVE;
-
+    Perl_magic_methcall(aTHX_ sv, mg, "CLEAR", G_DISCARD, 0);
     return 0;
 }
 
 int
 Perl_magic_nextpack(pTHX_ SV *sv, MAGIC *mg, SV *key)
 {
-    dVAR; dSP;
-    const char * const meth = SvOK(key) ? "NEXTKEY" : "FIRSTKEY";
+    dVAR;
+    SV* ret;
 
     PERL_ARGS_ASSERT_MAGIC_NEXTPACK;
 
-    ENTER;
-    SAVETMPS;
-    PUSHSTACKi(PERLSI_MAGIC);
-    PUSHMARK(SP);
-    EXTEND(SP, 2);
-    PUSHs(SvTIED_obj(sv, mg));
-    if (SvOK(key))
-       PUSHs(key);
-    PUTBACK;
-
-    if (call_method(meth, G_SCALAR))
-       sv_setsv(key, *PL_stack_sp--);
-
-    POPSTACK;
-    FREETMPS;
-    LEAVE;
+    ret = SvOK(key) ? Perl_magic_methcall(aTHX_ sv, mg, "NEXTKEY", 0, 1, key)
+       : Perl_magic_methcall(aTHX_ sv, mg, "FIRSTKEY", 0, 0);
+    if (ret)
+       sv_setsv(key,ret);
     return 0;
 }
 
@@ -1826,7 +1858,7 @@ Perl_magic_existspack(pTHX_ SV *sv, const MAGIC *mg)
 SV *
 Perl_magic_scalarpack(pTHX_ HV *hv, MAGIC *mg)
 {
-    dVAR; dSP;
+    dVAR;
     SV *retval;
     SV * const tied = SvTIED_obj(MUTABLE_SV(hv), mg);
     HV * const pkg = SvSTASH((const SV *)SvRV(tied));
@@ -1846,19 +1878,9 @@ Perl_magic_scalarpack(pTHX_ HV *hv, MAGIC *mg)
     }
    
     /* there is a SCALAR method that we can call */
-    ENTER;
-    PUSHSTACKi(PERLSI_MAGIC);
-    PUSHMARK(SP);
-    EXTEND(SP, 1);
-    PUSHs(tied);
-    PUTBACK;
-
-    if (call_method("SCALAR", G_SCALAR))
-        retval = *PL_stack_sp--; 
-    else
+    retval = Perl_magic_methcall(aTHX_ MUTABLE_SV(hv), mg, "SCALAR", 0, 0);
+    if (!retval)
        retval = &PL_sv_undef;
-    POPSTACK;
-    LEAVE;
     return retval;
 }
 
@@ -2233,7 +2255,8 @@ int
 Perl_magic_killbackrefs(pTHX_ SV *sv, MAGIC *mg)
 {
     PERL_ARGS_ASSERT_MAGIC_KILLBACKREFS;
-    return Perl_sv_kill_backrefs(aTHX_ sv, MUTABLE_AV(mg->mg_obj));
+    Perl_sv_kill_backrefs(aTHX_ sv, MUTABLE_AV(mg->mg_obj));
+    return 0;
 }
 
 int
@@ -2346,15 +2369,15 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
       setparen:
        if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
             CALLREG_NUMBUF_STORE((REGEXP * const)rx,paren,sv);
-            break;
        } else {
             /* Croak with a READONLY error when a numbered match var is
              * set without a previous pattern match. Unless it's C<local $1>
              */
             if (!PL_localizing) {
-                Perl_croak(aTHX_ "%s", PL_no_modify);
+                Perl_croak_no_modify(aTHX);
             }
         }
+        break;
     case '\001':       /* ^A */
        sv_setsv(PL_bodytarget, sv);
        break;
@@ -2453,6 +2476,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
       } else if (strEQ(remaining, "OSTMATCH")) { /* $^POSTMATCH */
           goto do_postmatch;
       }
+      break;
     case '\024':       /* ^T */
 #ifdef BIG_TIME
        PL_basetime = (Time_t)(SvNOK(sv) ? SvNVX(sv) : sv_2nv(sv));
@@ -2823,6 +2847,13 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
            PL_origargv[0][PL_origalen-1] = 0;
            for (i = 1; i < PL_origargc; i++)
                PL_origargv[i] = 0;
+#ifdef HAS_PRCTL_SET_NAME
+           /* Set the legacy process name in addition to the POSIX name on Linux */
+           if (prctl(PR_SET_NAME, (unsigned long)s, 0, 0, 0) != 0) {
+               /* diag_listed_as: SKIPME */
+               Perl_croak(aTHX_ "Can't set $0 with prctl(): %s", Strerror(errno));
+           }
+#endif
        }
 #endif
        UNLOCK_DOLLARZERO_MUTEX;
@@ -2977,7 +3008,7 @@ Perl_sighandler(int sig)
        (void)rsignal(sig, PL_csighandlerp);
 #endif
 #endif /* !PERL_MICRO */
-       Perl_die(aTHX_ NULL);
+       die_sv(ERRSV);
     }
 cleanup:
     if (flags & 1)
@@ -3044,13 +3075,12 @@ S_restore_magic(pTHX_ const void *p)
      */
     if (PL_savestack_ix == mgs->mgs_ss_ix)
     {
-       I32 popval = SSPOPINT;
+       UV popval = SSPOPUV;
         assert(popval == SAVEt_DESTRUCTOR_X);
         PL_savestack_ix -= 2;
-       popval = SSPOPINT;
-        assert(popval == SAVEt_ALLOC);
-       popval = SSPOPINT;
-        PL_savestack_ix -= popval;
+       popval = SSPOPUV;
+        assert((popval & SAVE_MASK) == SAVEt_ALLOC);
+        PL_savestack_ix -= popval >> SAVE_TIGHT_SHIFT;
     }
 
 }