This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: When should PERL_SYS_TERM() be called? [was: Re: [PATCH] Re: [PATCH] Re: [PATCH...
[perl5.git] / perlio.c
index 6efc7cd..0d91fb4 100644 (file)
--- a/perlio.c
+++ b/perlio.c
 #ifdef PERL_MICRO
 #   include "uconfig.h"
 #else
-#   include "config.h"
+#   ifndef USE_CROSS_COMPILE
+#       include "config.h"
+#   else
+#       include "xconfig.h"
+#   endif
 #endif
 
 #define PERLIO_NOT_STDIO 0
@@ -110,7 +114,15 @@ int mkstemp(char*);
        else                                                    \
                SETERRNO(EBADF, SS_IVCHAN)
 
+#if defined(__osf__) && _XOPEN_SOURCE < 500
+extern int   fseeko(FILE *, off_t, int);
+extern off_t ftello(FILE *);
+#endif
+
 #ifndef USE_SFIO
+
+EXTERN_C int perlsio_binmode(FILE *fp, int iotype, int mode);
+
 int
 perlsio_binmode(FILE *fp, int iotype, int mode)
 {
@@ -461,12 +473,19 @@ PerlIO_debug(const char *fmt, ...)
     va_list ap;
     dSYS;
     va_start(ap, fmt);
-    if (!PL_perlio_debug_fd && !PL_tainting && PL_uid == PL_euid && PL_gid == PL_egid) {
-       const char * const s = PerlEnv_getenv("PERLIO_DEBUG");
-       if (s && *s)
-           PL_perlio_debug_fd = PerlLIO_open3(s, O_WRONLY | O_CREAT | O_APPEND, 0666);
-       else
+    if (!PL_perlio_debug_fd) {
+       if (!PL_tainting && PL_uid == PL_euid && PL_gid == PL_egid) {
+           const char * const s = PerlEnv_getenv("PERLIO_DEBUG");
+           if (s && *s)
+               PL_perlio_debug_fd
+                   = PerlLIO_open3(s, O_WRONLY | O_CREAT | O_APPEND, 0666);
+           else
+               PL_perlio_debug_fd = -1;
+       } else {
+           /* tainting or set*id, so ignore the environment, and ensure we
+              skip these tests next time through.  */
            PL_perlio_debug_fd = -1;
+       }
     }
     if (PL_perlio_debug_fd > 0) {
        dTHX;
@@ -474,13 +493,9 @@ PerlIO_debug(const char *fmt, ...)
        const char * const s = CopFILE(PL_curcop);
        /* Use fixed buffer as sv_catpvf etc. needs SVs */
        char buffer[1024];
-       const STRLEN len = my_sprintf(buffer, "%.40s:%" IVdf " ", s ? s : "(none)", (IV) CopLINE(PL_curcop));
-# ifdef USE_VSNPRINTF
-       const STRLEN len2 = vsnprintf(buffer+len, sizeof(buffer) - len, fmt, ap);
-# else
-       const STRLEN len2 = vsprintf(buffer+len, fmt, ap);
-# endif /* USE_VSNPRINTF */
-       PerlLIO_write(PL_perlio_debug_fd, buffer, len + len2);
+       const STRLEN len1 = my_snprintf(buffer, sizeof(buffer), "%.40s:%" IVdf " ", s ? s : "(none)", (IV) CopLINE(PL_curcop));
+       const STRLEN len2 = my_vsnprintf(buffer + len1, sizeof(buffer) - len1, fmt, ap);
+       PerlLIO_write(PL_perlio_debug_fd, buffer, len1 + len2);
 #else
        const char *s = CopFILE(PL_curcop);
        STRLEN len;
@@ -1408,32 +1423,6 @@ Perl_PerlIO_fileno(pTHX_ PerlIO *f)
      Perl_PerlIO_or_Base(f, Fileno, fileno, -1, (aTHX_ f));
 }
 
-static const char *
-PerlIO_context_layers(pTHX_ const char *mode)
-{
-    dVAR;
-    const char *type = NULL;
-    /*
-     * Need to supply default layer info from open.pm
-     */
-    if (PL_curcop) {
-       SV * const layers = PL_curcop->cop_io;
-       if (layers) {
-           STRLEN len;
-           type = SvPV_const(layers, len);
-           if (type && mode[0] != 'r') {
-               /*
-                * Skip to write part
-                */
-               const char * const s = strchr(type, 0);
-               if (s && (STRLEN)(s - type) < len) {
-                   type = s + 1;
-               }
-           }
-       }
-    }
-    return type;
-}
 
 static PerlIO_funcs *
 PerlIO_layer_from_ref(pTHX_ SV *sv)
@@ -1442,8 +1431,14 @@ PerlIO_layer_from_ref(pTHX_ SV *sv)
     /*
      * For any scalar type load the handler which is bundled with perl
      */
-    if (SvTYPE(sv) < SVt_PVAV)
-       return PerlIO_find_layer(aTHX_ STR_WITH_LEN("scalar"), 1);
+    if (SvTYPE(sv) < SVt_PVAV) {
+       PerlIO_funcs *f = PerlIO_find_layer(aTHX_ STR_WITH_LEN("scalar"), 1);
+       /* This isn't supposed to happen, since PerlIO::scalar is core,
+        * but could happen anyway in smaller installs or with PAR */
+       if (!f && ckWARN(WARN_LAYER))
+           Perl_warner(aTHX_ packWARN(WARN_LAYER), "Unknown PerlIO layer \"scalar\"");
+       return f;
+    }
 
     /*
      * For other types allow if layer is known but don't try and load it
@@ -1457,8 +1452,9 @@ PerlIO_layer_from_ref(pTHX_ SV *sv)
        return PerlIO_find_layer(aTHX_ STR_WITH_LEN("Code"), 0);
     case SVt_PVGV:
        return PerlIO_find_layer(aTHX_ STR_WITH_LEN("Glob"), 0);
+    default:
+       return NULL;
     }
-    return NULL;
 }
 
 PerlIO_list_t *
@@ -1491,7 +1487,7 @@ PerlIO_resolve_layers(pTHX_ const char *layers,
        }
     }
     if (!layers || !*layers)
-       layers = PerlIO_context_layers(aTHX_ mode);
+       layers = Perl_PerlIO_context_layers(aTHX_ mode);
     if (layers && *layers) {
        PerlIO_list_t *av;
        if (incdef) {
@@ -1528,7 +1524,7 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd,
     if (!f && narg == 1 && *args == &PL_sv_undef) {
        if ((f = PerlIO_tmpfile())) {
            if (!layers || !*layers)
-               layers = PerlIO_context_layers(aTHX_ mode);
+               layers = Perl_PerlIO_context_layers(aTHX_ mode);
            if (layers && *layers)
                PerlIO_apply_layers(aTHX_ f, mode, layers);
        }
@@ -2263,13 +2259,9 @@ PerlIOBase_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags)
     return f;
 }
 
-#ifdef USE_THREADS
-perl_mutex PerlIO_mutex;
-#endif
-
 /* PL_perlio_fd_refcnt[] is in intrpvar.h */
 
-/* Must be called with PerlIO_mutex locked.  */
+/* Must be called with PL_perlio_mutex locked. */
 static void
 S_more_refcounted_fds(pTHX_ const int new_fd) {
     dVAR;
@@ -2286,12 +2278,12 @@ S_more_refcounted_fds(pTHX_ const int new_fd) {
 
     assert (new_max > new_fd);
 
-    new_array
-       = PerlMemShared_realloc(PL_perlio_fd_refcnt, new_max * sizeof(int));
+    new_array =
+       (int*) PerlMemShared_realloc(PL_perlio_fd_refcnt, new_max * sizeof(int));
 
     if (!new_array) {
-#ifdef USE_THREADS
-       MUTEX_UNLOCK(&PerlIO_mutex);
+#ifdef USE_ITHREADS
+       MUTEX_UNLOCK(&PL_perlio_mutex);
 #endif
        /* Can't use PerlIO to write as it allocates memory */
        PerlLIO_write(PerlIO_fileno(Perl_error_log),
@@ -2313,12 +2305,8 @@ S_more_refcounted_fds(pTHX_ const int new_fd) {
 void
 PerlIO_init(pTHX)
 {
- /* Place holder for stdstreams call ??? */
-#ifdef USE_THREADS
-    MUTEX_INIT(&PerlIO_mutex);
-#else
+    /* MUTEX_INIT(&PL_perlio_mutex) is done in PERL_SYS_INIT3(). */
     PERL_UNUSED_CONTEXT;
-#endif
 }
 
 void
@@ -2328,18 +2316,25 @@ PerlIOUnix_refcnt_inc(int fd)
     if (fd >= 0) {
        dVAR;
 
-#ifdef USE_THREADS
-       MUTEX_LOCK(&PerlIO_mutex);
+#ifdef USE_ITHREADS
+       MUTEX_LOCK(&PL_perlio_mutex);
 #endif
        if (fd >= PL_perlio_fd_refcnt_size)
            S_more_refcounted_fds(aTHX_ fd);
 
        PL_perlio_fd_refcnt[fd]++;
-       PerlIO_debug("fd %d refcnt=%d\n",fd,PL_perlio_fd_refcnt[fd]);
+       if (PL_perlio_fd_refcnt[fd] <= 0) {
+           Perl_croak(aTHX_ "refcnt_inc: fd %d: %d <= 0\n",
+                      fd, PL_perlio_fd_refcnt[fd]);
+       }
+       PerlIO_debug("refcnt_inc: fd %d refcnt=%d\n",
+                    fd, PL_perlio_fd_refcnt[fd]);
 
-#ifdef USE_THREADS
-       MUTEX_UNLOCK(&PerlIO_mutex);
+#ifdef USE_ITHREADS
+       MUTEX_UNLOCK(&PL_perlio_mutex);
 #endif
+    } else {
+       Perl_croak(aTHX_ "refcnt_inc: fd %d < 0\n", fd);
     }
 }
 
@@ -2350,19 +2345,24 @@ PerlIOUnix_refcnt_dec(int fd)
     int cnt = 0;
     if (fd >= 0) {
        dVAR;
-#ifdef USE_THREADS
-       MUTEX_LOCK(&PerlIO_mutex);
+#ifdef USE_ITHREADS
+       MUTEX_LOCK(&PL_perlio_mutex);
 #endif
-       /* XXX should this be a panic?  */
-       if (fd >= PL_perlio_fd_refcnt_size)
-           S_more_refcounted_fds(aTHX_ fd);
-
-       /* XXX should this be a panic if it drops below 0?  */
+       if (fd >= PL_perlio_fd_refcnt_size) {
+           Perl_croak(aTHX_ "refcnt_dec: fd %d >= refcnt_size %d\n",
+                      fd, PL_perlio_fd_refcnt_size);
+       }
+       if (PL_perlio_fd_refcnt[fd] <= 0) {
+           Perl_croak(aTHX_ "refcnt_dec: fd %d: %d <= 0\n",
+                      fd, PL_perlio_fd_refcnt[fd]);
+       }
        cnt = --PL_perlio_fd_refcnt[fd];
-       PerlIO_debug("fd %d refcnt=%d\n",fd,cnt);
-#ifdef USE_THREADS
-       MUTEX_UNLOCK(&PerlIO_mutex);
+       PerlIO_debug("refcnt_dec: fd %d refcnt=%d\n", fd, cnt);
+#ifdef USE_ITHREADS
+       MUTEX_UNLOCK(&PL_perlio_mutex);
 #endif
+    } else {
+       Perl_croak(aTHX_ "refcnt_dec: fd %d < 0\n", fd);
     }
     return cnt;
 }
@@ -2377,6 +2377,7 @@ PerlIO_cleanup(pTHX)
 #else
     PerlIO_debug("Cleanup layers\n");
 #endif
+
     /* Raise STDIN..STDERR refcount so we don't close them */
     for (i=0; i < 3; i++)
        PerlIOUnix_refcnt_inc(i);
@@ -2395,6 +2396,37 @@ PerlIO_cleanup(pTHX)
     }
 }
 
+void PerlIO_teardown(pTHX) /* Call only from PERL_SYS_TERM(). */
+{
+    
+#ifdef DEBUGGING
+    {
+       /* By now all filehandles should have been closed, so any
+        * stray (non-STD-)filehandles indicate *possible* (PerlIO)
+        * errors. */
+       int i;
+       for (i = 3; i < PL_perlio_fd_refcnt_size; i++) {
+           if (PL_perlio_fd_refcnt[i])
+               PerlIO_debug("PerlIO_cleanup: fd %d refcnt=%d\n",
+                            i, PL_perlio_fd_refcnt[i]);
+       }
+    }
+#endif
+#if !defined(WIN32) || !defined(PERL_IMPLICIT_SYS)
+    /* On Windows, under PERL_IMPLICIT_SYS, all memory allocated by
+     * PerlMemShared_...() will be freed anyways when PL_curinterp
+     * is being destroyed. */
+    if (PL_perlio_fd_refcnt_size /* Assuming initial size of zero. */
+        && PL_perlio_fd_refcnt) {
+       /* Not bothering with PL_perlio_mutex since by now all the
+        * interpreters are gone. */
+       PerlMemShared_free(PL_perlio_fd_refcnt);
+       PL_perlio_fd_refcnt = NULL;
+       PL_perlio_fd_refcnt_size = 0;
+    }
+#endif
+}
+
 
 
 /*--------------------------------------------------------------------------------------*/
@@ -2987,6 +3019,7 @@ PerlIOStdio_invalidate_fileno(pTHX_ FILE *f)
     f->_fileno = -1;
     return 1;
 #  elif defined(__sun__)
+    PERL_UNUSED_ARG(f);
     return 0;
 #  elif defined(__hpux)
     f->__fileH = 0xff;
@@ -3335,7 +3368,7 @@ PerlIOStdio_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
     FILE * const stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
     if (ptr != NULL) {
 #ifdef STDIO_PTR_LVALUE
-       PerlSIO_set_ptr(stdio, (void*)ptr); /* LHS STDCHAR* cast non-portable */
+       PerlSIO_set_ptr(stdio, ptr); /* LHS STDCHAR* cast non-portable */
 #ifdef STDIO_PTR_LVAL_SETS_CNT
        if (PerlSIO_get_cnt(stdio) != (cnt)) {
            assert(PerlSIO_get_cnt(stdio) == (cnt));
@@ -4208,6 +4241,21 @@ typedef struct {
                                 * buffer */
 } PerlIOCrlf;
 
+/* Inherit the PERLIO_F_UTF8 flag from previous layer.
+ * Otherwise the :crlf layer would always revert back to
+ * raw mode.
+ */
+static void
+S_inherit_utf8_flag(PerlIO *f)
+{
+    PerlIO *g = PerlIONext(f);
+    if (PerlIOValid(g)) {
+       if (PerlIOBase(g)->flags & PERLIO_F_UTF8) {
+           PerlIOBase(f)->flags |= PERLIO_F_UTF8;
+       }
+    }
+}
+
 IV
 PerlIOCrlf_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab)
 {
@@ -4225,17 +4273,19 @@ PerlIOCrlf_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab)
        * any given moment at most one CRLF-capable layer being enabled
        * in the whole layer stack. */
         PerlIO *g = PerlIONext(f);
-        while (g && *g) {
+        while (PerlIOValid(g)) {
              PerlIOl *b = PerlIOBase(g);
              if (b && b->tab == &PerlIO_crlf) {
                   if (!(b->flags & PERLIO_F_CRLF))
                        b->flags |= PERLIO_F_CRLF;
+                  S_inherit_utf8_flag(g);
                   PerlIO_pop(aTHX_ f);
                   return code;
              }           
              g = PerlIONext(g);
         }
     }
+    S_inherit_utf8_flag(f);
     return code;
 }
 
@@ -4570,7 +4620,7 @@ PerlIOMmap_map(pTHX_ PerlIO *f)
                }
                posn = (b->posn / PL_mmap_page_size) * PL_mmap_page_size;
                len = st.st_size - posn;
-               m->mptr = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, posn);
+               m->mptr = (Mmap_t)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, posn);
                if (m->mptr && m->mptr != (Mmap_t) - 1) {
 #if 0 && defined(HAS_MADVISE) && defined(MADV_SEQUENTIAL)
                    madvise(m->mptr, len, MADV_SEQUENTIAL);
@@ -4609,7 +4659,14 @@ PerlIOMmap_unmap(pTHX_ PerlIO *f)
     if (m->len) {
        PerlIOBuf * const b = &m->base;
        if (b->buf) {
-           code = munmap(m->mptr, m->len);
+           /* The munmap address argument is tricky: depending on the
+            * standard it is either "void *" or "caddr_t" (which is
+            * usually "char *" (signed or unsigned).  If we cast it
+            * to "void *", those that have it caddr_t and an uptight
+            * C++ compiler, will freak out.  But casting it as char*
+            * should work.  Maybe.  (Using Mmap_t figured out by
+            * Configure doesn't always work, apparently.) */
+           code = munmap((char*)m->mptr, m->len);
            b->buf = NULL;
            m->len = 0;
            m->mptr = NULL;
@@ -5026,16 +5083,9 @@ PerlIO_tmpfile(void)
 #    else      /* !HAS_MKSTEMP, fallback to stdio tmpfile(). */
      FILE * const stdio = PerlSIO_tmpfile();
 
-     if (stdio) {
-         if ((f = PerlIO_push(aTHX_(PerlIO_allocate(aTHX)),
-                               PERLIO_FUNCS_CAST(&PerlIO_stdio),
-                              "w+", NULL))) {
-              PerlIOStdio * const s = PerlIOSelf(f, PerlIOStdio);
+     if (stdio)
+         f = PerlIO_fdopen(fileno(stdio), "w+");
 
-               if (s)
-                    s->stdio = stdio;
-          }
-     }
 #    endif /* else HAS_MKSTEMP */
 #endif /* else WIN32 */
      return f;
@@ -5052,6 +5102,36 @@ PerlIO_tmpfile(void)
  * Now some functions in terms of above which may be needed even if we are
  * not in true PerlIO mode
  */
+const char *
+Perl_PerlIO_context_layers(pTHX_ const char *mode)
+{
+    dVAR;
+    const char *type = NULL;
+    /*
+     * Need to supply default layer info from open.pm
+     */
+    if (PL_curcop && PL_curcop->cop_hints & HINT_LEXICAL_IO) {
+       SV * const layers
+           = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash, 0,
+                                      "open", 4, 0, 0);
+       assert(layers);
+       if (SvOK(layers)) {
+           STRLEN len;
+           type = SvPV_const(layers, len);
+           if (type && mode && mode[0] != 'r') {
+               /*
+                * Skip to write part, which is separated by a '\0'
+                */
+               STRLEN read_len = strlen(type);
+               if (read_len < len) {
+                   type += read_len + 1;
+               }
+           }
+       }
+    }
+    return type;
+}
+
 
 #ifndef HAS_FSETPOS
 #undef PerlIO_setpos
@@ -5142,20 +5222,15 @@ vfprintf(FILE *fd, char *pat, char *args)
 int
 PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap)
 {
-    dVAR;
-#ifdef USE_VSNPRINTF
-    const int val = vsnprintf(s, n > 0 ? n : 0, fmt, ap);
-#else
-    const int val = vsprintf(s, fmt, ap);
-#endif /* #ifdef USE_VSNPRINTF */
-    if (n >= 0) {
-       if (strlen(s) >= (STRLEN) n) {
-           dTHX;
-           (void) PerlIO_puts(Perl_error_log,
-                              "panic: sprintf overflow - memory corrupted!\n");
-           my_exit(1);
-       }
+    dTHX; 
+    const int val = my_vsnprintf(s, n > 0 ? n : 0, fmt, ap);
+    PERL_UNUSED_CONTEXT;
+
+#ifndef PERL_MY_VSNPRINTF_GUARDED
+    if (val < 0 || (n > 0 ? val >= n : 0)) {
+       Perl_croak(aTHX_ "panic: my_vsnprintf overflow in PerlIO_vsprintf\n");
     }
+#endif
     return val;
 }
 #endif