This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
sv_gets() did not NUL-terminate SV when reading records
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index f5a979a..a54c6ba 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -96,17 +96,17 @@ typedef void (*SVFUNC) _((SV*));
     } while (0)
 
 static SV **registry;
-static I32 regsize;
+static I32 registry_size;
 
 #define REGHASH(sv,size)  ((((U32)(sv)) >> 2) % (size))
 
 #define REG_REPLACE(sv,a,b) \
     do {                               \
        void* p = sv->sv_any;           \
-       I32 h = REGHASH(sv, regsize);   \
+       I32 h = REGHASH(sv, registry_size);     \
        I32 i = h;                      \
        while (registry[i] != (a)) {    \
-           if (++i >= regsize)         \
+           if (++i >= registry_size)   \
                i = 0;                  \
            if (i == h)                 \
                die("SV registry bug"); \
@@ -121,13 +121,13 @@ static void
 reg_add(sv)
 SV* sv;
 {
-    if (sv_count >= (regsize >> 1))
+    if (sv_count >= (registry_size >> 1))
     {
        SV **oldreg = registry;
-       I32 oldsize = regsize;
+       I32 oldsize = registry_size;
 
-       regsize = regsize ? ((regsize << 2) + 1) : 2037;
-       Newz(707, registry, regsize, SV*);
+       registry_size = registry_size ? ((registry_size << 2) + 1) : 2037;
+       Newz(707, registry, registry_size, SV*);
 
        if (oldreg) {
            I32 i;
@@ -159,9 +159,9 @@ SVFUNC f;
 {
     I32 i;
 
-    for (i = 0; i < regsize; ++i) {
+    for (i = 0; i < registry_size; ++i) {
        SV* sv = registry[i];
-       if (sv)
+       if (sv && SvTYPE(sv) != SVTYPEMASK)
            (*f)(sv);
     }
 }
@@ -355,8 +355,6 @@ do_clean_named_objs(SV *sv)
            DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning named glob object:\n "), sv_dump(sv));)
            SvREFCNT_dec(sv);
        }
-       else if (GvSV(sv))
-           do_clean_objs(GvSV(sv));
     }
 }
 #endif
@@ -365,17 +363,18 @@ void
 sv_clean_objs(void)
 {
     in_clean_objs = TRUE;
+    visit(FUNC_NAME_TO_PTR(do_clean_objs));
 #ifndef DISABLE_DESTRUCTOR_KLUDGE
+    /* some barnacles may yet remain, clinging to typeglobs */
     visit(FUNC_NAME_TO_PTR(do_clean_named_objs));
 #endif
-    visit(FUNC_NAME_TO_PTR(do_clean_objs));
     in_clean_objs = FALSE;
 }
 
 STATIC void
 do_clean_all(SV *sv)
 {
-    DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning loops:\n "), sv_dump(sv));)
+    DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning loops: SV at 0x%lx\n", sv) );)
     SvFLAGS(sv) |= SVf_BREAK;
     SvREFCNT_dec(sv);
 }
@@ -417,14 +416,14 @@ sv_free_arenas(void)
 STATIC XPVIV*
 new_xiv(void)
 {
-    IV** xiv;
+    IV* xiv;
     if (xiv_root) {
        xiv = xiv_root;
        /*
         * See comment in more_xiv() -- RAM.
         */
-       xiv_root = (IV**)*xiv;
-       return (XPVIV*)((char*)xiv - sizeof(XPV));
+       xiv_root = *(IV**)xiv;
+       return (XPVIV*)((char*)xiv - STRUCT_OFFSET(XPVIV, xiv_iv));
     }
     return more_xiv();
 }
@@ -432,30 +431,30 @@ new_xiv(void)
 STATIC void
 del_xiv(XPVIV *p)
 {
-    IV** xiv = (IV**)((char*)(p) + sizeof(XPV));
-    *xiv = (IV *)xiv_root;
+    IV* xiv = (IV*)((char*)(p) + STRUCT_OFFSET(XPVIV, xiv_iv));
+    *(IV**)xiv = xiv_root;
     xiv_root = xiv;
 }
 
 STATIC XPVIV*
 more_xiv(void)
 {
-    register IV** xiv;
-    register IV** xivend;
+    register IV* xiv;
+    register IV* xivend;
     XPV* ptr;
     New(705, ptr, 1008/sizeof(XPV), XPV);
     ptr->xpv_pv = (char*)xiv_arenaroot;                /* linked list of xiv arenas */
     xiv_arenaroot = ptr;                       /* to keep Purify happy */
 
-    xiv = (IV**) ptr;
-    xivend = &xiv[1008 / sizeof(IV *) - 1];
-    xiv += (sizeof(XPV) - 1) / sizeof(IV *) + 1;   /* fudge by size of XPV */
+    xiv = (IV*) ptr;
+    xivend = &xiv[1008 / sizeof(IV) - 1];
+    xiv += (sizeof(XPV) - 1) / sizeof(IV) + 1;   /* fudge by size of XPV */
     xiv_root = xiv;
     while (xiv < xivend) {
-       *xiv = (IV *)(xiv + 1);
+       *(IV**)xiv = (IV *)(xiv + 1);
        xiv++;
     }
-    *xiv = 0;
+    *(IV**)xiv = 0;
     return new_xiv();
 }
 
@@ -466,7 +465,7 @@ new_xnv(void)
     if (xnv_root) {
        xnv = xnv_root;
        xnv_root = *(double**)xnv;
-       return (XPVNV*)((char*)xnv - sizeof(XPVIV));
+       return (XPVNV*)((char*)xnv - STRUCT_OFFSET(XPVNV, xnv_nv));
     }
     return more_xnv();
 }
@@ -474,7 +473,7 @@ new_xnv(void)
 STATIC void
 del_xnv(XPVNV *p)
 {
-    double* xnv = (double*)((char*)(p) + sizeof(XPVIV));
+    double* xnv = (double*)((char*)(p) + STRUCT_OFFSET(XPVNV, xnv_nv));
     *(double**)xnv = xnv_root;
     xnv_root = xnv;
 }
@@ -1118,8 +1117,16 @@ sv_grow(SV* sv, unsigned long newlen)
     else
        s = SvPVX(sv);
     if (newlen > SvLEN(sv)) {          /* need more room? */
-        if (SvLEN(sv) && s)
+       if (SvLEN(sv) && s) {
+#if defined(MYMALLOC) && !defined(PURIFY)
+           STRLEN l = malloced_size((void*)SvPVX(sv));
+           if (newlen <= l) {
+               SvLEN_set(sv, l);
+               return s;
+           } else
+#endif
            Renew(s,newlen,char);
+       }
         else
            New(703,s,newlen,char);
        SvPV_set(sv, s);
@@ -1202,14 +1209,8 @@ sv_setnv(register SV *sv, double num)
     case SVt_PV:
     case SVt_PVIV:
        sv_upgrade(sv, SVt_PVNV);
-       /* FALL THROUGH */
-    case SVt_PVNV:
-    case SVt_PVMG:
-    case SVt_PVBM:
-    case SVt_PVLV:
-       if (SvOOK(sv))
-           (void)SvOOK_off(sv);
        break;
+
     case SVt_PVGV:
        if (SvFAKE(sv)) {
            sv_unglob(sv);
@@ -1696,7 +1697,54 @@ sv_2pv(register SV *sv, STRLEN *lp)
            if (!sv)
                s = "NULLREF";
            else {
+               MAGIC *mg;
+               
                switch (SvTYPE(sv)) {
+               case SVt_PVMG:
+                   if ( ((SvFLAGS(sv) &
+                          (SVs_OBJECT|SVf_OK|SVs_GMG|SVs_SMG|SVs_RMG)) 
+                         == (SVs_OBJECT|SVs_RMG))
+                        && strEQ(s=HvNAME(SvSTASH(sv)), "Regexp")
+                        && (mg = mg_find(sv, 'r'))) {
+                       dTHR;
+                       regexp *re = (regexp *)mg->mg_obj;
+
+                       if (!mg->mg_ptr) {
+                           char *fptr = "msix";
+                           char reflags[6];
+                           char ch;
+                           int left = 0;
+                           int right = 4;
+                           U16 reganch = (re->reganch & PMf_COMPILETIME) >> 12;
+
+                           while(ch = *fptr++) {
+                               if(reganch & 1) {
+                                   reflags[left++] = ch;
+                               }
+                               else {
+                                   reflags[right--] = ch;
+                               }
+                               reganch >>= 1;
+                           }
+                           if(left != 4) {
+                               reflags[left] = '-';
+                               left = 5;
+                           }
+
+                           mg->mg_len = re->prelen + 4 + left;
+                           New(616, mg->mg_ptr, mg->mg_len + 1 + left, char);
+                           Copy("(?", mg->mg_ptr, 2, char);
+                           Copy(reflags, mg->mg_ptr+2, left, char);
+                           Copy(":", mg->mg_ptr+left+2, 1, char);
+                           Copy(re->precomp, mg->mg_ptr+3+left, re->prelen, char);
+                           mg->mg_ptr[mg->mg_len - 1] = ')';
+                           mg->mg_ptr[mg->mg_len] = 0;
+                       }
+                       reginterp_cnt += re->program[0].next_off;
+                       *lp = mg->mg_len;
+                       return mg->mg_ptr;
+                   }
+                                       /* Fall through */
                case SVt_NULL:
                case SVt_IV:
                case SVt_NV:
@@ -1704,8 +1752,7 @@ sv_2pv(register SV *sv, STRLEN *lp)
                case SVt_PV:
                case SVt_PVIV:
                case SVt_PVNV:
-               case SVt_PVBM:
-               case SVt_PVMG:  s = "SCALAR";                   break;
+               case SVt_PVBM:  s = "SCALAR";                   break;
                case SVt_PVLV:  s = "LVALUE";                   break;
                case SVt_PVAV:  s = "ARRAY";                    break;
                case SVt_PVHV:  s = "HASH";                     break;
@@ -1914,29 +1961,53 @@ sv_setsv(SV *dstr, register SV *sstr)
 
     switch (stype) {
     case SVt_NULL:
+      undef_sstr:
        if (dtype != SVt_PVGV) {
            (void)SvOK_off(dstr);
            return;
        }
        break;
     case SVt_IV:
-       if (dtype != SVt_IV && dtype < SVt_PVIV) {
-           if (dtype < SVt_IV)
+       if (SvIOK(sstr)) {
+           switch (dtype) {
+           case SVt_NULL:
                sv_upgrade(dstr, SVt_IV);
-           else if (dtype == SVt_NV)
+               break;
+           case SVt_NV:
                sv_upgrade(dstr, SVt_PVNV);
-           else
+               break;
+           case SVt_RV:
+           case SVt_PV:
                sv_upgrade(dstr, SVt_PVIV);
+               break;
+           }
+           (void)SvIOK_only(dstr);
+           SvIVX(dstr) = SvIVX(sstr);
+           SvTAINT(dstr);
+           return;
        }
-       break;
+       goto undef_sstr;
+
     case SVt_NV:
-       if (dtype != SVt_NV && dtype < SVt_PVNV) {
-           if (dtype < SVt_NV)
+       if (SvNOK(sstr)) {
+           switch (dtype) {
+           case SVt_NULL:
+           case SVt_IV:
                sv_upgrade(dstr, SVt_NV);
-           else
+               break;
+           case SVt_RV:
+           case SVt_PV:
+           case SVt_PVIV:
                sv_upgrade(dstr, SVt_PVNV);
+               break;
+           }
+           SvNVX(dstr) = SvNVX(sstr);
+           (void)SvNOK_only(dstr);
+           SvTAINT(dstr);
+           return;
        }
-       break;
+       goto undef_sstr;
+
     case SVt_RV:
        if (dtype < SVt_RV)
            sv_upgrade(dstr, SVt_RV);
@@ -1990,7 +2061,7 @@ sv_setsv(SV *dstr, register SV *sstr)
                SvFAKE_on(dstr);        /* can coerce to non-glob */
            }
            /* ahem, death to those who redefine active sort subs */
-           else if (curstackinfo->si_type == SI_SORT
+           else if (curstackinfo->si_type == PERLSI_SORT
                     && GvCV(dstr) && sortcop == CvSTART(GvCV(dstr)))
                croak("Can't redefine active sort subroutine %s",
                      GvNAME(dstr));
@@ -2087,7 +2158,7 @@ sv_setsv(SV *dstr, register SV *sstr)
                                                       Nullcv));
                                /* ahem, death to those who redefine
                                 * active sort subs */
-                               if (curstackinfo->si_type == SI_SORT &&
+                               if (curstackinfo->si_type == PERLSI_SORT &&
                                      sortcop == CvSTART(cv))
                                    croak(
                                    "Can't redefine active sort subroutine %s",
@@ -2779,7 +2850,7 @@ sv_clear(register SV *sv)
                destructor = gv_fetchmethod(SvSTASH(sv), "DESTROY");
                if (destructor) {
                    ENTER;
-                   PUSHSTACK(SI_DESTROY);
+                   PUSHSTACKi(PERLSI_DESTROY);
                    SvRV(&tmpref) = SvREFCNT_inc(sv);
                    EXTEND(SP, 2);
                    PUSHMARK(SP);
@@ -2788,7 +2859,7 @@ sv_clear(register SV *sv)
                    perl_call_sv((SV*)GvCV(destructor),
                                 G_DISCARD|G_EVAL|G_KEEPERR);
                    SvREFCNT(sv)--;
-                   POPSTACK();
+                   POPSTACK;
                    LEAVE;
                }
            } while (SvOBJECT(sv) && SvSTASH(sv) != stash);
@@ -2834,6 +2905,9 @@ sv_clear(register SV *sv)
     case SVt_PVAV:
        av_undef((AV*)sv);
        break;
+    case SVt_PVLV:
+       SvREFCNT_dec(LvTARG(sv));
+       goto freescalar;
     case SVt_PVGV:
        gp_free((GV*)sv);
        Safefree(GvNAME(sv));
@@ -2843,7 +2917,6 @@ sv_clear(register SV *sv)
           -- JohnPC, 27 Mar 1998 */
        stash = GvSTASH(sv);
        /* FALL THROUGH */
-    case SVt_PVLV:
     case SVt_PVMG:
     case SVt_PVNV:
     case SVt_PVIV:
@@ -2939,15 +3012,16 @@ sv_free(SV *sv)
 
     if (!sv)
        return;
-    if (SvREADONLY(sv)) {
-       if (sv == &sv_undef || sv == &sv_yes || sv == &sv_no)
-           return;
-    }
     if (SvREFCNT(sv) == 0) {
        if (SvFLAGS(sv) & SVf_BREAK)
            return;
        if (in_clean_all) /* All is fair */
            return;
+       if (SvREADONLY(sv) && SvIMMORTAL(sv)) {
+           /* make sure SvREFCNT(sv)==0 happens very seldom */
+           SvREFCNT(sv) = (~(U32)0)/2;
+           return;
+       }
        warn("Attempt to free unreferenced scalar");
        return;
     }
@@ -2956,10 +3030,15 @@ sv_free(SV *sv)
        return;
 #ifdef DEBUGGING
     if (SvTEMP(sv)) {
-       warn("Attempt to free temp prematurely: %s", SvPEEK(sv));
+       warn("Attempt to free temp prematurely: SV 0x%lx", (unsigned long)sv);
        return;
     }
 #endif
+    if (SvREADONLY(sv) && SvIMMORTAL(sv)) {
+       /* make sure SvREFCNT(sv)==0 happens very seldom */
+       SvREFCNT(sv) = (~(U32)0)/2;
+       return;
+    }
     sv_clear(sv);
     if (! SvREFCNT(sv))
        del_SV(sv);
@@ -3153,6 +3232,27 @@ sv_gets(register SV *sv, register PerlIO *fp, I32 append)
        rsptr = NULL;
        rslen = 0;
     }
+    else if (RsRECORD(rs)) {
+      I32 recsize, bytesread;
+      char *buffer;
+
+      /* Grab the size of the record we're getting */
+      recsize = SvIV(SvRV(rs));
+      (void)SvPOK_only(sv);    /* Validate pointer */
+      buffer = SvGROW(sv, recsize + 1);
+      /* Go yank in */
+#ifdef VMS
+      /* VMS wants read instead of fread, because fread doesn't respect */
+      /* RMS record boundaries. This is not necessarily a good thing to be */
+      /* doing, but we've got no other real choice */
+      bytesread = PerlLIO_read(PerlIO_fileno(fp), buffer, recsize);
+#else
+      bytesread = PerlIO_read(fp, buffer, recsize);
+#endif
+      SvCUR_set(sv, bytesread);
+      buffer[bytesread] = '\0';
+      return(SvCUR(sv) ? SvPVX(sv) : Nullch);
+    }
     else if (RsPARA(rs)) {
        rsptr = "\n\n";
        rslen = 2;
@@ -3391,10 +3491,13 @@ sv_inc(register SV *sv)
                croak(no_modify);
        }
        if (SvROK(sv)) {
+           IV i;
 #ifdef OVERLOAD
-         if (SvAMAGIC(sv) && AMG_CALLun(sv,inc)) return;
+           if (SvAMAGIC(sv) && AMG_CALLun(sv,inc)) return;
 #endif /* OVERLOAD */
-         sv_unref(sv);
+           i = (IV)SvRV(sv);
+           sv_unref(sv);
+           sv_setiv(sv, i);
        }
     }
     if (SvGMAGICAL(sv))
@@ -3468,10 +3571,13 @@ sv_dec(register SV *sv)
                croak(no_modify);
        }
        if (SvROK(sv)) {
+           IV i;
 #ifdef OVERLOAD
-         if (SvAMAGIC(sv) && AMG_CALLun(sv,dec)) return;
+           if (SvAMAGIC(sv) && AMG_CALLun(sv,dec)) return;
 #endif /* OVERLOAD */
-         sv_unref(sv);
+           i = (IV)SvRV(sv);
+           sv_unref(sv);
+           sv_setiv(sv, i);
        }
     }
     if (SvGMAGICAL(sv))
@@ -3557,8 +3663,8 @@ sv_2mortal(register SV *sv)
     dTHR;
     if (!sv)
        return sv;
-    if (SvREADONLY(sv) && curcop != &compiling)
-       croak(no_modify);
+    if (SvREADONLY(sv) && SvIMMORTAL(sv))
+       return sv;
     if (++tmps_ix >= tmps_max)
        sv_mortalgrow();
     tmps_stack[tmps_ix] = sv;
@@ -3638,7 +3744,7 @@ newSViv(IV i)
 }
 
 SV *
-newRV(SV *tmpRef)
+newRV_noinc(SV *tmpRef)
 {
     dTHR;
     register SV *sv;
@@ -3649,21 +3755,15 @@ newRV(SV *tmpRef)
     SvFLAGS(sv) = 0;
     sv_upgrade(sv, SVt_RV);
     SvTEMP_off(tmpRef);
-    SvRV(sv) = SvREFCNT_inc(tmpRef);
+    SvRV(sv) = tmpRef;
     SvROK_on(sv);
     return sv;
 }
 
-
-
 SV *
-Perl_newRV_noinc(SV *tmpRef)
+newRV(SV *tmpRef)
 {
-    register SV *sv;
-
-    sv = newRV(tmpRef);
-    SvREFCNT_dec(tmpRef);
-    return sv;
+    return newRV_noinc(SvREFCNT_inc(tmpRef));
 }
 
 /* make an exact duplicate of old */