Flip the sign of the value in body details offset, and change its type
[p5sagit/p5-mst-13.2.git] / sv.c
diff --git a/sv.c b/sv.c
index f2093fd..206cd2e 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -1224,7 +1224,7 @@ S_new_body(pTHX_ size_t size, svtype sv_type)
 struct body_details {
     size_t size;       /* Size to allocate  */
     size_t copy;       /* Size of structure to copy (may be shorter)  */
-    int offset;
+    size_t offset;
     bool cant_upgrade; /* Can upgrade this type */
     bool zero_nv;      /* zero the NV when upgrading from this */
     bool arena;                /* Allocated from an arena */
@@ -1242,10 +1242,38 @@ struct body_details {
 #endif
 #define NOARENA FALSE
 
+/* A macro to work out the offset needed to subtract from a pointer to (say)
+
+typedef struct {
+    STRLEN     xpv_cur;
+    STRLEN     xpv_len;
+} xpv_allocated;
+
+to make its members accessible via a pointer to (say)
+
+struct xpv {
+    NV         xnv_nv;
+    STRLEN     xpv_cur;
+    STRLEN     xpv_len;
+};
+
+*/
+
+#define relative_STRUCT_OFFSET(longer, shorter, member) \
+    (STRUCT_OFFSET(shorter, member) - STRUCT_OFFSET(longer, member))
+
+/* Calculate the length to copy. Specifically work out the length less any
+   final padding the compiler needed to add.  See the comment in sv_upgrade
+   for why copying the padding proved to be a bug.  */
+
+#define copy_length(type, last_member) \
+       STRUCT_OFFSET(type, last_member) \
+       + sizeof (((type*)SvANY((SV*)0))->last_member)
+
 static const struct body_details bodies_by_type[] = {
     {0, 0, 0, FALSE, NONV, NOARENA},
     /* IVs are in the head, so the allocation size is 0  */
-    {0, sizeof(IV), -STRUCT_OFFSET(XPVIV, xiv_iv), FALSE, NONV, NOARENA},
+    {0, sizeof(IV), STRUCT_OFFSET(XPVIV, xiv_iv), FALSE, NONV, NOARENA},
     /* 8 bytes on most ILP32 with IEEE doubles */
     {sizeof(NV), sizeof(NV), 0, FALSE, HADNV, HASARENA},
     /* RVs are in the head now */
@@ -1253,24 +1281,20 @@ static const struct body_details bodies_by_type[] = {
     {0, 0, 0, FALSE, NONV, NOARENA},
     /* 8 bytes on most ILP32 with IEEE doubles */
     {sizeof(xpv_allocated),
-     STRUCT_OFFSET(XPV, xpv_len) + sizeof (((XPV*)SvANY((SV*)0))->xpv_len)
-     + STRUCT_OFFSET(xpv_allocated, xpv_cur) - STRUCT_OFFSET(XPV, xpv_cur),
-     + STRUCT_OFFSET(xpv_allocated, xpv_cur) - STRUCT_OFFSET(XPV, xpv_cur)
-     , FALSE, NONV, HASARENA},
+     copy_length(XPV, xpv_len)
+     + relative_STRUCT_OFFSET(XPV, xpv_allocated, xpv_cur),
+     - relative_STRUCT_OFFSET(XPV, xpv_allocated, xpv_cur),
+     FALSE, NONV, HASARENA},
     /* 12 */
     {sizeof(xpviv_allocated),
-     STRUCT_OFFSET(XPVIV, xiv_u) + sizeof (((XPVIV*)SvANY((SV*)0))->xiv_u)
-     + STRUCT_OFFSET(xpviv_allocated, xpv_cur) - STRUCT_OFFSET(XPVIV, xpv_cur),
-     + STRUCT_OFFSET(xpviv_allocated, xpv_cur) - STRUCT_OFFSET(XPVIV, xpv_cur)
-    , FALSE, NONV, HASARENA},
+     copy_length(XPVIV, xiv_u)
+     + relative_STRUCT_OFFSET(XPVIV, xpviv_allocated, xpv_cur),
+     - relative_STRUCT_OFFSET(XPVIV, xpviv_allocated, xpv_cur),
+     FALSE, NONV, HASARENA},
     /* 20 */
-    {sizeof(XPVNV),
-     STRUCT_OFFSET(XPVNV, xiv_u) + sizeof (((XPVNV*)SvANY((SV*)0))->xiv_u),
-     0, FALSE, HADNV, HASARENA},
+    {sizeof(XPVNV), copy_length(XPVNV, xiv_u), 0, FALSE, HADNV, HASARENA},
     /* 28 */
-    {sizeof(XPVMG),
-     STRUCT_OFFSET(XPVMG, xmg_stash) + sizeof (((XPVMG*)SvANY((SV*)0))->xmg_stash),
-     0, FALSE, HADNV, HASARENA},
+    {sizeof(XPVMG), copy_length(XPVMG, xmg_stash), 0, FALSE, HADNV, HASARENA},
     /* 36 */
     {sizeof(XPVBM), sizeof(XPVBM), 0, TRUE, HADNV, HASARENA},
     /* 48 */
@@ -1279,20 +1303,16 @@ static const struct body_details bodies_by_type[] = {
     {sizeof(XPVLV), sizeof(XPVLV), 0, TRUE, HADNV, HASARENA},
     /* 20 */
     {sizeof(xpvav_allocated),
-     STRUCT_OFFSET(XPVAV, xmg_stash)
-     + sizeof (((XPVAV*)SvANY((SV *)0))->xmg_stash)
-     + STRUCT_OFFSET(xpvav_allocated, xav_fill)
-     - STRUCT_OFFSET(XPVAV, xav_fill),
-     STRUCT_OFFSET(xpvav_allocated, xav_fill)
-     - STRUCT_OFFSET(XPVAV, xav_fill), TRUE, HADNV, HASARENA},
+     copy_length(XPVAV, xmg_stash)
+     + relative_STRUCT_OFFSET(XPVAV, xpvav_allocated, xav_fill),
+     - relative_STRUCT_OFFSET(XPVAV, xpvav_allocated, xav_fill),
+     TRUE, HADNV, HASARENA},
     /* 20 */
     {sizeof(xpvhv_allocated),
-     STRUCT_OFFSET(XPVHV, xmg_stash)
-     + sizeof (((XPVHV*)SvANY((SV *)0))->xmg_stash)
-     + STRUCT_OFFSET(xpvhv_allocated, xhv_fill)
-     - STRUCT_OFFSET(XPVHV, xhv_fill),
-     STRUCT_OFFSET(xpvhv_allocated, xhv_fill)
-     - STRUCT_OFFSET(XPVHV, xhv_fill), TRUE, HADNV, HASARENA},
+     copy_length(XPVHV, xmg_stash)
+     + relative_STRUCT_OFFSET(XPVHV, xpvhv_allocated, xhv_fill),
+     - relative_STRUCT_OFFSET(XPVHV, xpvhv_allocated, xhv_fill),
+     TRUE, HADNV, HASARENA},
     /* 76 */
     {sizeof(XPVCV), sizeof(XPVCV), 0, TRUE, HADNV, HASARENA},
     /* 80 */
@@ -1303,7 +1323,7 @@ static const struct body_details bodies_by_type[] = {
 
 #define new_body_type(sv_type)                 \
     (void *)((char *)S_new_body(aTHX_ bodies_by_type[sv_type].size, sv_type)\
-            + bodies_by_type[sv_type].offset)
+            - bodies_by_type[sv_type].offset)
 
 #define del_body_type(p, sv_type)      \
     del_body(p, &PL_body_roots[sv_type])
@@ -1311,10 +1331,10 @@ static const struct body_details bodies_by_type[] = {
 
 #define new_body_allocated(sv_type)            \
     (void *)((char *)S_new_body(aTHX_ bodies_by_type[sv_type].size, sv_type)\
-            + bodies_by_type[sv_type].offset)
+            - bodies_by_type[sv_type].offset)
 
 #define del_body_allocated(p, sv_type)         \
-    del_body(p - bodies_by_type[sv_type].offset, &PL_body_roots[sv_type])
+    del_body(p + bodies_by_type[sv_type].offset, &PL_body_roots[sv_type])
 
 
 #define my_safemalloc(s)       (void*)safemalloc(s)
@@ -1366,9 +1386,9 @@ static const struct body_details bodies_by_type[] = {
 /* no arena for you! */
 
 #define new_NOARENA(details) \
-       my_safemalloc((details)->size - (details)->offset)
+       my_safemalloc((details)->size + (details)->offset)
 #define new_NOARENAZ(details) \
-       my_safecalloc((details)->size - (details)->offset)
+       my_safecalloc((details)->size + (details)->offset)
 
 /*
 =for apidoc sv_upgrade
@@ -1563,15 +1583,15 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
            /* This points to the start of the allocated area.  */
            new_body_inline(new_body, new_type_details->size, new_type);
            Zero(new_body, new_type_details->size, char);
-           new_body = ((char *)new_body) + new_type_details->offset;
+           new_body = ((char *)new_body) - new_type_details->offset;
        } else {
            new_body = new_NOARENAZ(new_type_details);
        }
        SvANY(sv) = new_body;
 
        if (old_type_details->copy) {
-           Copy((char *)old_body - old_type_details->offset,
-                (char *)new_body - old_type_details->offset,
+           Copy((char *)old_body + old_type_details->offset,
+                (char *)new_body + old_type_details->offset,
                 old_type_details->copy, char);
        }
 
@@ -1596,7 +1616,7 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
 #ifdef PURIFY
        my_safefree(old_body);
 #else
-       del_body((void*)((char*)old_body - old_type_details->offset),
+       del_body((void*)((char*)old_body + old_type_details->offset),
                 &PL_body_roots[old_type]);
 #endif
     }
@@ -5475,7 +5495,7 @@ Perl_sv_clear(pTHX_ register SV *sv)
     SvFLAGS(sv) |= SVTYPEMASK;
 
     if (sv_type_details->arena) {
-       del_body(((char *)SvANY(sv) - sv_type_details->offset),
+       del_body(((char *)SvANY(sv) + sv_type_details->offset),
                 &PL_body_roots[type]);
     }
     else if (sv_type_details->size) {
@@ -10021,7 +10041,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
                if (sv_type_details->arena) {
                    new_body_inline(new_body, sv_type_details->copy, sv_type);
                    new_body
-                       = (void*)((char*)new_body + sv_type_details->offset);
+                       = (void*)((char*)new_body - sv_type_details->offset);
                } else {
                    new_body = new_NOARENA(sv_type_details);
                }
@@ -10030,13 +10050,13 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
            SvANY(dstr) = new_body;
 
 #ifndef PURIFY
-           Copy(((char*)SvANY(sstr)) - sv_type_details->offset,
-                ((char*)SvANY(dstr)) - sv_type_details->offset,
+           Copy(((char*)SvANY(sstr)) + sv_type_details->offset,
+                ((char*)SvANY(dstr)) + sv_type_details->offset,
                 sv_type_details->copy, char);
 #else
            Copy(((char*)SvANY(sstr)),
                 ((char*)SvANY(dstr)),
-                sv_type_details->size - sv_type_details->offset, char);
+                sv_type_details->size + sv_type_details->offset, char);
 #endif
 
            if (sv_type != SVt_PVAV && sv_type != SVt_PVHV)