This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Use magic rather than DESTROY to free memory in Storable's context.
[perl5.git] / dist / Storable / Storable.xs
index ca6f9b4..9cba279 100644 (file)
@@ -17,7 +17,7 @@
 #include <patchlevel.h>                /* Perl's one, needed since 5.6 */
 #endif
 
-#if !defined(PERL_VERSION) || PERL_VERSION < 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 9) || (PERL_VERSION == 10 && PERL_SUBVERSION < 1)
+#if !defined(PERL_VERSION) || PERL_VERSION < 10 || (PERL_VERSION == 10 && PERL_SUBVERSION < 1)
 #define NEED_load_module
 #define NEED_vload_module
 #define NEED_newCONSTSUB
 #define SX_CODE         C(26)   /* Code references as perl source code */
 #define SX_WEAKREF     C(27)   /* Weak reference to object forthcoming */
 #define SX_WEAKOVERLOAD        C(28)   /* Overloaded weak reference */
-#define SX_ERROR       C(29)   /* Error */
+#define SX_VSTRING     C(29)   /* vstring forthcoming (small) */
+#define SX_LVSTRING    C(30)   /* vstring forthcoming (large) */
+#define SX_ERROR       C(31)   /* Error */
 
 /*
  * Those are only used to retrieve "old" pre-0.6 binary images.
@@ -259,6 +261,9 @@ typedef unsigned long stag_t;       /* Used by pre-0.6 binary format */
 #ifndef SvWEAKREF
 #define WEAKREF_CROAK() CROAK(("Cannot retrieve weak references in this perl"))
 #endif
+#ifndef SvVOK
+#define VSTRING_CROAK() CROAK(("Cannot retrieve vstring in this perl"))
+#endif
 
 #ifdef HvPLACEHOLDERS
 #define HAS_RESTRICTED_HASHES
@@ -330,11 +335,55 @@ typedef struct stcxt {
        int in_retrieve_overloaded; /* performance hack for retrieving overloaded objects */
 } stcxt_t;
 
+static int storable_free(pTHX_ SV *sv, MAGIC* mg);
+
+static MGVTBL vtbl_storable = {
+    NULL, /* get */
+    NULL, /* set */
+    NULL, /* len */
+    NULL, /* clear */
+    storable_free,
+#ifdef MGf_COPY
+    NULL, /* copy */
+#endif
+#ifdef MGf_DUP
+    NULL, /* dup */
+#endif
+#ifdef MGf_LOCAL
+    NULL /* local */
+#endif
+};
+
+/* From Digest::MD5.  */
+#ifndef sv_magicext
+# define sv_magicext(sv, obj, type, vtbl, name, namlen) \
+    THX_sv_magicext(aTHX_ sv, obj, type, vtbl, name, namlen)
+static MAGIC *THX_sv_magicext(pTHX_ SV *sv, SV *obj, int type,
+    MGVTBL const *vtbl, char const *name, I32 namlen)
+{
+    MAGIC *mg;
+    if (obj || namlen)
+       /* exceeded intended usage of this reserve implementation */
+       return NULL;
+    Newxz(mg, 1, MAGIC);
+    mg->mg_virtual = (MGVTBL*)vtbl;
+    mg->mg_type = type;
+    mg->mg_ptr = (char *)name;
+    mg->mg_len = -1;
+    (void) SvUPGRADE(sv, SVt_PVMG);
+    mg->mg_moremagic = SvMAGIC(sv);
+    SvMAGIC_set(sv, mg);
+    SvMAGICAL_off(sv);
+    mg_magical(sv);
+    return mg;
+}
+#endif
+
 #define NEW_STORABLE_CXT_OBJ(cxt)                                      \
   STMT_START {                                                                         \
        SV *self = newSV(sizeof(stcxt_t) - 1);                  \
        SV *my_sv = newRV_noinc(self);                                  \
-       sv_bless(my_sv, gv_stashpv("Storable::Cxt", GV_ADD));   \
+       sv_magicext(self, NULL, PERL_MAGIC_ext, &vtbl_storable, NULL, 0); \
        cxt = (stcxt_t *)SvPVX(self);                                   \
        Zero(cxt, 1, stcxt_t);                                                  \
        cxt->my_sv = my_sv;                                                             \
@@ -788,15 +837,17 @@ static const char byteorderstr_56[] = {BYTEORDER_BYTES_56, 0};
 #endif
 
 #define STORABLE_BIN_MAJOR     2               /* Binary major "version" */
-#define STORABLE_BIN_MINOR     8               /* Binary minor "version" */
+#define STORABLE_BIN_MINOR     9               /* Binary minor "version" */
 
 #if (PATCHLEVEL <= 5)
 #define STORABLE_BIN_WRITE_MINOR       4
-#else 
+#elif !defined (SvVOK)
 /*
- * Perl 5.6.0 onwards can do weak references.
+ * Perl 5.6.0-5.8.0 can do weak references, but not vstring magic.
 */
 #define STORABLE_BIN_WRITE_MINOR       8
+#else
+#define STORABLE_BIN_WRITE_MINOR       9
 #endif /* (PATCHLEVEL <= 5) */
 
 #if (PATCHLEVEL < 8 || (PATCHLEVEL == 8 && SUBVERSION < 1))
@@ -1040,6 +1091,12 @@ static const char byteorderstr_56[] = {BYTEORDER_BYTES_56, 0};
 static int store(pTHX_ stcxt_t *cxt, SV *sv);
 static SV *retrieve(pTHX_ stcxt_t *cxt, const char *cname);
 
+#define UNSEE()                             \
+  STMT_START {                              \
+    av_pop(cxt->aseen);                     \
+    cxt->tagnum--;                          \
+  } STMT_END
+
 /*
  * Dynamic dispatching table for SV store.
  */
@@ -1122,6 +1179,8 @@ static const sv_retrieve_t sv_old_retrieve[] = {
        (sv_retrieve_t)retrieve_other,  /* SX_CODE not supported */
        (sv_retrieve_t)retrieve_other,  /* SX_WEAKREF not supported */
        (sv_retrieve_t)retrieve_other,  /* SX_WEAKOVERLOAD not supported */
+       (sv_retrieve_t)retrieve_other,  /* SX_VSTRING not supported */
+       (sv_retrieve_t)retrieve_other,  /* SX_LVSTRING not supported */
        (sv_retrieve_t)retrieve_other,  /* SX_ERROR */
 };
 
@@ -1140,6 +1199,8 @@ static SV *retrieve_flag_hash(pTHX_ stcxt_t *cxt, const char *cname);
 static SV *retrieve_code(pTHX_ stcxt_t *cxt, const char *cname);
 static SV *retrieve_weakref(pTHX_ stcxt_t *cxt, const char *cname);
 static SV *retrieve_weakoverloaded(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_vstring(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_lvstring(pTHX_ stcxt_t *cxt, const char *cname);
 
 static const sv_retrieve_t sv_retrieve[] = {
        0,                      /* SX_OBJECT -- entry unused dynamically */
@@ -1171,6 +1232,8 @@ static const sv_retrieve_t sv_retrieve[] = {
        (sv_retrieve_t)retrieve_code,           /* SX_CODE */
        (sv_retrieve_t)retrieve_weakref,        /* SX_WEAKREF */
        (sv_retrieve_t)retrieve_weakoverloaded, /* SX_WEAKOVERLOAD */
+       (sv_retrieve_t)retrieve_vstring,        /* SX_VSTRING */
+       (sv_retrieve_t)retrieve_lvstring,       /* SX_LVSTRING */
        (sv_retrieve_t)retrieve_other,          /* SX_ERROR */
 };
 
@@ -1932,8 +1995,13 @@ static int store_ref(pTHX_ stcxt_t *cxt, SV *sv)
  * Store a scalar.
  *
  * Layout is SX_LSCALAR <length> <data>, SX_SCALAR <length> <data> or SX_UNDEF.
+ * SX_LUTF8STR and SX_UTF8STR are used for UTF-8 strings.
  * The <data> section is omitted if <length> is 0.
  *
+ * For vstrings, the vstring portion is stored first with
+ * SX_LVSTRING <length> <data> or SX_VSTRING <length> <data>, followed by
+ * SX_(L)SCALAR or SX_(L)UTF8STR with the actual PV.
+ *
  * If integer or double, the layout is SX_INTEGER <data> or SX_DOUBLE <data>.
  * Small integers (within [-127, +127]) are stored as SX_BYTE <byte>.
  */
@@ -2110,6 +2178,9 @@ static int store_scalar(pTHX_ stcxt_t *cxt, SV *sv)
             TRACEME(("ok (double 0x%"UVxf", value = %"NVff")", PTR2UV(sv), nv));
 
        } else if (flags & (SVp_POK | SVp_NOK | SVp_IOK)) {
+#ifdef SvVOK
+           MAGIC *mg;
+#endif
             I32 wlen; /* For 64-bit machines */
 
           string_readlen:
@@ -2121,6 +2192,12 @@ static int store_scalar(pTHX_ stcxt_t *cxt, SV *sv)
              */
           string:
 
+#ifdef SvVOK
+            if (SvMAGICAL(sv) && (mg = mg_find(sv, 'V')))
+                STORE_PV_LEN((const char *)mg->mg_ptr,
+                             mg->mg_len, SX_VSTRING, SX_LVSTRING);
+#endif
+
             wlen = (I32) len; /* WLEN via STORE_SCALAR expects I32 */
             if (SvUTF8 (sv))
                 STORE_UTF8STR(pv, wlen);
@@ -2854,6 +2931,7 @@ static int store_hook(
         */
 
        switch (type) {
+        case svis_REF:
        case svis_SCALAR:
                obj_type = SHT_SCALAR;
                break;
@@ -2916,9 +2994,8 @@ static int store_hook(
 
        TRACEME(("about to call STORABLE_freeze on class %s", classname));
 
-       ref = newRV_noinc(sv);                          /* Temporary reference */
+       ref = newRV_inc(sv);                            /* Temporary reference */
        av = array_call(aTHX_ ref, hook, clone);        /* @a = $object->STORABLE_freeze($c) */
-       SvRV_set(ref, NULL);
        SvREFCNT_dec(ref);                                      /* Reclaim temporary reference */
 
        count = AvFILLp(av) + 1;
@@ -3436,7 +3513,7 @@ static int sv_type(pTHX_ SV *sv)
        case SVt_PVCV:
                return svis_CODE;
 #if PERL_VERSION > 8
-       /* case SVt_BIND: */
+       /* case SVt_DUMMY: */
 #endif
        default:
                break;
@@ -4214,10 +4291,29 @@ static SV *retrieve_hook(pTHX_ stcxt_t *cxt, const char *cname)
            AvARRAY(av)[0] = SvREFCNT_inc(frozen);
            rv = newSVpv(classname, 0);
            attached = scalar_call(aTHX_ rv, attach_hook, clone, av, G_SCALAR);
+           /* Free memory after a call */
+           SvREFCNT_dec(rv);
+           SvREFCNT_dec(frozen);
+           av_undef(av);
+           sv_free((SV *) av);
+           SvREFCNT_dec(attach_hook);
            if (attached &&
                SvROK(attached) && 
-               sv_derived_from(attached, classname))
-               return SvRV(attached);
+               sv_derived_from(attached, classname)
+        ) {
+               UNSEE();
+               /* refcnt of unneeded sv is 2 at this point (one from newHV, second from SEEN call) */
+               SvREFCNT_dec(sv);
+               SvREFCNT_dec(sv);
+               /* we need to free RV but preserve value that RV point to */
+               sv = SvRV(attached);
+               SEEN(sv, 0, 0);
+               SvRV_set(attached, NULL);
+               SvREFCNT_dec(attached);
+               if (!(flags & SHF_IDX_CLASSNAME) && classname != buf)
+                   Safefree(classname);
+               return sv;
+           }
            CROAK(("STORABLE_attach did not return a %s object", classname));
        }
 
@@ -4850,6 +4946,79 @@ static SV *retrieve_lutf8str(pTHX_ stcxt_t *cxt, const char *cname)
 }
 
 /*
+ * retrieve_vstring
+ *
+ * Retrieve a vstring, and then retrieve the stringy scalar following it,
+ * attaching the vstring to the scalar via magic.
+ * If we're retrieving a vstring in a perl without vstring magic, croaks.
+ *
+ * The vstring layout mirrors an SX_SCALAR string:
+ * SX_VSTRING <length> <data> with SX_VSTRING already read.
+ */
+static SV *retrieve_vstring(pTHX_ stcxt_t *cxt, const char *cname)
+{
+#ifdef SvVOK
+       MAGIC *mg;
+       char s[256];
+       int len;
+       SV *sv;
+
+       GETMARK(len);
+       TRACEME(("retrieve_vstring (#%d), len = %d", cxt->tagnum, len));
+
+       READ(s, len);
+
+       sv = retrieve(aTHX_ cxt, cname);
+
+       sv_magic(sv,NULL,PERL_MAGIC_vstring,s,len);
+       /* 5.10.0 and earlier seem to need this */
+       SvRMAGICAL_on(sv);
+
+       TRACEME(("ok (retrieve_vstring at 0x%"UVxf")", PTR2UV(sv)));
+       return sv;
+#else
+       VSTRING_CROAK();
+       return Nullsv;
+#endif
+}
+
+/*
+ * retrieve_lvstring
+ *
+ * Like retrieve_vstring, but for longer vstrings.
+ */
+static SV *retrieve_lvstring(pTHX_ stcxt_t *cxt, const char *cname)
+{
+#ifdef SvVOK
+       MAGIC *mg;
+       char *s;
+       I32 len;
+       SV *sv;
+
+       RLEN(len);
+       TRACEME(("retrieve_lvstring (#%d), len = %"IVdf,
+                 cxt->tagnum, (IV)len));
+
+       New(10003, s, len+1, char);
+       SAFEPVREAD(s, len, s);
+
+       sv = retrieve(aTHX_ cxt, cname);
+
+       sv_magic(sv,NULL,PERL_MAGIC_vstring,s,len);
+       /* 5.10.0 and earlier seem to need this */
+       SvRMAGICAL_on(sv);
+
+       Safefree(s);
+
+       TRACEME(("ok (retrieve_lvstring at 0x%"UVxf")", PTR2UV(sv)));
+       return sv;
+#else
+       VSTRING_CROAK();
+       return Nullsv;
+#endif
+}
+
+/*
  * retrieve_integer
  *
  * Retrieve defined integer.
@@ -5097,7 +5266,7 @@ static SV *retrieve_hash(pTHX_ stcxt_t *cxt, const char *cname)
        SEEN(hv, cname, 0);             /* Will return if table not allocated properly */
        if (len == 0)
                return (SV *) hv;       /* No data follow if table empty */
-       hv_ksplit(hv, len);             /* pre-extend hash to save multiple splits */
+       hv_ksplit(hv, len + 1);         /* pre-extend hash to save multiple splits */
 
        /*
         * Now get each key/value pair in turn...
@@ -5184,7 +5353,7 @@ static SV *retrieve_flag_hash(pTHX_ stcxt_t *cxt, const char *cname)
     SEEN(hv, cname, 0);                /* Will return if table not allocated properly */
     if (len == 0)
         return (SV *) hv;      /* No data follow if table empty */
-    hv_ksplit(hv, len);                /* pre-extend hash to save multiple splits */
+    hv_ksplit(hv, len + 1);            /* pre-extend hash to save multiple splits */
 
     /*
      * Now get each key/value pair in turn...
@@ -5503,7 +5672,7 @@ static SV *old_retrieve_hash(pTHX_ stcxt_t *cxt, const char *cname)
        SEEN(hv, 0, 0);                 /* Will return if table not allocated properly */
        if (len == 0)
                return (SV *) hv;       /* No data follow if table empty */
-       hv_ksplit(hv, len);             /* pre-extend hash to save multiple splits */
+       hv_ksplit(hv, len + 1);         /* pre-extend hash to save multiple splits */
 
        /*
         * Now get each key/value pair in turn...
@@ -6278,21 +6447,17 @@ static SV *dclone(pTHX_ SV *sv)
 #define InputStream            PerlIO *
 #endif /* !OutputStream */
 
-MODULE = Storable      PACKAGE = Storable::Cxt
-
-void
-DESTROY(self)
-    SV *self
-PREINIT:
-       stcxt_t *cxt = (stcxt_t *)SvPVX(SvRV(self));
-PPCODE:
+static int
+storable_free(pTHX_ SV *sv, MAGIC* mg) {
+       stcxt_t *cxt = (stcxt_t *)SvPVX(sv);
        if (kbuf)
                Safefree(kbuf);
        if (!cxt->membuf_ro && mbase)
                Safefree(mbase);
        if (cxt->membuf_ro && (cxt->msaved).arena)
                Safefree((cxt->msaved).arena);
-
+       return 0;
+}
 
 MODULE = Storable      PACKAGE = Storable