Skip to content

Commit

Permalink
bodies_by_type[SVt_PVNV]: handle __float128 NV alignment on 32-bit
Browse files Browse the repository at this point in the history
Perl SV body structures include xmg_stash and xmg_u fields at the
front, which are only valid for type SVt_PVMG and higher.

This allows those fields to be at a constant offset from the start
of the body.

To save memory perl generally allocates the bodies where
type < SVt_PVMG without the space needed for these two fields,
offsetting the body pointer back by the size of the two fields.  At
least for the first body in an arena this is technically
undefined behaviour, but we've done it forever.

With -msse __float128 requires 16 byte alignment, but for XPVNV
bodies the hack used here means that the base of the XPVNV
body ends up mis-aligned on 32-bit systems.

On 64-bit systems the combined size of those fields is 16-bytes so
the modified pointer is still properly aligned.

To fix this allocate the full XPVNV structure when 16 byte alignment
is required for NV, NV is more than 8 bytes and pointers are small
enough that the NV would have been mis-aligned.

Fixes Perl#22577
  • Loading branch information
tonycoz committed Sep 24, 2024
1 parent 9a03665 commit ffbda81
Showing 1 changed file with 14 additions and 1 deletion.
15 changes: 14 additions & 1 deletion sv_inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,25 @@ static const struct body_details bodies_by_type[] = {
SVt_PVIV, FALSE, NONV, HASARENA,
FIT_ARENA(0, sizeof(XPVIV) - STRUCT_OFFSET(XPV, xpv_cur)) },

#if NVSIZE > 8 && PTRSIZE < 8 && MEM_ALIGNBYTES > 8
/* NV may need strict 16 byte alignment.
On 64-bit systems the NV ends up aligned despite the hack
avoiding allocation of xmg_stash and xmg_u, so only do this
for 32-bit systems.
*/
{ sizeof(XPVNV),
sizeof(XPVNV),
0,
SVt_PVNV, FALSE, HADNV, HASARENA,
FIT_ARENA(0, sizeof(XPVNV)) },
#else
{ sizeof(XPVNV) - STRUCT_OFFSET(XPV, xpv_cur),
copy_length(XPVNV, xnv_u) - STRUCT_OFFSET(XPV, xpv_cur),
+ STRUCT_OFFSET(XPV, xpv_cur),
SVt_PVNV, FALSE, HADNV, HASARENA,
FIT_ARENA(0, sizeof(XPVNV) - STRUCT_OFFSET(XPV, xpv_cur)) },

#endif
{ sizeof(XPVMG), copy_length(XPVMG, xnv_u), 0, SVt_PVMG, FALSE, HADNV,
HASARENA, FIT_ARENA(0, sizeof(XPVMG)) },

Expand Down

0 comments on commit ffbda81

Please sign in to comment.