This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Skip dist/ExtUtils-Install/t/InstallWithMM.t when cross-compiling.
[perl5.git] / doio.c
diff --git a/doio.c b/doio.c
index e8eafdc..39cbf6d 100644 (file)
--- a/doio.c
+++ b/doio.c
@@ -61,7 +61,7 @@
 #include <signal.h>
 
 bool
-Perl_do_openn(pTHX_ GV *gv, register const char *oname, I32 len, int as_raw,
+Perl_do_openn(pTHX_ GV *gv, const char *oname, I32 len, int as_raw,
              int rawmode, int rawperm, PerlIO *supplied_fp, SV **svp,
              I32 num_svs)
 {
@@ -206,6 +206,8 @@ Perl_do_openn(pTHX_ GV *gv, register const char *oname, I32 len, int as_raw,
            *--tend = '\0';
 
        if (num_svs) {
+            const char *p;
+            STRLEN nlen = 0;
            /* New style explicit name, type is just mode and layer info */
 #ifdef USE_STDIO
            if (SvROK(*svp) && !strchr(oname,'&')) {
@@ -216,8 +218,13 @@ Perl_do_openn(pTHX_ GV *gv, register const char *oname, I32 len, int as_raw,
                goto say_false;
            }
 #endif /* USE_STDIO */
-           name = (SvOK(*svp) || SvGMAGICAL(*svp)) ?
-                       savesvpv (*svp) : savepvs ("");
+            p = (SvOK(*svp) || SvGMAGICAL(*svp)) ? SvPV(*svp, nlen) : NULL;
+
+           if (p && !IS_SAFE_PATHNAME(p, nlen, "open"))
+                goto say_false;
+
+           name = p ? savepvn(p, nlen) : savepvs("");
+
            SAVEFREEPV(name);
        }
        else {
@@ -706,7 +713,7 @@ say_false:
 }
 
 PerlIO *
-Perl_nextargv(pTHX_ register GV *gv)
+Perl_nextargv(pTHX_ GV *gv)
 {
     dVAR;
     SV *sv;
@@ -806,7 +813,7 @@ Perl_nextargv(pTHX_ register GV *gv)
                    }
 #endif
 #ifdef HAS_RENAME
-#if !defined(DOSISH) && !defined(__CYGWIN__) && !defined(EPOC)
+#if !defined(DOSISH) && !defined(__CYGWIN__)
                    if (PerlLIO_rename(PL_oldname,SvPVX_const(sv)) < 0) {
                        Perl_ck_warner_d(aTHX_ packWARN(WARN_INPLACE),
                                         "Can't rename %s to %"SVf": %s, skipping file",
@@ -908,7 +915,7 @@ Perl_nextargv(pTHX_ register GV *gv)
        {
            GV * const oldout = MUTABLE_GV(av_pop(PL_argvout_stack));
            setdefout(oldout);
-           SvREFCNT_dec(oldout);
+           SvREFCNT_dec_NN(oldout);
            return NULL;
        }
        setdefout(gv_fetchpvs("STDOUT", GV_ADD|GV_NOTQUAL, SVt_PVIO));
@@ -1045,10 +1052,6 @@ Perl_do_tell(pTHX_ GV *gv)
     PERL_ARGS_ASSERT_DO_TELL;
 
     if (io && (fp = IoIFP(io))) {
-#ifdef ULTRIX_STDIO_BOTCH
-       if (PerlIO_eof(fp))
-           (void)PerlIO_seek(fp, 0L, 2);       /* ultrix 1.2 workaround */
-#endif
        return PerlIO_tell(fp);
     }
     report_evil_fh(gv);
@@ -1064,10 +1067,6 @@ Perl_do_seek(pTHX_ GV *gv, Off_t pos, int whence)
     PerlIO *fp;
 
     if (io && (fp = IoIFP(io))) {
-#ifdef ULTRIX_STDIO_BOTCH
-       if (PerlIO_eof(fp))
-           (void)PerlIO_seek(fp, 0L, 2);       /* ultrix 1.2 workaround */
-#endif
        return PerlIO_seek(fp, pos, whence) >= 0;
     }
     report_evil_fh(gv);
@@ -1199,7 +1198,7 @@ my_chsize(int fd, Off_t length)
 #endif /* !HAS_TRUNCATE && !HAS_CHSIZE */
 
 bool
-Perl_do_print(pTHX_ register SV *sv, PerlIO *fp)
+Perl_do_print(pTHX_ SV *sv, PerlIO *fp)
 {
     dVAR;
 
@@ -1333,17 +1332,20 @@ I32
 Perl_my_lstat_flags(pTHX_ const U32 flags)
 {
     dVAR;
-    static const char no_prev_lstat[] = "The stat preceding -l _ wasn't an lstat";
+    static const char* const no_prev_lstat = "The stat preceding -l _ wasn't an lstat";
     dSP;
     const char *file;
+    SV* const sv = TOPs;
+    bool isio = FALSE;
     if (PL_op->op_flags & OPf_REF) {
        if (cGVOP_gv == PL_defgv) {
            if (PL_laststype != OP_LSTAT)
-               Perl_croak(aTHX_ no_prev_lstat);
+               Perl_croak(aTHX_ "%s", no_prev_lstat);
            return PL_laststatval;
        }
        PL_laststatval = -1;
        if (ckWARN(WARN_IO)) {
+           /* diag_listed_as: Use of -l on filehandle%s */
            Perl_warner(aTHX_ packWARN(WARN_IO),
                             "Use of -l on filehandle %"HEKf,
                              HEKfARG(GvENAME_HEK(cGVOP_gv)));
@@ -1353,13 +1355,30 @@ Perl_my_lstat_flags(pTHX_ const U32 flags)
     if ((PL_op->op_private & (OPpFT_STACKED|OPpFT_AFTER_t))
             == OPpFT_STACKED) {
       if (PL_laststype != OP_LSTAT)
-       Perl_croak(aTHX_ no_prev_lstat);
+       Perl_croak(aTHX_ "%s", no_prev_lstat);
       return PL_laststatval;
-    } 
+    }
 
     PL_laststype = OP_LSTAT;
     PL_statgv = NULL;
-    file = SvPV_flags_const_nolen(TOPs, flags);
+    if ( (  (SvROK(sv) && (  isGV_with_GP(SvRV(sv))
+                          || (isio = SvTYPE(SvRV(sv)) == SVt_PVIO)  )
+            )
+         || isGV_with_GP(sv)
+         )
+      && ckWARN(WARN_IO)) {
+        if (isio)
+           /* diag_listed_as: Use of -l on filehandle%s */
+            Perl_warner(aTHX_ packWARN(WARN_IO),
+                             "Use of -l on filehandle");
+        else
+           /* diag_listed_as: Use of -l on filehandle%s */
+            Perl_warner(aTHX_ packWARN(WARN_IO),
+                             "Use of -l on filehandle %"HEKf,
+                              GvENAME_HEK((const GV *)
+                                          (SvROK(sv) ? SvRV(sv) : sv)));
+    }
+    file = SvPV_flags_const_nolen(sv, flags);
     sv_setpv(PL_statname,file);
     PL_laststatval = PerlLIO_lstat(file,&PL_statcache);
     if (PL_laststatval < 0 && ckWARN(WARN_NEWLINE) && strchr(file, '\n'))
@@ -1376,13 +1395,13 @@ S_exec_failed(pTHX_ const char *cmd, int fd, int do_report)
        Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't exec \"%s\": %s",
                    cmd, Strerror(e));
     if (do_report) {
-       PerlLIO_write(fd, (void*)&e, sizeof(int));
+       (void)PerlLIO_write(fd, (void*)&e, sizeof(int));
        PerlLIO_close(fd);
     }
 }
 
 bool
-Perl_do_aexec5(pTHX_ SV *really, register SV **mark, register SV **sp,
+Perl_do_aexec5(pTHX_ SV *really, SV **mark, SV **sp,
               int fd, int do_report)
 {
     dVAR;
@@ -1499,7 +1518,7 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
        goto doshell;
 
     s = cmd;
-    while (isALNUM(*s))
+    while (isWORDCHAR(*s))
        s++;    /* catch VAR=val gizmo */
     if (*s == '=')
        goto doshell;
@@ -1571,7 +1590,7 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
 #endif
 
 I32
-Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
+Perl_apply(pTHX_ I32 type, SV **mark, SV **sp)
 {
     dVAR;
     I32 val;
@@ -1584,6 +1603,8 @@ Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
 
     PERL_ARGS_ASSERT_APPLY;
 
+    PERL_UNUSED_VAR(what); /* may not be used depending on compile options */
+
     /* Doing this ahead of the switch statement preserves the old behaviour,
        where attempting to use kill as a taint test test would fail on
        platforms where kill was not defined.  */
@@ -1599,11 +1620,11 @@ Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
 
 #define APPLY_TAINT_PROPER() \
     STMT_START {                                                       \
-       if (PL_tainted) { TAINT_PROPER(what); }                         \
+       if (TAINT_get) { TAINT_PROPER(what); }                          \
     } STMT_END
 
     /* This is a first heuristic; it doesn't catch tainting magic. */
-    if (PL_tainting) {
+    if (TAINTING_get) {
        while (++mark <= sp) {
            if (SvTAINTED(*mark)) {
                TAINT;
@@ -1636,10 +1657,12 @@ Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
                    }
                }
                else {
-                   const char *name = SvPV_nomg_const_nolen(*mark);
+                   const char *name = SvPV_nomg_const(*mark, len);
                    APPLY_TAINT_PROPER();
-                   if (PerlLIO_chmod(name, val))
-                       tot--;
+                    if (!IS_SAFE_PATHNAME(name, len, "chmod") ||
+                        PerlLIO_chmod(name, val)) {
+                        tot--;
+                    }
                }
            }
        }
@@ -1670,10 +1693,12 @@ Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
                    }
                }
                else {
-                   const char *name = SvPV_nomg_const_nolen(*mark);
+                   const char *name = SvPV_nomg_const(*mark, len);
                    APPLY_TAINT_PROPER();
-                   if (PerlLIO_chown(name, val, val2))
+                    if (!IS_SAFE_PATHNAME(name, len, "chown") ||
+                        PerlLIO_chown(name, val, val2)) {
                        tot--;
+                    }
                }
            }
        }
@@ -1771,9 +1796,12 @@ nothing in the core.
        APPLY_TAINT_PROPER();
        tot = sp - mark;
        while (++mark <= sp) {
-           s = SvPV_nolen_const(*mark);
+           s = SvPV_const(*mark, len);
            APPLY_TAINT_PROPER();
-           if (PerlProc_geteuid() || PL_unsafe) {
+           if (!IS_SAFE_PATHNAME(s, len, "unlink")) {
+                tot--;
+            }
+           else if (PerlProc_geteuid() || PL_unsafe) {
                if (UNLINK(s))
                    tot--;
            }
@@ -1849,8 +1877,12 @@ nothing in the core.
                    }
                }
                else {
-                   const char * const name = SvPV_nomg_const_nolen(*mark);
+                   const char * const name = SvPV_nomg_const(*mark, len);
                    APPLY_TAINT_PROPER();
+                   if (!IS_SAFE_PATHNAME(name, len, "utime")) {
+                        tot--;
+                    }
+                    else
 #ifdef HAS_FUTIMES
                    if (utimes(name, (struct timeval *)utbufp))
 #else
@@ -1874,7 +1906,7 @@ nothing in the core.
 /* Do the permissions allow some operation?  Assumes statcache already set. */
 #ifndef VMS /* VMS' cando is in vms.c */
 bool
-Perl_cando(pTHX_ Mode_t mode, bool effective, register const Stat_t *statbufp)
+Perl_cando(pTHX_ Mode_t mode, bool effective, const Stat_t *statbufp)
 /* effective is a flag, true for EUID, or for checking if the effective gid
  *  is in the list of groups returned from getgroups().
  */
@@ -2155,6 +2187,7 @@ Perl_do_msgsnd(pTHX_ SV **mark, SV **sp)
     PERL_UNUSED_ARG(mark);
     /* diag_listed_as: msg%s not implemented */
     Perl_croak(aTHX_ "msgsnd not implemented");
+    return -1;
 #endif
 }
 
@@ -2186,10 +2219,8 @@ Perl_do_msgrcv(pTHX_ SV **mark, SV **sp)
     if (ret >= 0) {
        SvCUR_set(mstr, sizeof(long)+ret);
        *SvEND(mstr) = '\0';
-#ifndef INCOMPLETE_TAINTS
        /* who knows who has been playing with this message? */
        SvTAINTED_on(mstr);
-#endif
     }
     return ret;
 #else
@@ -2197,6 +2228,7 @@ Perl_do_msgrcv(pTHX_ SV **mark, SV **sp)
     PERL_UNUSED_ARG(mark);
     /* diag_listed_as: msg%s not implemented */
     Perl_croak(aTHX_ "msgrcv not implemented");
+    return -1;
 #endif
 }
 
@@ -2295,10 +2327,8 @@ Perl_do_shmio(pTHX_ I32 optype, SV **mark, SV **sp)
        SvCUR_set(mstr, msize);
        *SvEND(mstr) = '\0';
        SvSETMAGIC(mstr);
-#ifndef INCOMPLETE_TAINTS
        /* who knows who has been playing with this shared memory? */
        SvTAINTED_on(mstr);
-#endif
     }
     else {
        STRLEN len;
@@ -2313,6 +2343,7 @@ Perl_do_shmio(pTHX_ I32 optype, SV **mark, SV **sp)
 #else
     /* diag_listed_as: shm%s not implemented */
     Perl_croak(aTHX_ "shm I/O not implemented");
+    return -1;
 #endif
 }
 
@@ -2337,9 +2368,14 @@ Perl_start_glob (pTHX_ SV *tmpglob, IO *io)
     dVAR;
     SV * const tmpcmd = newSV(0);
     PerlIO *fp;
+    STRLEN len;
+    const char *s = SvPV(tmpglob, len);
 
     PERL_ARGS_ASSERT_START_GLOB;
 
+    if (!IS_SAFE_SYSCALL(s, len, "pattern", "glob"))
+        return NULL;
+
     ENTER;
     SAVEFREESV(tmpcmd);
 #ifdef VMS /* expand the wildcards right here, rather than opening a pipe, */
@@ -2399,6 +2435,12 @@ Perl_vms_start_glob
     fp = IoIFP(io);
 #endif /* !VMS */
     LEAVE;
+
+    if (!fp && ckWARN(WARN_GLOB)) {
+        Perl_warner(aTHX_ packWARN(WARN_GLOB), "glob failed (can't start child: %s)",
+                    Strerror(errno));
+    }
+
     return fp;
 }