This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate:
[perl5.git] / util.c
diff --git a/util.c b/util.c
index 0068f3c..1df8d62 100644 (file)
--- a/util.c
+++ b/util.c
@@ -64,7 +64,7 @@ S_write_no_mem(pTHX)
     PerlLIO_write(PerlIO_fileno(Perl_error_log),
                  PL_no_mem, strlen(PL_no_mem));
     my_exit(1);
-    return Nullch;
+    NORETURN_FUNCTION_END;
 }
 
 /* paranoid version of system's malloc() */
@@ -93,7 +93,24 @@ Perl_safesysmalloc(MEM_SIZE size)
     DEBUG_m(PerlIO_printf(Perl_debug_log, "0x%"UVxf": (%05ld) malloc %ld bytes\n",PTR2UV(ptr),(long)PL_an++,(long)size));
     if (ptr != NULL) {
 #ifdef PERL_TRACK_MEMPOOL
-        *(tTHX*)ptr = aTHX;
+       struct perl_memory_debug_header *const header
+           = (struct perl_memory_debug_header *)ptr;
+#endif
+
+#ifdef PERL_POISON
+       Poison(((char *)ptr), size, char);
+#endif
+
+#ifdef PERL_TRACK_MEMPOOL
+       header->interpreter = aTHX;
+       /* Link us into the list.  */
+       header->prev = &PL_memory_debug_header;
+       header->next = PL_memory_debug_header.next;
+       PL_memory_debug_header.next = header;
+       header->next->prev = header;
+#  ifdef PERL_POISON
+       header->size = size;
+#  endif
         ptr = (Malloc_t)((char*)ptr+sTHX);
 #endif
        return ptr;
@@ -101,7 +118,7 @@ Perl_safesysmalloc(MEM_SIZE size)
     else if (PL_nomemok)
        return NULL;
     else {
-       return S_write_no_mem(aTHX);
+       return write_no_mem();
     }
     /*NOTREACHED*/
 }
@@ -134,9 +151,23 @@ Perl_safesysrealloc(Malloc_t where,MEM_SIZE size)
 #ifdef PERL_TRACK_MEMPOOL
     where = (Malloc_t)((char*)where-sTHX);
     size += sTHX;
-    if (*(tTHX*)where != aTHX) {
-       /* int *nowhere = NULL; *nowhere = 0; */
-        Perl_croak_nocontext("panic: realloc from wrong pool");
+    {
+       struct perl_memory_debug_header *const header
+           = (struct perl_memory_debug_header *)where;
+
+       if (header->interpreter != aTHX) {
+           Perl_croak_nocontext("panic: realloc from wrong pool");
+       }
+       assert(header->next->prev == header);
+       assert(header->prev->next == header);
+#  ifdef PERL_POISON
+       if (header->size > size) {
+           const MEM_SIZE freed_up = header->size - size;
+           char *start_of_freed = ((char *)where) + size;
+           Poison(start_of_freed, freed_up, char);
+       }
+       header->size = size;
+#  endif
     }
 #endif
 #ifdef DEBUGGING
@@ -151,6 +182,20 @@ Perl_safesysrealloc(Malloc_t where,MEM_SIZE size)
 
     if (ptr != NULL) {
 #ifdef PERL_TRACK_MEMPOOL
+       struct perl_memory_debug_header *const header
+           = (struct perl_memory_debug_header *)ptr;
+
+#  ifdef PERL_POISON
+       if (header->size < size) {
+           const MEM_SIZE fresh = size - header->size;
+           char *start_of_fresh = ((char *)ptr) + size;
+           Poison(start_of_fresh, fresh, char);
+       }
+#  endif
+
+       header->next->prev = header;
+       header->prev->next = header;
+
         ptr = (Malloc_t)((char*)ptr+sTHX);
 #endif
        return ptr;
@@ -158,7 +203,7 @@ Perl_safesysrealloc(Malloc_t where,MEM_SIZE size)
     else if (PL_nomemok)
        return NULL;
     else {
-       return S_write_no_mem(aTHX);
+       return write_no_mem();
     }
     /*NOTREACHED*/
 }
@@ -175,9 +220,28 @@ Perl_safesysfree(Malloc_t where)
     if (where) {
 #ifdef PERL_TRACK_MEMPOOL
         where = (Malloc_t)((char*)where-sTHX);
-        if (*(tTHX*)where != aTHX) {
-           /* int *nowhere = NULL; *nowhere = 0; */
-            Perl_croak_nocontext("panic: free from wrong pool");
+       {
+           struct perl_memory_debug_header *const header
+               = (struct perl_memory_debug_header *)where;
+
+           if (header->interpreter != aTHX) {
+               Perl_croak_nocontext("panic: free from wrong pool");
+           }
+           if (!header->prev) {
+               Perl_croak_nocontext("panic: duplicate free");
+           }
+           if (!(header->next) || header->next->prev != header
+               || header->prev->next != header) {
+               Perl_croak_nocontext("panic: bad free");
+           }
+           /* Unlink us from the chain.  */
+           header->next->prev = header->prev;
+           header->prev->next = header->next;
+#  ifdef PERL_POISON
+           Poison(where, header->size, char);
+#  endif
+           /* Trigger the duplicate free warning.  */
+           header->next = NULL;
        }
 #endif
        PerlMem_free(where);
@@ -213,17 +277,27 @@ Perl_safesyscalloc(MEM_SIZE count, MEM_SIZE size)
     if (ptr != NULL) {
        memset((void*)ptr, 0, size);
 #ifdef PERL_TRACK_MEMPOOL
-        *(tTHX*)ptr = aTHX;
-        ptr = (Malloc_t)((char*)ptr+sTHX);
+       {
+           struct perl_memory_debug_header *const header
+               = (struct perl_memory_debug_header *)ptr;
+
+           header->interpreter = aTHX;
+           /* Link us into the list.  */
+           header->prev = &PL_memory_debug_header;
+           header->next = PL_memory_debug_header.next;
+           PL_memory_debug_header.next = header;
+           header->next->prev = header;
+#  ifdef PERL_POISON
+           header->size = size;
+#  endif
+           ptr = (Malloc_t)((char*)ptr+sTHX);
+       }
 #endif
        return ptr;
     }
     else if (PL_nomemok)
        return NULL;
-    else {
-       return S_write_no_mem(aTHX);
-    }
-    /*NOTREACHED*/
+    return write_no_mem();
 }
 
 /* These must be defined when not using Perl's malloc for binary
@@ -305,9 +379,11 @@ Perl_instr(pTHX_ register const char *big, register const char *little)
        for (x=big,s=little; *s; /**/ ) {
            if (!*x)
                return NULL;
-           if (*s++ != *x++) {
-               s--;
+           if (*s != *x)
                break;
+           else {
+               s++;
+               x++;
            }
        }
        if (!*s)
@@ -319,28 +395,24 @@ Perl_instr(pTHX_ register const char *big, register const char *little)
 /* same as instr but allow embedded nulls */
 
 char *
-Perl_ninstr(pTHX_ register const char *big, register const char *bigend, const char *little, const char *lend)
+Perl_ninstr(pTHX_ const char *big, const char *bigend, const char *little, const char *lend)
 {
-    register const I32 first = *little;
-    register const char *littleend = lend;
-
-    if (!first && little >= littleend)
-       return (char*)big;
-    if (bigend - big < littleend - little)
-       return Nullch;
-    bigend -= littleend - little++;
-    while (big <= bigend) {
-       register const char *s, *x;
-       if (*big++ != first)
-           continue;
-       for (x=big,s=little; s < littleend; /**/ ) {
-           if (*s++ != *x++) {
-               s--;
-               break;
-           }
-       }
-       if (s >= littleend)
-           return (char*)(big-1);
+    if (little >= lend)
+        return (char*)big;
+    {
+        char first = *little++;
+        const char *s, *x;
+        bigend -= lend - little;
+    OUTER:
+        while (big <= bigend) {
+            if (*big++ != first)
+                goto OUTER;
+            for (x=big,s=little; s < lend; x++,s++) {
+                if (*s != *x)
+                    goto OUTER;
+            }
+            return (char*)(big-1);
+        }
     }
     return NULL;
 }
@@ -352,9 +424,9 @@ Perl_rninstr(pTHX_ register const char *big, const char *bigend, const char *lit
 {
     register const char *bigbeg;
     register const I32 first = *little;
-    register const char *littleend = lend;
+    register const char * const littleend = lend;
 
-    if (!first && little >= littleend)
+    if (little >= littleend)
        return (char*)bigend;
     bigbeg = big;
     big = bigend - (littleend - little++);
@@ -363,9 +435,11 @@ Perl_rninstr(pTHX_ register const char *big, const char *bigend, const char *lit
        if (*big-- != first)
            continue;
        for (x=big+2,s=little; s < littleend; /**/ ) {
-           if (*s++ != *x++) {
-               s--;
+           if (*s != *x)
                break;
+           else {
+               x++;
+               s++;
            }
        }
        if (s >= littleend)
@@ -404,7 +478,7 @@ Perl_fbm_compile(pTHX_ SV *sv, U32 flags)
 
     if (flags & FBMcf_TAIL) {
        MAGIC * const mg = SvUTF8(sv) && SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_utf8) : NULL;
-       sv_catpvn(sv, "\n", 1);         /* Taken into account in fbm_instr() */
+       sv_catpvs(sv, "\n");            /* Taken into account in fbm_instr() */
        if (mg && mg->mg_len >= 0)
            mg->mg_len++;
     }
@@ -849,7 +923,7 @@ Perl_savesharedpv(pTHX_ const char *pv)
     pvlen = strlen(pv)+1;
     newaddr = (char*)PerlMemShared_malloc(pvlen);
     if (!newaddr) {
-       return S_write_no_mem(aTHX);
+       return write_no_mem();
     }
     return memcpy(newaddr,pv,pvlen);
 }
@@ -867,7 +941,7 @@ char *
 Perl_savesvpv(pTHX_ SV *sv)
 {
     STRLEN len;
-    const char *pv = SvPV_const(sv, len);
+    const char * const pv = SvPV_const(sv, len);
     register char *newaddr;
 
     ++len;
@@ -885,7 +959,7 @@ S_mess_alloc(pTHX)
     XPVMG *any;
 
     if (!PL_dirty)
-       return sv_2mortal(newSVpvn("",0));
+       return sv_2mortal(newSVpvs(""));
 
     if (PL_mess_sv)
        return PL_mess_sv;
@@ -978,46 +1052,45 @@ Perl_mess(pTHX_ const char *pat, ...)
     return retval;
 }
 
-STATIC COP*
-S_closest_cop(pTHX_ COP *cop, const OP *o)
+STATIC const COP*
+S_closest_cop(pTHX_ const COP *cop, const OP *o)
 {
     /* Look for PL_op starting from o.  cop is the last COP we've seen. */
 
-    if (!o || o == PL_op) return cop;
+    if (!o || o == PL_op)
+       return cop;
 
     if (o->op_flags & OPf_KIDS) {
-       OP *kid;
-       for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling)
-       {
-           COP *new_cop;
+       const OP *kid;
+       for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) {
+           const COP *new_cop;
 
            /* If the OP_NEXTSTATE has been optimised away we can still use it
             * the get the file and line number. */
 
            if (kid->op_type == OP_NULL && kid->op_targ == OP_NEXTSTATE)
-               cop = (COP *)kid;
+               cop = (const COP *)kid;
 
            /* Keep searching, and return when we've found something. */
 
            new_cop = closest_cop(cop, kid);
-           if (new_cop) return new_cop;
+           if (new_cop)
+               return new_cop;
        }
     }
 
     /* Nothing found. */
 
-    return Null(COP *);
+    return NULL;
 }
 
 SV *
 Perl_vmess(pTHX_ const char *pat, va_list *args)
 {
     SV * const sv = mess_alloc();
-    static const char dgd[] = " during global destruction.\n";
 
-    sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
+    sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
     if (!SvCUR(sv) || *(SvEND(sv) - 1) != '\n') {
-
        /*
         * Try and find the file and line for PL_op.  This will usually be
         * PL_curcop, but it might be a cop that has been optimised away.  We
@@ -1026,7 +1099,8 @@ Perl_vmess(pTHX_ const char *pat, va_list *args)
         */
 
        const COP *cop = closest_cop(PL_curcop, PL_curcop->op_sibling);
-       if (!cop) cop = PL_curcop;
+       if (!cop)
+           cop = PL_curcop;
 
        if (CopLINE(cop))
            Perl_sv_catpvf(aTHX_ sv, " at %s line %"IVdf,
@@ -1035,8 +1109,7 @@ Perl_vmess(pTHX_ const char *pat, va_list *args)
            const bool line_mode = (RsSIMPLE(PL_rs) &&
                              SvCUR(PL_rs) == 1 && *SvPVX_const(PL_rs) == '\n');
            Perl_sv_catpvf(aTHX_ sv, ", <%s> %s %"IVdf,
-                          PL_last_in_gv == PL_argvgv ?
-                          "" : GvNAME(PL_last_in_gv),
+                          PL_last_in_gv == PL_argvgv ? "" : GvNAME(PL_last_in_gv),
                           line_mode ? "line" : "chunk",
                           (IV)IoLINES(GvIOp(PL_last_in_gv)));
        }
@@ -1044,7 +1117,9 @@ Perl_vmess(pTHX_ const char *pat, va_list *args)
        if (thr->tid)
            Perl_sv_catpvf(aTHX_ sv, " thread %ld", thr->tid);
 #endif
-       sv_catpv(sv, PL_dirty ? dgd : ".\n");
+       if (PL_dirty)
+           sv_catpvs(sv, " during global destruction");
+       sv_catpvs(sv, ".\n");
     }
     return sv;
 }
@@ -1095,24 +1170,24 @@ Perl_write_to_stderr(pTHX_ const char* message, int msglen)
     }
 }
 
-/* Common code used by vcroak, vdie and vwarner  */
+/* Common code used by vcroak, vdie, vwarn and vwarner  */
 
-/* Whilst this should really be STATIC, it was not in 5.8.7, hence something
-   may have linked against it.  */
-void
-S_vdie_common(pTHX_ const char *message, STRLEN msglen, I32 utf8)
+STATIC bool
+S_vdie_common(pTHX_ const char *message, STRLEN msglen, I32 utf8, bool warn)
 {
     HV *stash;
     GV *gv;
     CV *cv;
-    /* sv_2cv might call Perl_croak() */
-    SV * const olddiehook = PL_diehook;
+    SV **const hook = warn ? &PL_warnhook : &PL_diehook;
+    /* sv_2cv might call Perl_croak() or Perl_warner() */
+    SV * const oldhook = *hook;
+
+    assert(oldhook);
 
-    assert(PL_diehook);
     ENTER;
-    SAVESPTR(PL_diehook);
-    PL_diehook = Nullsv;
-    cv = sv_2cv(olddiehook, &stash, &gv, 0);
+    SAVESPTR(*hook);
+    *hook = NULL;
+    cv = sv_2cv(oldhook, &stash, &gv, 0);
     LEAVE;
     if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
        dSP;
@@ -1120,7 +1195,11 @@ S_vdie_common(pTHX_ const char *message, STRLEN msglen, I32 utf8)
 
        ENTER;
        save_re_context();
-       if (message) {
+       if (warn) {
+           SAVESPTR(*hook);
+           *hook = NULL;
+       }
+       if (warn || message) {
            msg = newSVpvn(message, msglen);
            SvFLAGS(msg) |= utf8;
            SvREADONLY_on(msg);
@@ -1130,14 +1209,16 @@ S_vdie_common(pTHX_ const char *message, STRLEN msglen, I32 utf8)
            msg = ERRSV;
        }
 
-       PUSHSTACKi(PERLSI_DIEHOOK);
+       PUSHSTACKi(warn ? PERLSI_WARNHOOK : PERLSI_DIEHOOK);
        PUSHMARK(SP);
        XPUSHs(msg);
        PUTBACK;
        call_sv((SV*)cv, G_DISCARD);
        POPSTACK;
        LEAVE;
+       return TRUE;
     }
+    return FALSE;
 }
 
 /* Whilst this should really be STATIC, it was not in 5.8.7, hence something
@@ -1167,7 +1248,7 @@ S_vdie_croak_common(pTHX_ const char* pat, va_list* args, STRLEN* msglen,
                          "%p: die/croak: message = %s\ndiehook = %p\n",
                          thr, message, PL_diehook));
     if (PL_diehook) {
-       S_vdie_common(aTHX_ message, *msglen, *utf8);
+       S_vdie_common(aTHX_ message, *msglen, *utf8, FALSE);
     }
     /* Cast because we're not changing function prototypes in maint, and this
        function isn't actually static.  */
@@ -1296,39 +1377,8 @@ Perl_vwarn(pTHX_ const char* pat, va_list *args)
     const char * const message = SvPV_const(msv, msglen);
 
     if (PL_warnhook) {
-       /* sv_2cv might call Perl_warn() */
-       SV * const oldwarnhook = PL_warnhook;
-       CV * cv;
-       HV * stash;
-       GV * gv;
-
-       ENTER;
-       SAVESPTR(PL_warnhook);
-       PL_warnhook = Nullsv;
-       cv = sv_2cv(oldwarnhook, &stash, &gv, 0);
-       LEAVE;
-       if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
-           dSP;
-           SV *msg;
-
-           ENTER;
-           SAVESPTR(PL_warnhook);
-           PL_warnhook = Nullsv;
-           save_re_context();
-           msg = newSVpvn(message, msglen);
-           SvFLAGS(msg) |= utf8;
-           SvREADONLY_on(msg);
-           SAVEFREESV(msg);
-
-           PUSHSTACKi(PERLSI_WARNHOOK);
-           PUSHMARK(SP);
-           XPUSHs(msg);
-           PUTBACK;
-           call_sv((SV*)cv, G_DISCARD);
-           POPSTACK;
-           LEAVE;
+       if (vdie_common(message, msglen, utf8, TRUE))
            return;
-       }
     }
 
     write_to_stderr(message, msglen);
@@ -1391,7 +1441,7 @@ Perl_vwarner(pTHX_ U32  err, const char* pat, va_list* args)
     if (ckDEAD(err)) {
        SV * const msv = vmess(pat, args);
        STRLEN msglen;
-       const char *message = SvPV_const(msv, msglen);
+       const char * const message = SvPV_const(msv, msglen);
        const I32 utf8 = SvUTF8(msv);
 
 #ifdef USE_5005THREADS
@@ -1399,7 +1449,7 @@ Perl_vwarner(pTHX_ U32  err, const char* pat, va_list* args)
 #endif /* USE_5005THREADS */
        if (PL_diehook) {
            assert(message);
-           S_vdie_common(aTHX_ message, msglen, utf8);
+           S_vdie_common(aTHX_ message, msglen, utf8, FALSE);
        }
        if (PL_in_eval) {
            PL_restartop = die_where((char *) message, msglen);
@@ -2258,7 +2308,7 @@ Perl_my_popen(pTHX_ char *cmd, char *mode)
            PerlProc__exit(1);
        }
 #endif /* defined OS2 */
-       if ((tmpgv = gv_fetchpv("$",TRUE, SVt_PV))) {
+       if ((tmpgv = gv_fetchpvs("$", GV_ADD|GV_NOTQUAL, SVt_PV))) {
            SvREADONLY_off(GvSV(tmpgv));
            sv_setiv(GvSV(tmpgv), PerlProc_getpid());
            SvREADONLY_on(GvSV(tmpgv));
@@ -2550,8 +2600,7 @@ Perl_rsignal(pTHX_ int signo, Sighandler_t handler)
 static int PL_sig_trapped; /* XXX signals are process-wide anyway, so we
                              ignore the implications of this for threading */
 
-static
-Signal_t
+static Signal_t
 sig_trap(int signo)
 {
     PL_sig_trapped++;
@@ -2767,7 +2816,7 @@ Perl_my_pclose(pTHX_ PerlIO *ptr)
 {
     /* Needs work for PerlIO ! */
     FILE * const f = PerlIO_findFILE(ptr);
-    I32 result = pclose(f);
+    const I32 result = pclose(f);
     PerlIO_releaseFILE(ptr,f);
     return result;
 }
@@ -2868,7 +2917,7 @@ Perl_find_script(pTHX_ char *scriptname, bool dosearch, char **search_ext,
 #endif
     /* additional extensions to try in each dir if scriptname not found */
 #ifdef SEARCH_EXTS
-    const char *const exts[] = { SEARCH_EXTS };
+    static const char *const exts[] = { SEARCH_EXTS };
     const char *const *const ext =
        search_ext ? (const char *const *const)search_ext : exts;
     int extidx = 0, i = 0;
@@ -3322,7 +3371,7 @@ Perl_new_struct_thread(pTHX_ struct perl_thread *t)
     PL_in_eval = EVAL_NULL;    /* ~(EVAL_INEVAL|EVAL_WARNONLY|EVAL_KEEPERR|EVAL_INREQUIRE) */
     PL_restartop = 0;
 
-    PL_statname = NEWSV(66,0);
+    PL_statname = newSV(0);
     PL_errors = newSVpvn("", 0);
     PL_maxscream = -1;
     PL_regcompp = MEMBER_TO_FPTR(Perl_pregcomp);
@@ -3457,7 +3506,7 @@ Perl_getenv_len(pTHX_ const char *env_elem, unsigned long *len)
 MGVTBL*
 Perl_get_vtbl(pTHX_ int vtbl_id)
 {
-    const MGVTBL* result = Null(MGVTBL*);
+    const MGVTBL* result;
 
     switch(vtbl_id) {
     case want_vtbl_sv:
@@ -3557,6 +3606,9 @@ Perl_get_vtbl(pTHX_ int vtbl_id)
     case want_vtbl_utf8:
        result = &PL_vtbl_utf8;
        break;
+    default:
+       result = Null(MGVTBL*);
+       break;
     }
     return (MGVTBL*)result;
 }
@@ -4279,8 +4331,8 @@ S_socketpair_udp (int fd[2]) {
        fd_set rset;
 
        FD_ZERO(&rset);
-       FD_SET(sockets[0], &rset);
-       FD_SET(sockets[1], &rset);
+       FD_SET((unsigned int)sockets[0], &rset);
+       FD_SET((unsigned int)sockets[1], &rset);
 
        got = PerlSock_select(max + 1, &rset, NULL, NULL, &waitfor);
        if (got != 2 || !FD_ISSET(sockets[0], &rset)
@@ -4438,7 +4490,7 @@ Perl_my_socketpair (int family, int type, int protocol, int fd[2]) {
 #endif
   tidy_up_and_fail:
     {
-       int save_errno = errno;
+       const int save_errno = errno;
        if (listener != -1)
            PerlLIO_close(listener);
        if (connector != -1)